diff --git a/3d/first_person_shooter/README.md b/3d/first_person_shooter/README.md
new file mode 100644
index 00000000000..93e1dd5e2cc
--- /dev/null
+++ b/3d/first_person_shooter/README.md
@@ -0,0 +1,53 @@
+# First-Person Shooter
+
+This is a demo implementing a retro-styled first-person shooter with a 2.5D
+aesthetic (level is 3D, but enemies are 2D sprites).
+
+Controls:
+
+- Mouse, arrow keys or Gamepad Right Stick: Look around
+- W, Gamepad Left Stick: Move forward
+- S, Gamepad Left Stick: Move backward
+- A, Gamepad Left Stick: Move left
+- D, Gamepad Left Stick: Move right
+- Space, Right mouse button, Gamepad A/Cross: Jump
+- Left mouse button, Gamepad Right Trigger: Attack (or respawn if dead)
+- F, Thumb mouse buttons, Gamepad B/Circle: Toggle flashlight
+- Escape, Gamepad D-Pad Up: Quit
+
+Language: GDScript
+
+Renderer: Forward Plus
+
+## How does it work?
+
+The base vehicle uses a
+[`VehicleBody`](https://docs.godotengine.org/en/latest/classes/class_vehiclebody.html)
+node. The trailer truck is tied together using a
+[`ConeJointTwist`](https://docs.godotengine.org/en/latest/classes/class_conetwistjoint.html)
+node, and the tow truck is tried together using a chain made of
+[`RigidBody`](https://docs.godotengine.org/en/latest/classes/class_rigidbody.html)
+nodes which are pinned together using
+[`PinJoint`](https://docs.godotengine.org/en/latest/classes/class_pinjoint.html) nodes.
+
+## Screenshot
+
+
+
+## License
+
+- `player/shotgun/spritesheet.png`, `player/shotgun/*.wav` and
+ `enemy/spritesheet.png` are Copyright © 2001-2022
+ [Contributors to the Freedoom project](https://freedoom.github.io/)
+ and are licensed under
+ [3-clause BSD](https://github.com/freedoom/freedoom/blob/master/COPYING.adoc).
+- `player/water_splash_in.ogg` and `player/water_splash_out.ogg` are Copyright ©
+ 2009-2019 [Red Eclipse Team](https://www.redeclipse.net/) and are licensed under
+ [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
+- `player/rain.ogg` is
+ [Copyright © Paul Hertz ("ignotus")](https://freesound.org/people/ignotus/sounds/14779/)
+ and is licensed under
+ [CC BY 3.0](https://creativecommons.org/licenses/by/3.0/).
+- `fonts/vga-rom-font.png` is edited from
+ , which is considered to be
+ ineligible for copyright and therefore in the public domain.
diff --git a/3d/first_person_shooter/addons/bsp_importer/bsp_editor_plugin.gd b/3d/first_person_shooter/addons/bsp_importer/bsp_editor_plugin.gd
new file mode 100644
index 00000000000..5a465a8fcaa
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/bsp_editor_plugin.gd
@@ -0,0 +1,15 @@
+@tool
+extends EditorPlugin
+
+
+var import_plugin
+
+
+func _enter_tree():
+ import_plugin = preload("bsp_importer_plugin.gd").new()
+ add_import_plugin(import_plugin)
+
+
+func _exit_tree():
+ remove_import_plugin(import_plugin)
+ import_plugin = null
diff --git a/3d/first_person_shooter/addons/bsp_importer/bsp_editor_plugin.gd.uid b/3d/first_person_shooter/addons/bsp_importer/bsp_editor_plugin.gd.uid
new file mode 100644
index 00000000000..01891ad14d3
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/bsp_editor_plugin.gd.uid
@@ -0,0 +1 @@
+uid://mcabx7bw2p6k
diff --git a/3d/first_person_shooter/addons/bsp_importer/bsp_import_preset.gd b/3d/first_person_shooter/addons/bsp_importer/bsp_import_preset.gd
new file mode 100644
index 00000000000..d3bd13baf6b
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/bsp_import_preset.gd
@@ -0,0 +1,63 @@
+extends Resource
+
+class_name BSPImportPreset
+
+## Number of Quake units per meter
+@export var inverse_scale_factor := 32.0
+## Flags the BSP Reader will ignore when generating geometry (Quake 2 Only)
+@export var ignored_flags : PackedInt64Array = []
+## If true, automatically generate materials from the textures.
+@export var generate_texture_materials := true
+## {texture_name} will be replaced by the texture name in the BSP file.
+@export var material_path_pattern := "res://materials/{texture_name}_material.tres"
+## Optional texture name to material remapping dictionary
+@export var texture_material_rename := { &"texture_name1_example" : "res://material/texture_name1_material.tres" }
+## Will write the material and texture files generated from the BSP file.
+@export var save_separate_materials := true
+## Generate a new matertial to replace existing one (useful if you update palette or textures compiled into BSP file).
+@export var overwrite_existing_materials := false
+## {texture_name} will be replaced by the texture name in the BSP file.
+@export var texture_path_pattern := "res://textures/{texture_name}.png"
+## {texture_name} will be replaced by the texture name in the BSP file.
+@export var texture_emission_path_pattern := "res://textures/{texture_name}_emission.png"
+## Optional texture name to material remapping dictionary
+@export var texture_path_remap := { &"texture_name1_example" : "res://textures/texture_name1_example.png" }
+## "{" is the default transparency texture indicator for Quake. This will be stripped off the name and allow the texture to be used as a transparent surface.
+@export var transparent_texture_prefix := "{"
+## Palette .lmp file used when loading paletted textures.
+@export var palette_palette_path := "res://textures/palette.lmp"
+## Range of colors that willl be fullbright (emission). Usually the last 32 colors.
+@export var fullbright_range : PackedInt32Array = [224, 255]
+## Will overwrite texture png files with the ones loaded from the BSP File. Be careful with this! Useful if you need to change the palette
+@export var overwrite_existing_textures := false
+## Water brushes from the BSP file will be replaced with this scene. It should have an Area3D as the root. Brush collision will be added as children.
+@export var water_scene_template : PackedScene = preload("res://addons/bsp_importer/examples/water_example_template.tscn")
+## Slime brushes from the BSP file will be replaced with this scene. It should have an Area3D as the root. Brush collision will be added as children.
+@export var slime_scene_template : PackedScene = preload("res://addons/bsp_importer/examples/slime_example_template.tscn")
+## Lava brushes from the BSP file will be replaced with this scene. It should have an Area3D as the root. Brush collision will be added as children.
+@export var lava_scene_template : PackedScene = preload("res://addons/bsp_importer/examples/lava_example_template.tscn")
+## Entities from the BSP file will use this scene, with {classname} replaced by the the class name string. Use the entity remap if you want to map to specific scenes with different instead. Brush entities should have a CharacterBody3D (or some other body) as the root. Collisions from brushes will be added as children.
+@export var entity_path_pattern := "res://entities/{classname}.tscn"
+## Remaps an entity classname to a scene. Brush entities should have a CharacterBody3D (or some other body) as the root. Collisions from brushes will be added as children.
+@export var entity_remap := { &"trigger_example" : preload("res://addons/bsp_importer/examples/trigger_example.tscn") }
+## Some entities, such as health packs, are not centered, or you might need to offset them with this classname to vector3 offset dictionary. Uses Quake units.
+@export var entity_offsets_quake_units := { &"example_offset_entity_classname" : Vector3(16, 16, 0) }
+## If true, light entities will import as omnilights.
+@export var import_lights := true
+## Light Brightness Scale
+@export var light_brightness_scale := 16.0
+## If true, will generate an occlusion mesh from the worldspawn to help cull out lights and objects behind walls.
+@export var generate_occlusion_culling := true
+## List of textures to exclude from the occlusion culling mesh. Anything with transparency (grates, fences, etc) should be added here.
+@export var culling_textures_exclude : Array[StringName] = []
+#@export var generate_shadow_mesh := true # This doesn't work properly, yet.
+## Break the world down into chunks based on a grid size. This was an experiment to try to improve performance by culling out other rooms but seemed to perform worse, so I'd recommend leaving it off.
+@export var separate_mesh_on_grid := false
+## Size of grid chunks
+@export var mesh_separation_grid_size := 256.0
+## If true, use triangle collision from the visual geometry instead of convex brush collisions. Faster to import, but usually slower for the physics performance.
+@export var use_triangle_collision := false
+## If true, the error message when importing a missing entity will not be printed.
+@export var ignore_missing_entities := false
+## Script to execute after importing for any custom post-import cleanup.
+@export_file("*.gd") var post_import_script := ""
diff --git a/3d/first_person_shooter/addons/bsp_importer/bsp_import_preset.gd.uid b/3d/first_person_shooter/addons/bsp_importer/bsp_import_preset.gd.uid
new file mode 100644
index 00000000000..5272ba0fef3
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/bsp_import_preset.gd.uid
@@ -0,0 +1 @@
+uid://bblkqbg3tu5cm
diff --git a/3d/first_person_shooter/addons/bsp_importer/bsp_importer_plugin.gd b/3d/first_person_shooter/addons/bsp_importer/bsp_importer_plugin.gd
new file mode 100644
index 00000000000..9a977eac6e9
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/bsp_importer_plugin.gd
@@ -0,0 +1,352 @@
+@tool
+extends EditorImportPlugin
+class_name BSPImporterPlugin
+
+# Unfortunately, usinge resources in the import settings can cause the project to fail to load due
+# to a bug in the config file reader: https://github.com/godotengine/godot/issues/83316
+# Related issues: https://github.com/godotengine/godot/issues/99267 and https://github.com/godotengine/godot-proposals/issues/8350
+const USE_PRESET_RESOURCE := false
+var last_selected_file := "" # used for differenciating in stuffwha
+
+func _get_importer_name():
+ return "bsp"
+
+func _get_visible_name():
+ match last_selected_file.get_extension().to_lower():
+ "bsp": return "Quake BSP"
+ "wad": return "WAD Container"
+
+func _get_recognized_extensions():
+ return ["bsp", "wad"]
+
+
+func _get_priority():
+ return 1.0
+
+
+func _get_import_order():
+ return 0
+
+
+func _get_save_extension():
+ return "scn"
+
+
+func _get_resource_type():
+ return "PackedScene"
+
+
+func _can_import_threaded():
+ return false
+
+
+enum Presets { DEFAULT }
+
+
+func _get_preset_count():
+ return Presets.size()
+
+
+func _get_preset_name(preset):
+ match preset:
+ Presets.DEFAULT:
+ return "Default"
+ _:
+ return "Unknown"
+
+
+func _get_import_options(path : String, preset_index : int):
+ last_selected_file = path
+ match path.get_extension().to_lower():
+ "bsp":
+ print("get options ", path, " index: ", preset_index)
+ var import_path = str(path, ".import")
+ var import_config := ConfigFile.new()
+ var bsp_preset : BSPImportPreset
+ if (USE_PRESET_RESOURCE):
+ # Grab the old settings and store them in a preset.
+ if (import_config.load(import_path) == OK):
+ # If it has a preset, it's a newer import file. If not, convert the data into a preset
+ if (!import_config.has_section_key("params", "preset")):
+ bsp_preset = BSPImportPreset.new()
+ bsp_preset.unit_scale = 1.0 / import_config.get_value("params", "inverse_scale_factor", 32.0)
+ bsp_preset.ignored_flags = import_config.get_value("params", "ignored_flags", PackedInt64Array())
+ bsp_preset.generate_texture_materials = import_config.get_value("params", "generate_texture_materials", true)
+ bsp_preset.save_separate_materials = import_config.get_value("params", "save_separate_materials", true)
+ bsp_preset.material_path_pattern = import_config.get_value("params", "material_path_pattern", "res://materials/{texture_name}_material.tres")
+ bsp_preset.texture_material_rename = import_config.get_value("params", "texture_material_rename", {})
+ bsp_preset.texture_path_pattern = import_config.get_value("params", "texture_path_pattern", "res://textures/{texture_name}.png")
+ bsp_preset.texture_emission_path_pattern = import_config.get_value("params", "texture_emission_path_pattern", "res://textures/{texture_name}_emission.png")
+ bsp_preset.texture_path_remap = import_config.get_value("params", "texture_path_remap", {})
+ bsp_preset.transparent_texture_prefix = import_config.get_value("params", "transparent_texture_prefix", "{")
+ bsp_preset.texture_palette_path = import_config.get_value("params", "texture_palette_path", "res://textures/palette.lmp")
+ bsp_preset.fullbright_range = import_config.get_value("params", "fullbright_range", [224,255])
+ bsp_preset.overwrite_existing_textures = import_config.get_value("params", "overwrite_existing_textures", false)
+ bsp_preset.water_scene_template = load(import_config.get_value("params", "water_scene_template", "res://addons/bsp_importer/examples/water_example_template.tscn"))
+ bsp_preset.slime_scene_template = load(import_config.get_value("params", "slime_scene_template", "res://addons/bsp_importer/examples/slime_example_template.tscn"))
+ bsp_preset.lava_scene_template = load(import_config.get_value("params", "lava_scene_template", "res://addons/bsp_importer/examples/lava_example_template.tscn"))
+ bsp_preset.entity_path_pattern = import_config.get_value("params", "entity_path_pattern", "res://entities/{classname}.tscn")
+ bsp_preset.entity_remap = import_config.get_value("params", "entity_remap", { &"trigger_example" : preload("res://addons/bsp_importer/examples/trigger_example.tscn") })
+ bsp_preset.entity_offsets_quake_units = import_config.get_value("params", "entity_offsets_quake_units", {})
+ bsp_preset.import_lights = import_config.get_value("params", "import_lights", true)
+ bsp_preset.generate_occlusion_culling = import_config.get_value("params", "generate_occlusion_culling", true)
+ bsp_preset.culling_textures_exclude = import_config.get_value("params", "culling_textures_exclude", [])
+ bsp_preset.separate_mesh_on_grid = import_config.get_value("params", "separate_mesh_on_grid", false)
+ bsp_preset.mesh_separation_grid_size = import_config.get_value("params", "mesh_separation_grid_size", 256.0)
+ bsp_preset.use_triangle_collision = import_config.get_value("params", "use_triangle_collision", false)
+ bsp_preset.ignore_missing_entities = import_config.get_value("params", "ignore_missing_entities", false)
+ bsp_preset.post_import_script = import_config.get_value("params", "post_import_script", "")
+
+ if (!bsp_preset):
+ bsp_preset = preload("res://addons/bsp_importer/examples/preset_example.tres")
+
+ match preset_index:
+ Presets.DEFAULT:
+ return [ {
+ "name" : "preset",
+ "default_value" : bsp_preset,
+ "property_hint" : PROPERTY_HINT_RESOURCE_TYPE,
+ "hint_string" : "BSPImportPreset"
+ } ]
+ _:
+ return []
+ else: # No preset resource -- use this until the issues in the engine are resolved.
+ match preset_index:
+ Presets.DEFAULT:
+ return [{
+ "name" : "inverse_scale_factor",
+ "default_value" : 32.0
+ },
+ {
+ "name" : "ignored_flags",
+ "default_value" : PackedInt64Array()
+ },
+ {
+ "name" : "include_sky_surfaces",
+ "default_value" : true
+ },
+ {
+ "name" : "generate_texture_materials",
+ "default_value" : true
+ },
+ {
+ "name" : "save_separate_materials",
+ "default_value" : true
+ },
+ {
+ "name" : "overwrite_existing_materials",
+ "default_value" : false
+ },
+ {
+ "name" : "material_path_pattern",
+ "default_value" : "res://materials/{texture_name}_material.tres"
+ },
+ {
+ "name" : "texture_material_rename",
+ "default_value" : { "texture_name1_example" : "res://material/texture_name1_material.tres" }
+ },
+ {
+ "name" : "texture_path_pattern",
+ "default_value" : "res://textures/{texture_name}.png"
+ },
+ {
+ "name" : "texture_emission_path_pattern",
+ "default_value" : "res://textures/{texture_name}_emission.png"
+ },
+ {
+ "name" : "texture_path_remap",
+ "default_value" : { "texture_name1_example" : "res://textures/texture_name1.png" }
+ },
+ {
+ "name" : "transparent_texture_prefix",
+ "default_value" : "{"
+ },
+ {
+ "name" : "texture_palette_path",
+ "default_value" : "res://textures/palette.lmp"
+ },
+ {
+ "name" : "fullbright_range",
+ "default_value" : [224, 255] as PackedInt32Array
+ },
+ {
+ "name" : "overwrite_existing_textures",
+ "default_value" : false
+ },
+ {
+ "name" : "water_scene_template",
+ "default_value" : "res://addons/bsp_importer/examples/water_example_template.tscn"
+ },
+ {
+ "name" : "slime_scene_template",
+ "default_value" : "res://addons/bsp_importer/examples/slime_example_template.tscn"
+ },
+ {
+ "name" : "lava_scene_template",
+ "default_value" : "res://addons/bsp_importer/examples/lava_example_template.tscn"
+ },
+ {
+ "name" : "entity_path_pattern",
+ "default_value" : "res://entities/{classname}.tscn"
+ },
+ {
+ "name" : "entity_remap",
+ "default_value" : { &"trigger_example" : "res://triggers/trigger_example.tres" }
+ },
+ {
+ "name" : "entity_offsets_quake_units",
+ "default_value" : { &"example_offset_entity" : Vector3(16, 16, 0) }
+ },
+ {
+ "name" : "import_lights",
+ "default_value" : true
+ },
+ {
+ "name" : "light_brightness_scale",
+ "default_value" : 16.0
+ },
+ {
+ "name" : "generate_occlusion_culling",
+ "default_value" : true
+ },
+ # This doesn't work properly, yet.
+ #{
+ ### Generates an optimized mesh for shadow rendering (single material, merged verts)
+ #"name" : "generate_shadow_mesh",
+ #"default_value" : true
+ #},
+ {
+ "name" : "culling_textures_exclude",
+ "default_value" : [] as Array[StringName]
+ },
+ {
+ "name" : "use_triangle_collision",
+ "default_value" : false
+ },
+ {
+ "name" : "separate_mesh_on_grid",
+ "default_value" : false
+ },
+ {
+ "name" : "mesh_separation_grid_size",
+ "default_value" : 256.0
+ },
+ {
+ "name" : "ignore_missing_entities",
+ "default_value" : false
+ },
+ {
+ "name" : "post_import_script",
+ "default_value" : ""
+ }]
+ _:
+ return []
+
+
+func _get_option_visibility(_option, _options, _unknown_dictionary):
+ return true
+
+
+func _import(source_file : String, save_path : String, options : Dictionary, r_platform_variants, r_gen_files):
+ match source_file.get_extension().to_lower():
+ "wad":
+ var reader = WADReader.new()
+ reader.read_wad(source_file)
+ reader.read_directory(source_file)
+ reader.name = source_file.get_file()
+
+ var packed_scene := PackedScene.new()
+ var err := packed_scene.pack(reader)
+ if err == OK:
+
+ var r = ResourceSaver.save(packed_scene, "%s.%s" % [save_path, _get_save_extension()])
+
+ reader.free()
+ return r
+
+ "bsp":
+ var bsp_reader := BSPReader.new()
+ var preset : BSPImportPreset
+ if (USE_PRESET_RESOURCE):
+ preset = options.get("preset", null)
+ if (preset):
+ print("Importing BSP from preset.")
+ bsp_reader.unit_scale = 1.0 / preset.inverse_scale_factor
+ bsp_reader.ignored_flags = preset.ignored_flags
+ bsp_reader.generate_texture_materials = preset.generate_texture_materials
+ bsp_reader.save_separate_materials = preset.save_separate_materials
+ bsp_reader.overwrite_existing_materials = preset.overwrite_existing_materials
+ bsp_reader.material_path_pattern = preset.material_path_pattern
+ bsp_reader.texture_material_rename = preset.texture_material_rename
+ bsp_reader.texture_path_pattern = preset.texture_path_pattern
+ bsp_reader.texture_emission_path_pattern = preset.texture_emission_path_pattern
+ bsp_reader.texture_path_remap = preset.texture_path_remap
+ bsp_reader.transparent_texture_prefix = preset.transparent_texture_prefix
+ bsp_reader.texture_palette_path = preset.texture_palette_path
+ bsp_reader.fullbright_range = preset.fullbright_range
+ bsp_reader.overwrite_existing_textures = preset.overwrite_existing_textures
+ bsp_reader.water_template = preset.water_scene_template
+ bsp_reader.slime_template = preset.slime_scene_template
+ bsp_reader.lava_template = preset.lava_scene_template
+ bsp_reader.entity_path_pattern = preset.entity_path_pattern
+ bsp_reader.entity_remap = preset.entity_remap
+ bsp_reader.entity_offsets_quake_units = preset.entity_offsets_quake_units
+ bsp_reader.import_lights = preset.import_lights
+ bsp_reader.light_brightness_scale = preset.light_brightness_scale
+ bsp_reader.generate_occlusion_culling = preset.generate_occlusion_culling
+ bsp_reader.culling_textures_exclude = preset.culling_textures_exclude
+ #bsp_reader.generate_shadow_mesh = preset.generate_shadow_mesh # Not fully implemented, yet
+ bsp_reader.use_triangle_collision = preset.use_triangle_collision
+ bsp_reader.separate_mesh_on_grid = preset.separate_mesh_on_grid
+ bsp_reader.mesh_separation_grid_size = preset.mesh_separation_grid_size
+ bsp_reader.ignore_missing_entities = preset.ignore_missing_entities
+ bsp_reader.post_import_script_path = preset.post_import_script
+ else:
+ print("Importing BSP from import settings.")
+ bsp_reader.unit_scale = 1.0 / options.inverse_scale_factor
+ bsp_reader.ignored_flags = options.ignored_flags
+ bsp_reader.include_sky_surfaces = options.include_sky_surfaces
+ bsp_reader.generate_texture_materials = options.generate_texture_materials
+ bsp_reader.save_separate_materials = options.save_separate_materials
+ bsp_reader.overwrite_existing_materials = options.overwrite_existing_materials
+ bsp_reader.material_path_pattern = options.material_path_pattern
+ bsp_reader.texture_material_rename = options.texture_material_rename
+ bsp_reader.texture_path_pattern = options.texture_path_pattern
+ bsp_reader.texture_emission_path_pattern = options.texture_emission_path_pattern
+ bsp_reader.texture_path_remap = options.texture_path_remap
+ bsp_reader.transparent_texture_prefix = options.transparent_texture_prefix
+ bsp_reader.texture_palette_path = options.texture_palette_path
+ bsp_reader.fullbright_range = options.fullbright_range
+ bsp_reader.overwrite_existing_textures = options.overwrite_existing_textures
+ bsp_reader.water_template = load(options.water_scene_template)
+ bsp_reader.slime_template = load(options.slime_scene_template)
+ bsp_reader.lava_template = load(options.lava_scene_template)
+ bsp_reader.entity_path_pattern = options.entity_path_pattern
+ bsp_reader.entity_remap = options.entity_remap
+ bsp_reader.entity_offsets_quake_units = options.entity_offsets_quake_units
+ bsp_reader.import_lights = options.import_lights
+ bsp_reader.light_brightness_scale = options.light_brightness_scale
+ bsp_reader.generate_occlusion_culling = options.generate_occlusion_culling
+ bsp_reader.culling_textures_exclude = options.culling_textures_exclude
+ #bsp_reader.generate_shadow_mesh = options.generate_shadow_mesh # Not fully implemented yet.
+ bsp_reader.use_triangle_collision = options.use_triangle_collision
+ bsp_reader.separate_mesh_on_grid = options.separate_mesh_on_grid
+ bsp_reader.mesh_separation_grid_size = options.mesh_separation_grid_size
+ bsp_reader.ignore_missing_entities = options.ignore_missing_entities
+ bsp_reader.post_import_script_path = options.post_import_script
+
+ var bsp_scene := bsp_reader.read_bsp(source_file)
+ if (!bsp_scene):
+ return bsp_reader.error
+ for wad in bsp_reader.wad_paths: wad.free()
+ bsp_reader.wad_paths.clear()
+ var packed_scene := PackedScene.new()
+ var err := packed_scene.pack(bsp_scene)
+ if (err):
+ print("Failed to pack scene: ", err)
+ return err
+
+ print("Saving to %s.%s" % [save_path, _get_save_extension()])
+ var r = ResourceSaver.save(packed_scene, "%s.%s" % [save_path, _get_save_extension()])
+ bsp_reader.free()
+ return r
diff --git a/3d/first_person_shooter/addons/bsp_importer/bsp_importer_plugin.gd.uid b/3d/first_person_shooter/addons/bsp_importer/bsp_importer_plugin.gd.uid
new file mode 100644
index 00000000000..d970b3172be
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/bsp_importer_plugin.gd.uid
@@ -0,0 +1 @@
+uid://d1044gq3ckyl
diff --git a/3d/first_person_shooter/addons/bsp_importer/bsp_reader.gd b/3d/first_person_shooter/addons/bsp_importer/bsp_reader.gd
new file mode 100644
index 00000000000..78eaa7c9d31
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/bsp_reader.gd
@@ -0,0 +1,2571 @@
+extends Node
+
+class_name BSPReader
+
+const USE_BSPX_BRUSHES := true # If -wrbrushes is used, use the extra brush data for collision instead of the BSP tree collision.
+const TEST_BOX_ONLY_COLLISION := false # For performance testing using only boxes.
+# Documentation: https://docs.godotengine.org/en/latest/tutorials/plugins/editor/import_plugins.html
+const SINGLE_STATIC_BODY := true
+
+const CONTENTS_EMPTY := -1
+const CONTENTS_SOLID := -2
+const CONTENTS_WATER := -3
+const CONTENTS_SLIME := -4
+const CONTENTS_LAVA := -5
+const SURFACE_FLAG_SKY := 4
+const SURFACE_FLAG_NODRAW := 128
+const SURFACE_FLAG_HINT := 256
+const SURFACE_FLAG_SKIP := 512
+#define CONTENTS_SKY -6
+#define CONTENTS_ORIGIN -7
+#define CONTENTS_CLIP -8
+#define CONTENTS_CURRENT_0 -9
+#define CONTENTS_CURRENT_90 -10
+#define CONTENTS_CURRENT_180 -11
+#define CONTENTS_CURRENT_270 -12
+#define CONTENTS_CURRENT_UP -13
+#define CONTENTS_CURRENT_DOWN -14
+#define CONTENTS_TRANSLUCENT -15
+
+const BSPX_NAME_LENGTH := 24
+
+const CLIPNODES_STRUCT_SIZE := (4 + 2 + 2) # 32bit int for plane index, 2 16bit children.
+const NODES_STRUCT_SIZE_Q1BSP := (4 + 2 + 2 + 2 * 6 + 2 + 2) # 32bit int for plane index, 2 16bit children. bbox short, face id, face num
+const NODES_STRUCT_SIZE_Q1BSP2 := (4 + 4 + 4 + 4 * 6 + 4 + 4) # 32bit int for plane index, 2 32bit children. bbox int32?, face id, face num
+
+#typedef struct
+#{ long type; // Special type of leaf
+# long vislist; // Beginning of visibility lists
+# // must be -1 or in [0,numvislist[
+# bboxshort_t bound; // Bounding box of the leaf
+# u_short lface_id; // First item of the list of faces
+# // must be in [0,numlfaces[
+# u_short lface_num; // Number of faces in the leaf
+# u_char sndwater; // level of the four ambient sounds:
+# u_char sndsky; // 0 is no sound
+# u_char sndslime; // 0xFF is maximum volume
+# u_char sndlava; //
+#} dleaf_t;
+
+const LEAF_SIZE_Q1BSP := 4 + 4 + 2 * 6 + 2 + 2 + 1 + 1 + 1 + 1
+const LEAF_SIZE_BSP2 := 4 + 4 + 4 * 6 + 4 + 4 + 1 + 1 + 1 + 1
+
+
+class BSPEdge:
+ var vertex_index_0 : int
+ var vertex_index_1 : int
+ func read_edge_16_bit(file : FileAccess) -> int:
+ vertex_index_0 = file.get_16()
+ vertex_index_1 = file.get_16()
+ return 4 # 2 2 byte values
+ func read_edge_32_bit(file : FileAccess) -> int:
+ vertex_index_0 = file.get_32()
+ vertex_index_1 = file.get_32()
+ return 8 # 2 4 byte values
+
+
+class BSPModelData:
+ var bound_min : Vector3
+ var bound_max : Vector3
+ var origin : Vector3
+ var node_id0 : int
+ var node_id1 : int
+ var node_id2 : int
+ var node_id3 : int
+ var num_leafs : int # For vis?
+ var face_index : int
+ var face_count : int
+
+const MODEL_DATA_SIZE_Q1_BSP := 2 * 3 * 4 + 3 * 4 + 7 * 4
+
+func read_model_data_q1_bsp(model_data : BSPModelData):
+ # Since some axes are negated here, min/max is funky.
+ var mins := read_vector_convert_scaled()
+ var maxs := read_vector_convert_scaled()
+ model_data.bound_min = Vector3(min(mins.x, maxs.x), min(mins.y, maxs.y), min(mins.z, maxs.z))
+ model_data.bound_max = Vector3(max(mins.x, maxs.x), max(mins.y, maxs.y), max(mins.z, maxs.z))
+ # Not sure why, but it seems the mins/maxs are 1 unit inside of the actual mins/maxs, so increase bounds by 1 unit:
+ model_data.bound_min -= Vector3(unit_scale, unit_scale, unit_scale)
+ model_data.bound_max += Vector3(unit_scale, unit_scale, unit_scale)
+ model_data.origin = read_vector_convert_scaled()
+ model_data.node_id0 = file.get_32()
+ model_data.node_id1 = file.get_32()
+ model_data.node_id2 = file.get_32()
+ model_data.node_id3 = file.get_32()
+ model_data.num_leafs = file.get_32()
+ model_data.face_index = file.get_32()
+ model_data.face_count = file.get_32()
+
+
+class BSPModelDataQ2:
+ var bound_min : Vector3
+ var bound_max : Vector3
+ var origin : Vector3
+ var node_id0 : int
+ static func get_data_size() -> int:
+ return 2 * 3 * 4 + 3 * 4 + 1 * 4
+ func read_model(file : FileAccess):
+ bound_min = Vector3(file.get_float(), file.get_float(), file.get_float())
+ bound_max = Vector3(file.get_float(), file.get_float(), file.get_float())
+ origin = Vector3(file.get_float(), file.get_float(), file.get_float())
+ node_id0 = file.get_32()
+
+
+# For load_or_create_material, because we can't return more than one thing...
+class MaterialInfo:
+ var width : int
+ var height : int
+ var material : Material
+
+
+static var default_palette : PackedByteArray = []
+
+class BSPTexture:
+ var name : StringName
+ var width : int
+ var height : int
+ var material : Material
+ var is_warp := false
+ var is_transparent := false
+ var texture_data_offset : int
+
+ static func get_data_size() -> int:
+ return 40 # 16 + 4 * 6
+
+ func read_texture(file : FileAccess, reader : BSPReader) -> int:
+ var texture_header_file_offset := file.get_position()
+ name = file.get_buffer(16).get_string_from_ascii()
+ if (name.begins_with("*")):
+ name = name.substr(1)
+ is_warp = true
+ is_transparent = true
+ if (name.begins_with(reader.transparent_texture_prefix)):
+ name = name.substr(reader.transparent_texture_prefix.length())
+ is_transparent = true
+ width = file.get_32()
+ height = file.get_32()
+ texture_data_offset = BSPReader.unsigned32_to_signed(file.get_32())
+ if (texture_data_offset > 0):
+ texture_data_offset += texture_header_file_offset
+ file.get_32() # for mip levels
+ file.get_32() # for mip levels
+ file.get_32() # for mip levels
+ name = name.to_lower()
+ #current_file_offset = file.get_position()
+ print("texture: ", name, " width: ", width, " height: ", height)
+ if (name != &"skip" && name != &"trigger" && name != &"waterskip" && name != &"slimeskip" && name != &"clip" && (reader.include_sky_surfaces || !name.begins_with("sky"))):
+ var material_info := reader.load_or_create_material(name, self)
+ if (material_info):
+ material = material_info.material
+ width = material_info.width
+ height = material_info.height
+ else:
+ printerr("Failed to load or create material for ", name)
+ return get_data_size()
+
+
+class BSPTextureInfo:
+ var vec_s : Vector3
+ var offset_s : float
+ var vec_t : Vector3
+ var offset_t : float
+ var texture_index : int
+ var flags : int
+ # Q2 stuff:
+ var value : int
+ var texture_path : String
+ static func get_data_size() -> int:
+ return 40 # 3 * 2 * 4 + 4 * 2 + 2 * 4
+ func read_texture_info(file : FileAccess) -> int:
+ #vec_s = BSPImporterPlugin.convert_normal_vector_from_quake(Vector3(file.get_float(), file.get_float(), file.get_float()))
+ vec_s = BSPReader.read_vector_convert_unscaled(file)
+ offset_s = file.get_float()
+ #vec_t = BSPImporterPlugin.convert_normal_vector_from_quake(Vector3(file.get_float(), file.get_float(), file.get_float()))
+ vec_t = BSPReader.read_vector_convert_unscaled(file)
+ offset_t = file.get_float()
+ texture_index = file.get_32()
+ #print("texture_index: ", texture_index)
+ flags = file.get_32()
+ return get_data_size()
+
+
+class BSPFace:
+ var plane_id : int
+ var plane_side : int
+ var edge_list_id : int # var first_edge?
+ var num_edges : int
+ var texinfo_id : int
+ var light_type : int
+ var light_base : int
+ var light_model_0 : int
+ var light_model_1 : int
+ var lightmap : int
+ var lightmap_start : Vector2i
+ var lightmap_size : Vector2i
+
+ # most Q3 stuff isnt needed with the current construction method but i'll probably figure that out later, otherwise that would go here. - cs
+
+ var verts : PackedVector3Array = [] # For Mesh Construction
+ var q3_uv : PackedVector2Array
+ var q3_uv2 : PackedVector2Array
+ var vert_normal : Vector3 = Vector3.ZERO
+ var face_normal : Vector3 = Vector3.ZERO
+
+ static func get_data_size_q1bsp() -> int:
+ return 20
+ static func get_data_size_bsp2() -> int: # for bsp2
+ return 20 + 2 * 4 # plane id, side, num edges all have an extra 2 bytes going from 16 to 32 bit
+ func print_face():
+ print("BSPFace: plane_id: ", plane_id, " side: ", plane_side, " edge_list_id: ", edge_list_id, " num_edges: ", num_edges, " texinfo_id: ", texinfo_id)
+ func read_face_q1bsp(file : FileAccess) -> int:
+ plane_id = file.get_16()
+ plane_side = file.get_16()
+ edge_list_id = file.get_32()
+ num_edges = file.get_16()
+ texinfo_id = file.get_16()
+ light_type = file.get_8()
+ light_base = file.get_8()
+ light_model_0 = file.get_8()
+ light_model_1 = file.get_8()
+ lightmap = file.get_32()
+ return get_data_size_q1bsp()
+ func read_face_bsp2(file : FileAccess) -> int:
+ plane_id = file.get_32()
+ #print("plane_id ", plane_id)
+ plane_side = file.get_32()
+ #print("side ", side)
+ edge_list_id = file.get_32()
+ #print("edge_list_id ", edge_list_id)
+ num_edges = file.get_32()
+ #print("num_edges ", num_edges)
+ texinfo_id = file.get_32()
+ #print("texinfo_id ", texinfo_id)
+ light_type = file.get_8()
+ light_base = file.get_8()
+ light_model_0 = file.get_8()
+ light_model_1 = file.get_8()
+ lightmap = file.get_32()
+ #print("lightmap ", lightmap)
+ return get_data_size_bsp2()
+
+
+const MAX_15B := 1 << 15
+const MAX_16B := 1 << 16
+
+static func unsigned16_to_signed(unsigned : int) -> int:
+ return (unsigned + MAX_15B) % MAX_16B - MAX_15B
+
+
+const MAX_31B = 1 << 31
+const MAX_32B = 1 << 32
+
+static func unsigned32_to_signed(unsigned : int) -> int:
+ return (unsigned + MAX_31B) % MAX_32B - MAX_31B
+
+
+# X is forward in Quake, -Z is forward in Godot. Z is up in Quake, Y is up in Godot
+static func convert_vector_from_quake_unscaled(quake_vector : Vector3) -> Vector3:
+ return Vector3(-quake_vector.y, quake_vector.z, -quake_vector.x)
+
+
+static func convert_vector_from_quake_scaled(quake_vector : Vector3, scale: float) -> Vector3:
+ return Vector3(-quake_vector.y, quake_vector.z, -quake_vector.x) * scale
+
+
+static func read_vector_convert_unscaled(file : FileAccess) -> Vector3:
+ return convert_vector_from_quake_unscaled(Vector3(file.get_float(), file.get_float(), file.get_float()))
+
+
+func read_vector_convert_scaled() -> Vector3:
+ return convert_vector_from_quake_scaled(Vector3(file.get_float(), file.get_float(), file.get_float()), unit_scale)
+
+
+var error := ERR_UNCONFIGURED
+var save_separate_materials := false # Save material as separate resource. Set to false when loading in-game.
+var material_path_pattern : String
+var texture_material_rename : Dictionary
+var texture_path_pattern : String
+var texture_emission_path_pattern : String
+var texture_path_remap : Dictionary
+var transparent_texture_prefix : String
+var texture_palette_path : String
+var entity_path_pattern : String
+var water_template : PackedScene
+var slime_template : PackedScene
+var lava_template : PackedScene
+var entity_remap : Dictionary
+var entity_offsets_quake_units : Dictionary
+var array_of_planes_array := []
+var array_of_planes : PackedInt32Array = []
+var water_planes_array := [] # Array of arrays of planes
+var slime_planes_array := []
+var lava_planes_array := []
+var file : FileAccess
+var leaves_offset : int
+var nodes_offset : int
+var root_node : Node3D
+var plane_normals : PackedVector3Array
+var plane_distances : PackedFloat32Array
+var model_scenes : Dictionary = {}
+var is_bsp2 := false
+var unit_scale : float = 1.0 / 32.0
+var import_lights := true
+var light_brightness_scale := 16.0
+var generate_occlusion_culling := true
+var generate_shadow_mesh := false
+var use_triangle_collision := false
+var culling_textures_exclude : Array[StringName]
+var generate_lightmap_uv2 := true
+var post_import_script_path : String
+var ignore_missing_entities := false
+var separate_mesh_on_grid := false
+var generate_texture_materials := false
+var overwrite_existing_materials := false
+var overwrite_existing_textures := false
+var mesh_separation_grid_size := 256.0
+var bspx_model_to_brush_map := {}
+var fullbright_range : PackedInt32Array = [224, 255]
+var ignored_flags : PackedInt64Array = []
+var include_sky_surfaces := true
+
+# used for reading wads for goldsource games.
+var is_gsrc : bool = false
+var wad_paths : Array[WADReader] = []
+
+func clear_data():
+ error = ERR_UNCONFIGURED
+ array_of_planes_array = []
+ array_of_planes = []
+ water_planes_array = []
+ slime_planes_array = []
+ lava_planes_array = []
+ if (file):
+ file.close()
+ file = null
+ root_node = null
+ plane_normals = []
+ plane_distances = []
+ model_scenes = {}
+ wad_paths.clear()
+
+# To find the end of a block of l
+static func get_lumps_end(current_end : int, offset : int, length : int) -> int:
+ return max(current_end, offset + length)
+
+
+class BSPXBrush:
+ var mins : Vector3
+ var maxs : Vector3
+ var contents : int
+ var planes : Array[Plane]
+
+
+
+func read_bsp(source_file : String) -> Node:
+
+ clear_data() # Probably not necessary, but just in case somebody reads a bsp file with the same instance
+ print("Attempting to import %s" % source_file)
+ print("Material path pattern: ", material_path_pattern)
+ file = FileAccess.open(source_file, FileAccess.READ)
+
+ if !(ignored_flags == PackedInt64Array([])): push_warning("Ignored Flags seems to have a value, this array's usage is only integrated for Quake 2/3 at the moment.")
+
+ if (!file):
+ error = FileAccess.get_open_error()
+ print("Failed to open %s: %d" % [source_file, error])
+ return null
+
+ root_node = Node3D.new()
+ root_node.name = source_file.get_file().get_basename() # Get the file out of the path and remove file extension
+
+ # Read the header
+ var is_q2 := false
+ is_bsp2 = false
+ var has_textures := true
+ var has_clipnodes := true
+ var has_brush_table := false
+ var bsp_version := file.get_32()
+
+ var index_bits_32 := false
+ print("BSP version: %d\n" % bsp_version, " ")
+ is_gsrc = (bsp_version == 30) # check if its goldsrc so it doesn't try to look for textures in WADs for non-goldsrc formats.
+ if is_gsrc:
+ create_wad_table()
+ prints("WADs located.")
+
+ if (bsp_version == 1347633737): # "IBSP" - Quake 2 BSP format, this also creates for Quake 3.
+ var bsp_q2_texts = [
+ "Moving File %s to QBSPi2" % source_file.get_file().get_basename(),
+ "QBSPi2 is Our Lord and Savior!, said literally no one ever.",
+ "Why did jitspoe decide QBSPi2 should be in here??",
+ "Why did I decide QBSPi2 would be a fun project?? like?? why???",
+
+ ]
+
+ prints("IBSP Format Detected.", bsp_q2_texts.pick_random())
+
+ # Keeping these for safety!
+ is_q2 = true
+ has_textures = false
+ has_clipnodes = false
+ has_brush_table = true
+ bsp_version = file.get_32()
+
+ print("BSP sub-version: %d\n" % bsp_version)
+ file.close()
+ file = null
+ return convertBSPtoScene(source_file)
+ if (bsp_version == 1112756274): # "2PSB" - depricated extended quake BSP format.
+ print("2PSB format not supported.")
+ file.close()
+ file = null
+ return
+ if (bsp_version == 844124994): # "BSP2" - extended Quake BSP format
+ print("BSP2 extended Quake format.")
+ is_bsp2 = true
+ index_bits_32 = true
+
+ var entity_offset := file.get_32()
+ var entity_size := file.get_32()
+ # Need to figure out the end of the vanilla BSP data so that we can get the BSPX data.
+ var bsp_end := get_lumps_end(0, entity_offset, entity_size)
+ var planes_offset := file.get_32()
+ var planes_size := file.get_32()
+ bsp_end = get_lumps_end(bsp_end, planes_offset, planes_size)
+ var textures_offset := file.get_32() if has_textures else 0
+ var textures_size := file.get_32() if has_textures else 0
+ bsp_end = get_lumps_end(bsp_end, textures_offset, textures_size)
+ var verts_offset := file.get_32()
+ var verts_size := file.get_32()
+ bsp_end = get_lumps_end(bsp_end, verts_offset, verts_size)
+ var vis_offset := file.get_32()
+ var vis_size := file.get_32()
+ bsp_end = get_lumps_end(bsp_end, vis_offset, vis_size)
+ nodes_offset = file.get_32()
+ var nodes_size := file.get_32()
+ bsp_end = get_lumps_end(bsp_end, nodes_offset, nodes_size)
+ var texinfo_offset := file.get_32()
+ var texinfo_size := file.get_32()
+ bsp_end = get_lumps_end(bsp_end, texinfo_offset, texinfo_size)
+ var faces_offset := file.get_32()
+ var faces_size := file.get_32()
+ bsp_end = get_lumps_end(bsp_end, faces_offset, faces_size)
+ var lightmaps_offset := file.get_32()
+ var lightmaps_size := file.get_32()
+ bsp_end = get_lumps_end(bsp_end, lightmaps_offset, lightmaps_size)
+ var clipnodes_offset := file.get_32() if has_clipnodes else 0
+ var clipnodes_size := file.get_32() if has_clipnodes else 0
+ bsp_end = get_lumps_end(bsp_end, clipnodes_offset, clipnodes_size)
+ leaves_offset = file.get_32()
+ var leaves_size := file.get_32()
+ bsp_end = get_lumps_end(bsp_end, leaves_offset, leaves_size)
+ var listfaces_size := file.get_32()
+ var listfaces_offset := file.get_32()
+ bsp_end = get_lumps_end(bsp_end, listfaces_offset, listfaces_size)
+ var leaf_brush_table_offset := file.get_32() if has_brush_table else 0 # For Q2
+ var leaf_brush_table_size := file.get_32() if has_brush_table else 0
+ bsp_end = get_lumps_end(bsp_end, leaf_brush_table_offset, leaf_brush_table_size)
+ var edges_offset := file.get_32()
+ var edges_size := file.get_32()
+ bsp_end = get_lumps_end(bsp_end, edges_offset, edges_size)
+ var listedges_offset := file.get_32()
+ var listedges_size := file.get_32()
+ bsp_end = get_lumps_end(bsp_end, listedges_offset, listedges_size)
+ var models_offset := file.get_32()
+ var models_size := file.get_32()
+ bsp_end = get_lumps_end(bsp_end, models_offset, models_size)
+ # Q2-specific
+ var brushes_offset := file.get_32() if has_brush_table else 0
+ var brushes_size := file.get_32() if has_brush_table else 0
+ bsp_end = get_lumps_end(bsp_end, brushes_offset, brushes_size)
+ var brush_sides_offset := file.get_32() if has_brush_table else 0
+ var brush_sides_size := file.get_32() if has_brush_table else 0
+ bsp_end = get_lumps_end(bsp_end, brush_sides_offset, brush_sides_size)
+ # Pop
+ # Areas
+ # Area portals
+
+ # BSPX support: https://github.com/fte-team/fteqw/blob/master/specs/bspx.txt
+ var has_bspx := false
+ var bspx_offset := bsp_end
+ # Needs to be aligned by 4.
+ bspx_offset = ((bspx_offset + 3) / 4) * 4
+ file.seek(bspx_offset)
+ var bspx_check := file.get_32()
+ var use_bspx_brushes := false
+ if (bspx_check == 1481659202): # "BSPX"
+ has_bspx = true
+ print("Has BSPX.")
+ var has_bspx_brushes := false
+ var bspx_brushes_offset := 0
+ var bspx_brushes_length := 0
+ var num_bspx_entries := file.get_32()
+ for i in num_bspx_entries:
+ var entry_name := file.get_buffer(BSPX_NAME_LENGTH).get_string_from_ascii()
+ print("BSPX entry: ", entry_name)
+ if (entry_name == "BRUSHLIST"):
+ print("Has BSPX brush list.")
+ has_bspx_brushes = true
+ bspx_brushes_offset = file.get_32()
+ bspx_brushes_length = file.get_32()
+ if (has_bspx_brushes && USE_BSPX_BRUSHES):
+ use_bspx_brushes = true
+ var bytes_read := 0
+ file.seek(bspx_brushes_offset)
+ while (file.get_position() < file.get_length()): # Safer than while (true)
+ if (bytes_read >= bspx_brushes_length):
+ break
+ var version := file.get_32()
+ bytes_read += 4
+ if (version != 1):
+ print("Only BSPX brush version 1 supported. Version: ", version)
+ break
+ var model_num := file.get_32()
+ bytes_read += 4
+ var get_whatever := bspx_model_to_brush_map.get(model_num)
+ var brush_array : Array[BSPXBrush] = []
+ if (get_whatever):
+ brush_array = get_whatever # WHY?!??!?!?!?!?!?!
+ var num_brushes := file.get_32()
+ bytes_read += 4
+ var num_planes_total := file.get_32()
+ bytes_read += 4
+
+ for brush_index in num_brushes:
+ var bspx_brush := BSPXBrush.new()
+ var mins := read_vector_convert_scaled()
+ bytes_read += 3 * 4
+ var maxs := read_vector_convert_scaled()
+ bytes_read += 3 * 4
+ bspx_brush.mins = Vector3(minf(mins.x, maxs.x), minf(mins.y, maxs.y), minf(mins.z, maxs.z))
+ bspx_brush.maxs = Vector3(maxf(mins.x, maxs.x), maxf(mins.y, maxs.y), maxf(mins.z, maxs.z))
+ bspx_brush.contents = unsigned16_to_signed(file.get_16())
+ bytes_read += 2
+ var num_bspx_planes := file.get_16()
+ bytes_read += 2
+ for plane_index in num_bspx_planes:
+ var normal := read_vector_convert_unscaled(file)
+ bytes_read += 3 * 4
+ var dist := file.get_float() * unit_scale
+ bytes_read += 4
+ var plane := Plane(normal, dist)
+ bspx_brush.planes.append(plane)
+ brush_array.append(bspx_brush)
+ bspx_model_to_brush_map[model_num] = brush_array
+ else:
+ print("Does not have BSPX.")
+
+
+
+ # Read vertex data
+ var verts : PackedVector3Array
+ file.seek(verts_offset)
+ var vert_data_left := verts_size
+ var vertex_count := verts_size / (4 * 3)
+ verts.resize(vertex_count)
+ for i in vertex_count:
+ verts[i] = convert_vector_from_quake_scaled(Vector3(file.get_float(), file.get_float(), file.get_float()), unit_scale)
+
+ # Read entity data
+ file.seek(entity_offset)
+ var entity_string : String = file.get_buffer(entity_size).get_string_from_ascii()
+ #print("Entity data: ", entity_string)
+ var entity_dict_array := parse_entity_string(entity_string)
+ convert_entity_dict_to_scene(entity_dict_array)
+
+ #print("edges_offset: ", edges_offset)
+ file.seek(edges_offset)
+ var edges_data_left := edges_size
+ var edges := []
+ while (edges_data_left > 0):
+ var edge := BSPEdge.new()
+ if (index_bits_32):
+ edges_data_left -= edge.read_edge_32_bit(file)
+ else:
+ edges_data_left -= edge.read_edge_16_bit(file)
+ #print("edge v 0: ", edge.vertex_index_0)
+ #print("edge v 1: ", edge.vertex_index_0)
+ edges.append(edge)
+ #print("edges_data_left: ", edges_data_left)
+
+ var edge_list : PackedInt32Array
+ var num_edge_list := listedges_size / 4
+ edge_list.resize(num_edge_list)
+ file.seek(listedges_offset)
+ for i in num_edge_list:
+ #edge_list[i] = unsigned16_to_signed(file.get_16())
+ # Page was wrong, this is 32bit
+ edge_list[i] = file.get_32()
+ #print("edge list: ", edge_list[i])
+
+ var num_planes := planes_size / (4 * 5) # vector, float, and int32
+ plane_normals.resize(num_planes)
+ plane_distances.resize(num_planes)
+ file.seek(planes_offset)
+ for i in num_planes:
+ var quake_plane_normal := Vector3(file.get_float(), file.get_float(), file.get_float())
+ plane_normals[i] = convert_vector_from_quake_unscaled(quake_plane_normal)
+ plane_distances[i] = file.get_float() * unit_scale
+ var _type = file.get_32() # 0 = X-Axial plane, 1 = Y-axial pane, 2 = z-axial plane, 3 nonaxial, toward x, 4 y, 5 z
+ #print("Quake plane ", i, ": ", quake_plane_normal, " dist: ", plane_distances[i], " type: ", _type)
+ #print("plane_normals: ", plane_normals)
+ file.seek(clipnodes_offset)
+ var num_clipnodes := clipnodes_size / CLIPNODES_STRUCT_SIZE
+ print("clipnodes offset: ", clipnodes_offset, " clipnodes_size: ", clipnodes_size, " num_clipnodes: ", num_clipnodes)
+ # todo
+
+ # Read in the textures (to get the sizes for UV's)
+ #print("textures offset: ", textures_offset)
+ #var texture_data_left := textures_size
+ #var num_textures := textures_size / BSPTexture.get_data_size()
+ var textures := []
+ var texture_offset_offsets : PackedInt32Array # Offset to texture area has an array of offsets relative to the start of this
+
+ file.seek(textures_offset)
+ var num_textures := file.get_32()
+ texture_offset_offsets.resize(num_textures)
+ print("num_textures: ", num_textures)
+ textures.resize(num_textures)
+ for i in num_textures:
+ texture_offset_offsets[i] = file.get_32()
+ for i in num_textures:
+ var texture_offset := texture_offset_offsets[i]
+ if (texture_offset < 0):
+ print("Missing texture ", i, " make sure wad file is compiled into map.")
+ var bad_tex := BSPTexture.new()
+ bad_tex.width = 64
+ bad_tex.height = 64
+ bad_tex.name = "_bad_texture_"
+ textures[i] = bad_tex
+ else:
+ var complete_offset := textures_offset + texture_offset
+ file.seek(complete_offset)
+ textures[i] = BSPTexture.new()
+ textures[i].read_texture(file, self)
+
+ # UV stuff
+ file.seek(texinfo_offset)
+ var num_texinfo := texinfo_size / BSPTextureInfo.get_data_size()
+ var textureinfos := []
+ textureinfos.resize(num_texinfo)
+ for i in num_texinfo:
+ textureinfos[i] = BSPTextureInfo.new()
+ textureinfos[i].read_texture_info(file)
+ #print("Textureinfo: ", textureinfos[i].vec_s, " ", textureinfos[i].offset_s, " ", textureinfos[i].vec_t, " ", textureinfos[i].offset_t, " ", textureinfos[i].texture_index)
+
+ # Get model data:
+ var model_data_size := MODEL_DATA_SIZE_Q1_BSP if !is_q2 else BSPModelDataQ2.get_data_size()
+ var num_models := models_size / model_data_size
+ var model_data := []
+ model_data.resize(num_models)
+ for i in num_models:
+ if (is_q2):
+ model_data[i] = BSPModelDataQ2.new()
+ file.seek(models_offset + model_data_size * i) # We'll skip around in the file loading data
+ model_data[i].read_model(file)
+ else:
+ model_data[i] = BSPModelData.new()
+ file.seek(models_offset + model_data_size * i) # We'll skip around in the file loading data
+ read_model_data_q1_bsp(model_data[i])
+
+ file.seek(faces_offset)
+ var face_data_left := faces_size
+ var bsp_face := BSPFace.new()
+ var begun := false
+ var previous_tex_name := "UNSET"
+
+ for model_index in num_models:
+ #print("Model index ", model_index)
+ var mesh_grid := {} # Dictionary of surface tools where the key is an integer vector3.
+ water_planes_array = [] # Clear that out so water isn't duplicated for each mesh.
+ slime_planes_array = []
+ lava_planes_array = []
+ var needs_import := false
+ var parent_node : Node3D = root_node
+ var parent_inv_transform := Transform3D() # If a world model is rotated (such as a trigger) we want to keep things in the correct spot
+ var is_worldspawn := (model_index == 0)
+ if (is_worldspawn):
+ needs_import = true # Always import worldspawn.
+ if (SINGLE_STATIC_BODY):
+ var static_body := StaticBody3D.new()
+ static_body.name = "StaticBody"
+ root_node.add_child(static_body, true)
+ static_body.owner = root_node
+ parent_node = static_body
+ if (model_scenes.has(model_index)):
+ needs_import = true # Import supported entities.
+ parent_node = model_scenes[model_index]
+ parent_inv_transform = Transform3D(parent_node.transform.basis.inverse(), Vector3.ZERO) #parent_node.transform.inverse()
+ if (needs_import):
+ var bsp_model : BSPModelData = model_data[model_index]
+ var face_size := BSPFace.get_data_size_q1bsp() if !is_bsp2 else BSPFace.get_data_size_bsp2()
+ file.seek(faces_offset + bsp_model.face_index * face_size)
+ var num_faces := bsp_model.face_count
+ #print("num_faces: ", num_faces)
+ for face_index in num_faces:
+ if (is_bsp2):
+ bsp_face.read_face_bsp2(file)
+ else:
+ bsp_face.read_face_q1bsp(file)
+ if (bsp_face.texinfo_id > textureinfos.size()):
+ printerr("Bad texinfo_id: ", bsp_face.texinfo_id)
+ bsp_face.print_face()
+ continue
+ if (bsp_face.num_edges < 3):
+ printerr("face with fewer than 3 edges.")
+ bsp_face.print_face()
+ continue
+
+ var edge_list_index_start := bsp_face.edge_list_id
+ var i := 0
+ var face_verts : PackedVector3Array
+ face_verts.resize(bsp_face.num_edges)
+ var face_normals : PackedVector3Array
+ face_normals.resize(bsp_face.num_edges)
+ var face_normal := Vector3.UP
+ if (bsp_face.plane_id < plane_normals.size()):
+ face_normal = plane_normals[bsp_face.plane_id]
+ else:
+ print("Plane id out of bounds: ", bsp_face.plane_id)
+ if (bsp_face.plane_side > 0):
+ face_normal = -face_normal
+
+ # Get the texture from the face
+ var tex_info : BSPTextureInfo = textureinfos[bsp_face.texinfo_id]
+ var texture : BSPTexture = textures[tex_info.texture_index]
+
+ var vs := tex_info.vec_s
+ var vt := tex_info.vec_t
+ var s := tex_info.offset_s
+ var t := tex_info.offset_t
+ var tex_width : int = texture.width
+ var tex_height : int = texture.height
+ var tex_name : String = texture.name
+ if (previous_tex_name != tex_name):
+ previous_tex_name = tex_name
+ #print("width: ", tex_width, " height: ", tex_height)
+ var face_uvs : PackedVector2Array
+ face_uvs.resize(bsp_face.num_edges)
+ var tex_scale_x := 1.0 / (unit_scale * tex_width)
+ var tex_scale_y := 1.0 / (unit_scale * tex_height)
+ #print("normal: ", face_normal)
+ var face_position := Vector3.ZERO
+ for edge_list_index in range(edge_list_index_start, edge_list_index_start + bsp_face.num_edges):
+ var vert_index_0 : int
+ var reverse_order := false
+ var edge_index := edge_list[edge_list_index]
+ if (edge_index < 0):
+ reverse_order = true
+ edge_index = -edge_index
+
+ if (reverse_order): # Not sure which way this should be flipped to get correct tangents
+ vert_index_0 = edges[edge_index].vertex_index_1
+ else:
+ vert_index_0 = edges[edge_index].vertex_index_0
+ var vert := verts[vert_index_0]
+ #print("vert (%s): %d, " % ["r" if reverse_order else "f", vert_index_0], vert)
+ face_verts[i] = vert
+ face_normals[i] = face_normal
+ face_uvs[i].x = vert.dot(vs) * tex_scale_x + s / tex_width
+ face_uvs[i].y = vert.dot(vt) * tex_scale_y + t / tex_height
+ #print("vert: ", vert, " vs: ", vs, " d: ", vert.dot(vs), " vt: ", vt, " d: ", vert.dot(vt))
+ face_position += vert
+ i += 1
+ face_position /= i # Average all the verts
+ var surf_tool : SurfaceTool
+ if (texture.is_transparent):
+ # Transparent meshes need to be sorted, so make each face its own mesh for now.
+ surf_tool = SurfaceTool.new()
+ surf_tool.begin(Mesh.PRIMITIVE_TRIANGLES)
+ surf_tool.set_material(texture.material)
+ else:
+ var grid_index
+ if (separate_mesh_on_grid):
+ grid_index = Vector3i(face_position / mesh_separation_grid_size)
+ else:
+ grid_index = 0
+
+ var surface_tools : Dictionary = mesh_grid.get(grid_index, {})
+ if (surface_tools.has(texture.name)):
+ surf_tool = surface_tools[texture.name]
+ else:
+ surf_tool = SurfaceTool.new()
+ surf_tool.begin(Mesh.PRIMITIVE_TRIANGLES)
+ surf_tool.set_material(texture.material)
+ surface_tools[texture.name] = surf_tool
+ mesh_grid[grid_index] = surface_tools
+ surf_tool.add_triangle_fan(face_verts, face_uvs, [], [], face_normals)
+
+ # Need to create unique meshes for each transparent surface so they sort properly.
+ # These ignore the mesh grid.
+ if (texture.is_transparent):
+ var mesh_instance := MeshInstance3D.new()
+ # Create a mesh out of all the surfaces
+ surf_tool.generate_tangents()
+ var array_mesh : ArrayMesh = null
+ array_mesh = surf_tool.commit(array_mesh)
+ mesh_instance.mesh = array_mesh
+ mesh_instance.name = "TransparentMesh"
+ parent_node.add_child(mesh_instance, true)
+ mesh_instance.transform = parent_inv_transform
+ mesh_instance.owner = root_node
+
+ # Create meshes for each cell in the mesh grid.
+ for grid_index in mesh_grid:
+ var surface_tools = mesh_grid[grid_index] # Is there a way to loop through the keys instead?
+ var mesh_instance := MeshInstance3D.new()
+ var array_mesh : ArrayMesh = null
+ var array_mesh_no_cull : ArrayMesh = null
+ var has_nocull_materials := false
+ for texture_name in surface_tools:
+ var surf_tool : SurfaceTool = surface_tools[texture_name]
+ surf_tool.generate_tangents()
+ if (culling_textures_exclude.has(texture_name)):
+ #array_mesh_no_cull = surf_tool.commit(array_mesh_no_cull)
+ has_nocull_materials = true
+ #print("Has no-cull materials")
+ else:
+ array_mesh = surf_tool.commit(array_mesh)
+
+ if (array_mesh || has_nocull_materials):
+ mesh_instance.name = "Mesh"
+ parent_node.add_child(mesh_instance, true)
+ mesh_instance.transform = parent_inv_transform
+ mesh_instance.owner = root_node
+
+ if (generate_occlusion_culling && array_mesh && is_worldspawn): # TOmaybeDO - optional flag on entities for like large doors or something to have occlusion culling?
+ # Occlusion mesh data
+ var vertices := PackedVector3Array()
+ var indices := PackedInt32Array()
+ # Build occlusion from all surfaces of the array mesh.
+ for i in array_mesh.get_surface_count():
+ var offset = vertices.size()
+ var arrays := array_mesh.surface_get_arrays(i)
+ vertices.append_array(arrays[ArrayMesh.ARRAY_VERTEX])
+ if arrays[ArrayMesh.ARRAY_INDEX] == null:
+ indices.append_array(range(offset, offset + arrays[ArrayMesh.ARRAY_VERTEX].size()))
+ else:
+ for index in arrays[ArrayMesh.ARRAY_INDEX]:
+ indices.append(index + offset)
+ # Create and add occluder and occluder instance.
+ var occluder = ArrayOccluder3D.new()
+ occluder.set_arrays(vertices, indices)
+ var occluder_instance = OccluderInstance3D.new()
+ occluder_instance.occluder = occluder
+ occluder_instance.name = "Occluder"
+ mesh_instance.add_child(occluder_instance, true)
+ occluder_instance.owner = root_node
+
+ var shadow_mesh : ArrayMesh = null
+ if (generate_shadow_mesh):
+ print("Generating shadow mesh...")
+ # TODO: Merge verts.
+ # Ideally create_shadow_mesh() from the engine could be exposed and placed on the ArrayMesh class.
+ var vertices := PackedVector3Array()
+ var indices := PackedInt32Array()
+ for i in array_mesh.get_surface_count():
+ var offset = vertices.size()
+ var arrays := array_mesh.surface_get_arrays(i)
+ vertices.append_array(arrays[ArrayMesh.ARRAY_VERTEX])
+ if arrays[ArrayMesh.ARRAY_INDEX] == null:
+ indices.append_array(range(offset, offset + arrays[ArrayMesh.ARRAY_VERTEX].size()))
+ else:
+ for index in arrays[ArrayMesh.ARRAY_INDEX]:
+ indices.append(index + offset)
+ if (indices.size() >= 3): # Make sure we have at least 1 face.
+ shadow_mesh = ArrayMesh.new()
+ var mesh_arrays := []
+ mesh_arrays.resize(ArrayMesh.ARRAY_MAX)
+ indices.resize(3) # TESTING
+ mesh_arrays[ArrayMesh.ARRAY_VERTEX] = vertices
+ mesh_arrays[ArrayMesh.ARRAY_INDEX] = indices
+ shadow_mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, mesh_arrays, [], {}, ArrayMesh.ArrayFormat.ARRAY_FORMAT_VERTEX)
+
+ # Add non-occluding materials to the mesh after we've generated occlusion
+ if (has_nocull_materials):
+ for texture_name in surface_tools:
+ if (culling_textures_exclude.has(texture_name)):
+ var surf_tool : SurfaceTool = surface_tools[texture_name]
+ array_mesh = surf_tool.commit(array_mesh)
+
+ array_mesh.shadow_mesh = shadow_mesh # This will be null if generate_shadow_mesh isn't set.
+ mesh_instance.mesh = array_mesh
+ #print("Shadow mesh: ", shadow_mesh.get_surface_count(), ", ", shadow_mesh.get_faces())
+ if (shadow_mesh):
+ print("Shadow mesh: ", shadow_mesh.get_surface_count())
+
+ if (generate_lightmap_uv2):
+ var err = mesh_instance.mesh.lightmap_unwrap(mesh_instance.global_transform, unit_scale * 4.0)
+ #print("Lightmap unwrap result: ", err)
+
+ if (use_triangle_collision):
+ var collision_shape := CollisionShape3D.new()
+ collision_shape.name = "CollisionShape"
+ collision_shape.shape = mesh_instance.mesh.create_trimesh_shape()
+ parent_node.add_child(collision_shape, true)
+ mesh_instance.transform = parent_inv_transform
+ collision_shape.owner = root_node
+ # Apparently we have to let the gc handle this autamically now: file.close()
+ if (use_bspx_brushes && !use_triangle_collision):
+ var bspx_brushes := bspx_model_to_brush_map.get(model_index)
+ if (bspx_brushes):
+ #print("Number of brushes for model ", model_index, ": ", bspx_brushes.size())
+ create_collision_from_brushes(parent_node, bspx_brushes, parent_inv_transform)
+ else:
+ printerr("Could not find bspx collision for ", model_index)
+ elif (!use_triangle_collision): # Attempt to create collision out of BSP nodes
+ # Clear these out, as we may be importing multiple models.
+ array_of_planes_array = []
+ array_of_planes = []
+ if (0): # Clipnodes -- these are lossy and account for player size
+ print("Node 0: ", bsp_model.node_id0, " Node 1: ", bsp_model.node_id1, " Node 2: ", bsp_model.node_id2, " Node 3: ", bsp_model.node_id3)
+ file.seek(clipnodes_offset + bsp_model.node_id0 * CLIPNODES_STRUCT_SIZE) # Not sure which node I should be using here. I think 0 is for rendering and 1 is point collision.
+ #test_print_planes(file, planes_offset)
+ read_clipnodes_recursive(file, clipnodes_offset)
+ else:
+ var seek_location := nodes_offset + bsp_model.node_id0 * (NODES_STRUCT_SIZE_Q1BSP if !is_bsp2 else NODES_STRUCT_SIZE_Q1BSP2)
+ #print("Reading nodes: ", nodes_offset, " ", bsp_model.node_id0, " location: ", seek_location)
+ file.seek(seek_location)
+ read_nodes_recursive()
+ #print("Array of planes array: ", array_of_planes_array)
+ var model_mins := bsp_model.bound_min;
+ var model_maxs := bsp_model.bound_max;
+ #print("Model mins: ", model_mins, " Model maxs: ", model_maxs)
+ #print("Origin: ", bsp_model.origin)
+ var model_mins_maxs_planes : Array[Plane]
+ model_mins_maxs_planes.push_back(Plane(Vector3.RIGHT, model_maxs.x))
+ model_mins_maxs_planes.push_back(Plane(Vector3.UP, model_maxs.y))
+ model_mins_maxs_planes.push_back(Plane(Vector3.BACK, model_maxs.z))
+ model_mins_maxs_planes.push_back(Plane(Vector3.LEFT, -model_mins.x))
+ model_mins_maxs_planes.push_back(Plane(Vector3.DOWN, -model_mins.y))
+ model_mins_maxs_planes.push_back(Plane(Vector3.FORWARD, -model_mins.z))
+
+ # Create collision shapes for world using BSP planes (we don't have brush data)
+ create_collision_shapes(parent_node, array_of_planes_array, model_mins_maxs_planes, parent_inv_transform)
+
+ # Create liquids (water, slime, lava)
+ create_liquid_from_planes(parent_node, water_planes_array, model_mins_maxs_planes, parent_inv_transform, water_template)
+ create_liquid_from_planes(parent_node, slime_planes_array, model_mins_maxs_planes, parent_inv_transform, slime_template)
+ create_liquid_from_planes(parent_node, lava_planes_array, model_mins_maxs_planes, parent_inv_transform, lava_template)
+ if (post_import_script_path):
+ var post_import_node := Node.new()
+ print("Loading post import script: ", post_import_script_path)
+ var script = load(post_import_script_path)
+ if (script && script is Script):
+ post_import_node.set_script(script)
+ if (post_import_node.has_method("post_import")):
+ if (post_import_node.get_script().is_tool()):
+ post_import_node.post_import(root_node)
+ else:
+ printerr("Post import script must have @tool set.")
+ else:
+ printerr("Post import script does not have post_import() function.")
+ else:
+ printerr("Invalid script path: ", post_import_script_path)
+ #print("Post import nodes: ", post_import_nodes)
+ for node in post_import_nodes:
+ node.post_import(root_node)
+
+ file.close()
+ file = null
+ print("BSP read complete.")
+ return root_node
+
+
+# Traverse tree and create liquid.
+# Note: Not used if we have the brush data.
+func create_liquid_from_planes(parent_node : Node3D, planes_array : Array, model_mins_maxs_planes : Array[Plane], parent_inv_transform : Transform3D, template : PackedScene):
+ if (planes_array.size() > 0 && template):
+ var liquid_body : Node = template.instantiate()
+ parent_node.add_child(liquid_body, true)
+ liquid_body.transform = parent_inv_transform
+ liquid_body.owner = root_node
+ create_collision_shapes(liquid_body, planes_array, model_mins_maxs_planes, Transform3D())
+
+
+func parse_entity_string(entity_string : String) -> Array:
+ var ent_dict := {}
+ var ent_dict_array := []
+ var in_key_string := false
+ var in_value_string := false
+ var key : StringName
+ var value : String
+ var parsed_key := false
+ for char in entity_string:
+ if (in_key_string):
+ if (char == '"'):
+ in_key_string = false
+ parsed_key = true
+ else:
+ key += char
+ elif (in_value_string):
+ if (char == '"'):
+ in_value_string = false
+ ent_dict[key] = value
+ key = ""
+ value = ""
+ parsed_key = false
+ else:
+ value += char
+ elif (char == '"'):
+ if (parsed_key):
+ in_value_string = true
+ else:
+ in_key_string = true
+ elif (char == '}'):
+ ent_dict_array.push_back(ent_dict)
+ elif (char == '{'):
+ ent_dict = {}
+ parsed_key = false
+ return ent_dict_array
+
+const WORLDSPAWN_STRING_NAME := &"worldspawn"
+const LIGHT_STRING_NAME := &"light"
+var post_import_nodes : Array[Node] = []
+
+
+func convert_entity_dict_to_scene(ent_dict_array : Array):
+ post_import_nodes = []
+ for ent_dict in ent_dict_array:
+ if (ent_dict.has("classname")):
+ var classname : StringName = ent_dict["classname"].to_lower()
+ var scene_path : String = ""
+ if (entity_remap.has(classname)):
+ scene_path = entity_remap[classname]
+ else:
+ if (classname != WORLDSPAWN_STRING_NAME):
+ scene_path = entity_path_pattern.replace("{classname}", classname)
+
+ if (!scene_path.is_empty() && ResourceLoader.exists(scene_path)):
+ var scene_resource = load(scene_path)
+ if (!scene_resource):
+ print("Failed to load ", scene_path)
+ else:
+ var scene_node : Node = scene_resource.instantiate()
+ if (!scene_node):
+ print("Failed to instantiate scene: ", scene_path)
+ else:
+ if (scene_node.has_method("post_import")):
+ post_import_nodes.append(scene_node)
+ add_generic_entity(scene_node, ent_dict)
+
+ # Imported script might need to know all values in the entity dictionary ahead of time, so optionally send that as well.
+ if (scene_node.has_method("set_entity_dictionary")):
+ if (!scene_node.get_script().is_tool()):
+ printerr(scene_node.name + " has 'set_entity_dictionary()' function but must have @tool set to work for imports.")
+ else:
+ scene_node.set_entity_dictionary(ent_dict)
+
+ # For every key/value pair in the entity, see if there's a corresponding
+ # variable in the gdscript and set it.
+ for key in ent_dict.keys():
+ var string_value : String = ent_dict[key]
+ var value = string_value
+ if (key == "spawnflags"):
+ value = value.to_int()
+
+ # Allow scenes to have custom implementations of this so they can remap values or whatever
+ # Returning true means it was handled.
+ if (scene_node.has_method("set_import_value")):
+ if (!scene_node.get_script().is_tool()):
+ printerr(scene_node.name + " has 'set_import_value()' function but must have @tool set to work for imports.")
+ else:
+ if (scene_node.set_import_value(key, string_value)):
+ continue
+
+ var dest_value = scene_node.get(key) # Se if we can figure out the type of the destination value
+ if (dest_value != null):
+ var dest_type := typeof(dest_value)
+ match (dest_type):
+ TYPE_BOOL:
+ value = convert_string_to_bool(string_value)
+ TYPE_INT:
+ value = string_value.to_int()
+ TYPE_FLOAT:
+ value = string_value.to_float()
+ TYPE_STRING:
+ value = string_value
+ TYPE_STRING_NAME:
+ value = string_value
+ TYPE_VECTOR3:
+ value = string_to_vector3(string_value)
+ TYPE_COLOR:
+ value = string_to_color(string_value)
+ _:
+ printerr("Key value type not handled for ", key, " : ", dest_type)
+ value = string_value # Try setting it to the string value and hope for the best.
+ scene_node.set(key, value)
+ else: # No entity remap for this classname or no scene matching the entity path pattern
+ if (classname == LIGHT_STRING_NAME):
+ if (import_lights):
+ add_light_entity(ent_dict)
+ else:
+ if (classname != WORLDSPAWN_STRING_NAME):
+ if (!scene_path.is_empty()):
+ if not ignore_missing_entities:
+ printerr("Could not open ", scene_path, " for classname: ", classname)
+ else:
+ printerr("No entity remap found for ", classname, ". Ignoring.")
+
+
+func add_generic_entity(scene_node : Node, ent_dict : Dictionary):
+ var origin := Vector3.ZERO
+ if (ent_dict.has("origin")):
+ var origin_string : String = ent_dict["origin"]
+ origin = string_to_origin(origin_string, unit_scale)
+ var offset : Vector3 = convert_vector_from_quake_scaled(entity_offsets_quake_units.get(ent_dict["classname"], Vector3.ZERO), unit_scale)
+ origin += offset
+ var mangle_string : String = ent_dict.get("mangle", "")
+ var angle_string : String = ent_dict.get("angle", "")
+ var angles_string : String = ent_dict.get("angles", "")
+ var basis := Basis()
+ if (angle_string.length() > 0):
+ basis = angle_string_to_basis(angle_string)
+ if (mangle_string.length() > 0):
+ basis = mangle_string_to_basis(mangle_string)
+ if (angles_string.length() > 0):
+ basis = angles_string_to_basis(angles_string)
+ var transform := Transform3D(basis, origin)
+ root_node.add_child(scene_node, true)
+ scene_node.transform = transform
+ scene_node.owner = root_node
+ if (ent_dict.has("model")):
+ var model_value : String = ent_dict["model"]
+ # Models that start with a * are contained with in the BSP file (ex: doors, triggers, etc)
+ if (model_value[0] == '*'):
+ model_scenes[model_value.substr(1).to_int()] = scene_node
+
+
+const _COLOR_STRING_NAME := StringName("_color")
+const COLOR_STRING_NAME := StringName("color")
+
+
+func add_light_entity(ent_dict : Dictionary):
+ var light_node := OmniLight3D.new()
+ var light_value := 300.0
+ var light_color := Color(1.0, 1.0, 1.0, 1.0)
+ var color_string : String
+ if (ent_dict.has(LIGHT_STRING_NAME)):
+ light_value = ent_dict[LIGHT_STRING_NAME].to_float()
+ if (ent_dict.has(_COLOR_STRING_NAME)):
+ light_color = string_to_color(ent_dict[_COLOR_STRING_NAME])
+ if (ent_dict.has(COLOR_STRING_NAME)):
+ light_color = string_to_color(ent_dict[COLOR_STRING_NAME])
+ light_node.omni_range = light_value * unit_scale
+ light_node.light_energy = light_value * light_brightness_scale / 255.0
+ light_node.light_color = light_color
+ light_node.shadow_enabled = true # Might want to have an option to shut this off for some lights?
+ add_generic_entity(light_node, ent_dict)
+
+
+func string_to_color(color_string : String) -> Color:
+ var color := Color(1.0, 1.0, 1.0, 1.0)
+ var floats := color_string.split_floats(" ")
+ var scale := 1.0
+ # Sometimes color is in the 0-255 range, so if anything is above 1, divide by 255
+ for f in floats:
+ if f > 1.0:
+ scale = 1.0 / 255.0
+ break
+ for i in min(3, floats.size()):
+ color[i] = floats[i] * scale
+ return color
+
+
+static func string_to_origin(origin_string : String, scale: float) -> Vector3:
+ var vec := string_to_vector3(origin_string)
+ return convert_vector_from_quake_scaled(vec, scale)
+
+
+static func string_to_vector3(vec_string : String) -> Vector3:
+ var vec := Vector3.ZERO
+ var split := vec_string.split(" ")
+ var i := 0
+ for pos in split:
+ if (i < 3):
+ vec[i] = pos.to_float()
+ i += 1
+ return vec
+
+
+static func string_to_angles_pyr(angles_string : String, pitch_up_negative : bool) -> Vector3:
+ var split := angles_string.split(" ")
+ var angles := Vector3.ZERO
+ var i := 0
+ for pos in split:
+ if (i < 3):
+ angles[i] = deg_to_rad(pos.to_float())
+ i += 1
+ if (pitch_up_negative):
+ angles[0] = -angles[0]
+ return angles
+
+
+static func angles_string_to_basis_pyr(angles_string : String, pitch_up_negative : bool) -> Basis:
+ var angles := string_to_angles_pyr(angles_string, pitch_up_negative)
+ return Basis.from_euler(angles)
+
+
+static func mangle_string_to_basis(mangle_string : String) -> Basis:
+ return angles_string_to_basis_pyr(mangle_string, true)
+
+
+static func angle_string_to_basis(angle_string : String) -> Basis:
+ # Special case for up and down:
+ if (angle_string == "-1"): # Up, but Z is negative for forward, so we use DOWN
+ return Basis(Vector3.RIGHT, Vector3.BACK, Vector3.DOWN)
+ if (angle_string == "-2"): # Down, but Z is negative for forward, so we use UP
+ return Basis(Vector3.RIGHT, Vector3.FORWARD, Vector3.UP)
+ var angles := Vector3.ZERO
+ angles[1] = deg_to_rad(angle_string.to_float())
+ var basis := Basis.from_euler(angles)
+ return basis
+
+
+static func angles_string_to_basis(angles_string : String) -> Basis:
+ # Sometimes this is the same as mangle, and sometimes it's yaw pitch roll, depending on the entity
+ # Not sure 100% what the rules are, so just use mangle for now.
+ return angles_string_to_basis_pyr(angles_string, true)
+
+
+func create_collision_from_brushes(parent : Node3D, brushes : Array[BSPXBrush], parent_inv_transform : Transform3D):
+ #print("create_collision_from_brushes\n")
+ var water_body : Node3D
+ var slime_body : Node3D
+ var lava_body : Node3D
+ var collision_index := 0
+ #print("Total brushes: ", brushes.size())
+ var brushes_added := 0
+ for brush in brushes:
+ collision_index += 1
+ var aabb := AABB(brush.mins, Vector3.ZERO)
+ aabb = aabb.expand(brush.maxs)
+ var center := aabb.get_center()
+ var body_to_add_to : Node3D = parent
+ if (brush.contents == CONTENTS_SOLID):
+ if (!SINGLE_STATIC_BODY):
+ var static_body_child := StaticBody3D.new()
+ static_body_child.name = "StaticBody%d" % collision_index
+ #static_body_child.transform = collision_shape.transform
+ #collision_shape.transform = Transform3D()
+ parent.add_child(static_body_child, true)
+ static_body_child.owner = root_node
+ body_to_add_to = static_body_child
+ elif (brush.contents == CONTENTS_WATER):
+ if (!water_body):
+ water_body = water_template.instantiate()
+ parent.add_child(water_body)
+ water_body.owner = root_node
+ body_to_add_to = water_body
+ print("water body ", water_body)
+ elif (brush.contents == CONTENTS_SLIME):
+ if (!slime_body):
+ slime_body = slime_template.instantiate()
+ parent.add_child(slime_body)
+ slime_body.owner = root_node
+ body_to_add_to = slime_body
+ elif (brush.contents == CONTENTS_LAVA):
+ if (!lava_body):
+ lava_body = lava_template.instantiate()
+ parent.add_child(lava_body)
+ lava_body.owner = root_node
+ body_to_add_to = lava_body
+ else:
+ print("Unknown brush contents: ", brush.contents)
+ if (brush.planes.size() == 0): # If it's just an AABB, we can use a box.
+ var collision_shape := CollisionShape3D.new()
+ collision_shape.name = "CollisionBox%d" % collision_index
+ var box := BoxShape3D.new()
+ box.size = aabb.size
+ collision_shape.position = center
+ collision_shape.shape = box
+ body_to_add_to.add_child(collision_shape)
+ brushes_added += 1
+ collision_shape.owner = root_node
+ collision_shape.transform = parent_inv_transform * collision_shape.transform
+ else: # Planes. Can't do a simple box (Though maybe it could be a rotated box?)
+ var planes := brush.planes
+ planes.push_back(Plane(Vector3.RIGHT, brush.maxs.x))
+ planes.push_back(Plane(Vector3.UP, brush.maxs.y))
+ planes.push_back(Plane(Vector3.BACK, brush.maxs.z))
+ planes.push_back(Plane(Vector3.LEFT, -brush.mins.x))
+ planes.push_back(Plane(Vector3.DOWN, -brush.mins.y))
+ planes.push_back(Plane(Vector3.FORWARD, -brush.mins.z))
+ var convex_points := convert_planes_to_points(planes)
+ if (convex_points.size() < 3):
+ print("Convex shape creation failed ", collision_index)
+ else:
+ var collision_shape := CollisionShape3D.new()
+ #print("Convex planes: ", convex_planes)
+ collision_shape.name = "Collision%d" % collision_index
+ collision_shape.shape = ConvexPolygonShape3D.new()
+ for point_index in convex_points.size():
+ convex_points[point_index] -= center
+ collision_shape.shape.points = convex_points
+ collision_shape.position = center
+ collision_shape.transform = parent_inv_transform * collision_shape.transform
+ #print("Convex points: ", convex_points)
+ body_to_add_to.add_child(collision_shape)
+ brushes_added += 1
+ collision_shape.owner = root_node
+ #print("Brushes added: ", brushes_added)
+
+func create_collision_shapes(body : Node3D, planes_array, model_mins_maxs_planes, parent_inv_transform : Transform3D):
+ #print("Create collision shapes.")
+ for i in planes_array.size():
+ var plane_indexes : PackedInt32Array = planes_array[i]
+ var convex_planes : Array[Plane]
+ #print("Planes index: ", i)
+ convex_planes.append_array(model_mins_maxs_planes)
+ for plane_index in plane_indexes:
+ # sign of 0 is 0, so we offset the index by 1.
+ var plane := Plane(plane_normals[abs(plane_index) - 1] * sign(plane_index), (plane_distances[abs(plane_index) - 1]) * sign(plane_index))
+ convex_planes.push_back(plane)
+ #print("Plane ", plane_index, ": ", plane)
+ var convex_points := convert_planes_to_points(convex_planes)
+ if (convex_points.size() < 3):
+ print("Convex shape creation failed ", i)
+ else:
+ var collision_shape := CollisionShape3D.new()
+ #print("Convex planes: ", convex_planes)
+ collision_shape.name = "Collision%d" % i
+ var center := Vector3.ZERO
+ for point in convex_points:
+ center += point
+ center /= convex_points.size()
+ if (TEST_BOX_ONLY_COLLISION):
+ var aabb := AABB(convex_points[0], Vector3.ZERO)
+ for point in convex_points:
+ aabb = aabb.expand(point)
+ var box_shape := BoxShape3D.new()
+ box_shape.size = abs(aabb.size)
+ collision_shape.shape = box_shape
+ else:
+ collision_shape.shape = ConvexPolygonShape3D.new()
+ for point_index in convex_points.size():
+ convex_points[point_index] -= center
+ collision_shape.shape.points = convex_points
+ collision_shape.position = center
+ collision_shape.transform = parent_inv_transform * collision_shape.transform
+ #print("Convex points: ", convex_points)
+ if (SINGLE_STATIC_BODY):
+ body.add_child(collision_shape)
+ else:
+ var static_body := StaticBody3D.new()
+ static_body.name = "StaticBody%d" % i
+ static_body.transform = collision_shape.transform
+ collision_shape.transform = Transform3D()
+ body.add_child(static_body, true)
+ static_body.owner = root_node
+ static_body.add_child(collision_shape)
+ collision_shape.owner = root_node
+
+
+func read_nodes_recursive():
+ var plane_index := file.get_32()
+ var child0 := unsigned16_to_signed(file.get_16()) if !is_bsp2 else unsigned32_to_signed(file.get_32())
+ var child1 := unsigned16_to_signed(file.get_16()) if !is_bsp2 else unsigned32_to_signed(file.get_32())
+ #print("plane: ", plane_index, " child0: ", child0, " child1: ", child1)
+ # Hack upon hack -- store the plane index offset by 1, so we can negate the first index
+ array_of_planes.push_back(-(plane_index + 1)) # Stupid nonsense where the front plane is negative. Store the index as negative so we know to negate the plane later
+ handle_node_child(child0)
+ array_of_planes.resize(array_of_planes.size() - 1) # pop back
+ array_of_planes.push_back(plane_index + 1)
+ handle_node_child(child1)
+ array_of_planes.resize(array_of_planes.size() - 1) # pop back
+
+
+func handle_node_child(child_value : int):
+ if (child_value < 0): # less than 0 means its a leaf.
+ var leaf_id := ~child_value
+ var file_offset := leaves_offset + leaf_id * (LEAF_SIZE_Q1BSP if !is_bsp2 else LEAF_SIZE_BSP2)
+ #print("leaf_id: ", leaf_id, " file offset: ", file_offset)
+ file.seek(file_offset)
+ var leaf_type := unsigned32_to_signed(file.get_32())
+ #print("leaf_type: ", leaf_type)
+ match leaf_type:
+ CONTENTS_SOLID:
+ array_of_planes_array.push_back(array_of_planes.duplicate())
+ CONTENTS_WATER:
+ water_planes_array.push_back(array_of_planes.duplicate())
+ CONTENTS_SLIME:
+ slime_planes_array.push_back(array_of_planes.duplicate())
+ CONTENTS_LAVA:
+ lava_planes_array.push_back(array_of_planes.duplicate())
+ else:
+ file.seek(nodes_offset + child_value * (NODES_STRUCT_SIZE_Q1BSP if !is_bsp2 else NODES_STRUCT_SIZE_Q1BSP2))
+ read_nodes_recursive()
+
+
+func read_clipnodes_recursive(file : FileAccess, clipnodes_offset : int):
+ var plane_index := file.get_32()
+ var child0 := unsigned16_to_signed(file.get_16()) # Need to handle BSP2 if we ever use this
+ var child1 := unsigned16_to_signed(file.get_16())
+ print("plane: ", plane_index, " child0: ", child0, " child1: ", child1)
+ array_of_planes.push_back(-plane_index) # Stupid nonsense where the front plane is negative. Store the index as negative so we know to negate the plane later
+ handle_clip_child(file, clipnodes_offset, child0)
+ array_of_planes.resize(array_of_planes.size() - 1) # pop back
+ array_of_planes.push_back(plane_index)
+ handle_clip_child(file, clipnodes_offset, child1)
+ array_of_planes.resize(array_of_planes.size() - 1) # pop back
+
+
+func handle_clip_child(file : FileAccess, clipnodes_offset : int, child_value : int):
+ if (child_value < 0): # less than 0 means its a leaf.
+ if (child_value == CONTENTS_SOLID):
+ array_of_planes_array.push_back(array_of_planes.duplicate())
+ else:
+ file.seek(clipnodes_offset + child_value * CLIPNODES_STRUCT_SIZE)
+ read_clipnodes_recursive(file, clipnodes_offset)
+
+
+func convert_planes_to_points(convex_planes : Array[Plane]) -> PackedVector3Array :
+ # If you get errors about this, you're using a godot version that doesn't have this
+ # function exposed, yet. Comment it out and uncomment the code below.
+ return Geometry3D.compute_convex_mesh_points(convex_planes)
+# var clipper := BspClipper.new()
+# clipper.begin()
+# for plane in convex_planes:
+# clipper.clip_plane(plane)
+# clipper.filter_and_clean()
+#
+# return clipper.vertices
+
+func create_wad_table():
+ var wad_path = texture_path_pattern.replace("{texture_name}.png", "wad/")
+ if not DirAccess.dir_exists_absolute(wad_path): DirAccess.make_dir_recursive_absolute(wad_path)
+ var files_in_dir = DirAccess.get_files_at(wad_path)
+
+ for file in files_in_dir:
+ if file.get_extension() == "wad":
+ var w : WADReader = load(wad_path + file).instantiate()
+ wad_paths.append(w)
+ prints("loading", w)
+
+# BSPTexture is optional, for handling Q1 BSP files that have textures embedded.
+func load_or_create_material(name : StringName, bsp_texture : BSPTexture = null) -> MaterialInfo:
+ var width := 0
+ var height := 0
+ var material : Material = null
+ if (bsp_texture):
+ width = bsp_texture.width
+ height = bsp_texture.height
+ var material_path : String
+ if (texture_material_rename.has(name)):
+ material_path = texture_material_rename[name]
+ else:
+ material_path = material_path_pattern.replace("{texture_name}", name)
+ var image_path : String
+ var texture : Texture2D = null
+ var texture_emission : Texture2D = null
+ var need_to_save_image := false
+ if (texture_path_remap.has(name)):
+ image_path = texture_path_remap[name]
+ else:
+ image_path = texture_path_pattern.replace("{texture_name}", name)
+ var original_image_path := image_path
+
+ if (!ResourceLoader.exists(image_path)):
+ image_path = str(image_path.get_basename(), ".jpg") # Jpeg fallback
+ if (!ResourceLoader.exists(image_path)):
+ image_path = str(image_path.get_basename(), ".tga") # tga fallback
+ if (ResourceLoader.exists(image_path)):
+ texture = load(image_path)
+ if (texture):
+ width = texture.get_width()
+ height = texture.get_height()
+ print(name, ": External image width: ", width, " height: ", height)
+ elif (!ResourceLoader.exists(image_path) && !is_gsrc):
+ print("Could not load ", original_image_path)
+
+ # finally, check for if it is goldsrc to read the wad.
+ # this code is pretty sucky wucky :-( probably better for memory management
+ if (!ResourceLoader.exists(image_path) && is_gsrc):
+ for wad in wad_paths:
+ var n = name.to_lower()
+ if wad.resources.has(n):
+ var struct = wad.resources.get(n)
+ texture = wad.load_texture(struct, texture_path_pattern.replace("{texture_name}", struct.get("name")), true)
+
+
+ var image_emission_path : String
+ image_emission_path = texture_emission_path_pattern.replace("{texture_name}", name)
+ if (ResourceLoader.exists(image_emission_path)):
+ texture_emission = load(image_emission_path)
+ if (ResourceLoader.exists(material_path)):
+ material = load(material_path)
+ if (material && !overwrite_existing_materials):
+ # Try to get the width and height off of the material.
+ if (width == 0 || height == 0):
+ print(name, ": Texture size is 0. Attempting to get texture size from material.")
+ if (material is BaseMaterial3D):
+ print("Attempting to get image size from base material.")
+ texture = material.albedo_texture
+ elif (material is ShaderMaterial):
+ var parameters_to_check : PackedStringArray = [ "albedo_texture", "texture_albedo", "texture", "albedo", "texture_diffuse" ]
+ for param_name in parameters_to_check:
+ # Might not exist/be a texture, so we need to test for htat.
+ var test = material.get_shader_parameter(param_name)
+ if (test is Texture2D):
+ print("Got ", param_name, " from ShaderMaterial.")
+ texture = test
+ break
+ if (!texture):
+ print("No texture found in shader material with these parameters: ", parameters_to_check)
+ if (texture):
+ width = texture.get_width()
+ height = texture.get_height()
+ print("Material texture width: ", width, " height: ", height)
+ else:
+ print("No texture found in material.")
+ else: # Need to create a material.
+ print(name, ": Need to create a material.")
+ var image : Image = null
+ var image_emission : Image = null
+ if (!texture || overwrite_existing_textures): # Try creating image from the texture in the BSP file.
+ var palette : PackedByteArray = []
+ var palette_file := FileAccess.open(texture_palette_path, FileAccess.READ)
+ if (palette_file):
+ palette = palette_file.get_buffer(256 * 3)
+ else: # No palette, load default palette.
+ print("Could not load palette file: ", texture_palette_path, ". loading built-in palette.")
+ palette = generate_default_palette()
+ if (bsp_texture):
+ if (bsp_texture.texture_data_offset > 0):
+ print("Reading texture from bsp file at ", bsp_texture.texture_data_offset)
+ file.seek(bsp_texture.texture_data_offset)
+ var num_pixels := width * height
+ var image_data : PackedByteArray = []
+ var image_data_emission : PackedByteArray = []
+ image_data.resize(num_pixels * 3)
+ var has_emission := false
+ var image_cursor := 0
+ for pixel_index in num_pixels:
+ var indexed_color := file.get_8()
+ if (is_fullbright_index(indexed_color)):
+ if (!has_emission):
+ has_emission = true
+ image_data_emission.resize(num_pixels * 3)
+ # If it's fullbright, write the color to emission and black to albedo.
+ image_data[image_cursor] = 0
+ image_data_emission[image_cursor] = palette[indexed_color * 3 + 0] # Sir_Kane thought it was disguisting that I didn't have a + 0 here.
+ image_cursor += 1
+ image_data[image_cursor] = 0
+ image_data_emission[image_cursor] = palette[indexed_color * 3 + 1]
+ image_cursor += 1
+ image_data[image_cursor] = 0
+ image_data_emission[image_cursor] = palette[indexed_color * 3 + 2]
+ image_cursor += 1
+ else: # Not fullbright
+ image_data[image_cursor] = palette[indexed_color * 3 + 0] # Sir_Kane thought it was disguisting that I didn't have a + 0 here.
+ image_cursor += 1
+ image_data[image_cursor] = palette[indexed_color * 3 + 1]
+ image_cursor += 1
+ image_data[image_cursor] = palette[indexed_color * 3 + 2]
+ image_cursor += 1
+ image = Image.create_from_data(width, height, false, Image.FORMAT_RGB8, image_data)
+ image.generate_mipmaps()
+ if (has_emission):
+ image_emission = Image.create_from_data(width, height, false, Image.FORMAT_RGB8, image_data_emission)
+ image_emission.generate_mipmaps()
+ texture = ImageTexture.create_from_image(image)
+ need_to_save_image = true
+ #file.seek(bsp_texture.current_file_offset) # Go back to where we were, in case that matters for reading the next texture.
+ else:
+ print("No texture data in BSP file.")
+ if (texture && generate_texture_materials):
+ print("Creating material with texture.")
+ material = StandardMaterial3D.new()
+ material.albedo_texture = texture
+ #print("albedo_texture set to ", material.albedo_texture)
+ if (image_emission):
+ texture_emission = ImageTexture.create_from_image(image_emission)
+ #print("texture_emission = ", texture_emission)
+ if (texture_emission):
+ print("Emission enabled.")
+ material.emission_enabled = true
+ material.emission_texture = texture_emission
+ material.texture_filter = BaseMaterial3D.TEXTURE_FILTER_NEAREST
+ material.diffuse_mode = BaseMaterial3D.DIFFUSE_BURLEY
+ material.specular_mode = BaseMaterial3D.SPECULAR_DISABLED
+ if (name.begins_with(transparent_texture_prefix)):
+ print("Transparency enabled.")
+ material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA_SCISSOR
+ if (save_separate_materials): # Write materials
+ print("Save separate materials.")
+ # Write texture if it wasn't in the project.
+ if (image && need_to_save_image):
+ image_path = str(image_path.get_basename(), ".png") # Make sure images we write have png extension
+ print("Writing image to ", image_path)
+ # Create image directory if it doesn't exist
+ var image_dir := image_path.get_base_dir()
+ if (!DirAccess.dir_exists_absolute(image_dir)):
+ DirAccess.make_dir_recursive_absolute(image_dir)
+ var err := image.save_png(image_path)
+ if (err != OK):
+ printerr("Failed to write to ", image_path, " (", err, ")")
+ else:
+ material.albedo_texture.resource_path = image_path
+ if (image_emission):
+ image_emission_path = str(image_emission_path.get_basename(), ".png") # Make sure we use the png extenison.
+ err = image_emission.save_png(image_emission_path)
+ if (err == OK):
+ material.emission_texture.resource_path = image_emission_path
+ else:
+ printerr("Failed to write to ", image_emission_path, " (", err, ")")
+
+ # Create directory if it doesn't exist
+ var material_dir := material_path.get_base_dir()
+ print("Material dir: ", material_dir)
+ if (!DirAccess.dir_exists_absolute(material_dir)):
+ DirAccess.make_dir_recursive_absolute(material_dir)
+ var err := ResourceSaver.save(material, material_path) # Note: If we do map loading from within the game, we don't want to save this.
+ if (err == OK):
+ print("Wrote material: ", material_path)
+ material.take_over_path(material_path) # Not sure why setting resource_path here doesn't save a reference to the resource.
+ else:
+ printerr("Failed to write to ", material_path)
+ else:
+ if (material):
+ print("Material with no texture image.")
+ if (!material):
+ print("No texture found. Assigning random color.")
+ material = StandardMaterial3D.new()
+ material.albedo_color = Color(randf_range(0.0, 1.0), randf_range(0.0, 1.0), randf_range(0.0, 1.0))
+ var material_info := MaterialInfo.new()
+ material_info.material = material
+ material_info.width = width
+ material_info.height = height
+ return material_info
+
+func is_fullbright_index(index : int) -> bool:
+ if (fullbright_range.size() == 0):
+ return false
+ if (index >= fullbright_range[0]):
+ if (fullbright_range.size() > 1):
+ if (index <= fullbright_range[1]):
+ return true
+ else:
+ return true
+ return false
+
+
+func lerp_palette_range(start_index : int, end_index : int, start_color : Color, end_color : Color):
+ var total := end_index - start_index + 1
+ var byte_index := start_index * 3
+ for i in total:
+ var fraction := float(i) / float(total)
+ var color := start_color.lerp(end_color, fraction)
+ default_palette[byte_index] = int(roundf(color.r * 255))
+ byte_index += 1
+ default_palette[byte_index] = int(roundf(color.g * 255))
+ byte_index += 1
+ default_palette[byte_index] = int(roundf(color.b * 255))
+ byte_index += 1
+
+
+func generate_default_palette():
+ if (default_palette.size() == 0):
+ default_palette.resize(256 * 3)
+ for i in (256 * 3):
+ default_palette[i] = ((i * 256) / (256 * 3))
+ # Generate an approximation of the Quake palette. Supposedly it's public domain, but just to be safe, I'm doing my own thing:
+ var index := 0
+ lerp_palette_range(0, 15, Color.BLACK, Color(0.92, 0.92, 0.92))
+ lerp_palette_range(16, 31, Color(0.06, 0.04, 0.03), Color(0.56, 0.44, 0.14))
+ lerp_palette_range(32, 47, Color(0.04, 0.04, 0.06), Color(0.55, 0.55, 0.8))
+ lerp_palette_range(48, 63, Color.BLACK, Color(0.42, 0.42, 0.06))
+ lerp_palette_range(64, 79, Color(0.03, 0.0, 0.0), Color(0.5, 0.0, 0.0)) # reds
+ lerp_palette_range(80, 95, Color(0.07, 0.07, 0.0), Color(0.69, 0.40, 0.14)) # dark green to light brown
+ lerp_palette_range(96, 103, Color(0.14, 0.07, 0.03), Color(0.5, 0.23, 0.17)) # brown to yellow 1 (gold)
+ lerp_palette_range(104, 111, Color(0.56, 0.26, 0.20), Color(1.00, 1.00, 0.11)) # brown to yellow, 2 (gold)
+ lerp_palette_range(112, 119, Color(0.04, 0.03, 0.00), Color(0.44, 0.29, 0.20)) # tan/flesh 1
+ lerp_palette_range(120, 127, Color(0.50, 0.33, 0.25), Color(0.89, 0.70, 0.60)) # tan/flesh 2
+ lerp_palette_range(128, 143, Color(0.67, 0.54, 0.64), Color(0.06, 0.03, 0.03))
+ lerp_palette_range(144, 159, Color(0.73, 0.45, 0.62), Color(0.06, 0.03, 0.03))
+ lerp_palette_range(160, 167, Color(0.86, 0.76, 0.73), Color(0.48, 0.39, 0.33)) # tan 1
+ lerp_palette_range(168, 175, Color(0.42, 0.34, 0.29), Color(0.06, 0.04, 0.03)) # tan 2
+ lerp_palette_range(176, 191, Color(0.44, 0.51, 0.48), Color(0.03, 0.04, 0.03))
+ lerp_palette_range(192, 207, Color(1.00, 0.95, 0.11), Color(0.04, 0.03, 0.00))
+ lerp_palette_range(208, 223, Color(0.00, 0.00, 1.00), Color(0.04, 0.04, 0.06)) # blue
+ lerp_palette_range(224, 231, Color(0.17, 0.00, 0.00), Color(0.64, 0.15, 0.04)) # dark red to light orange/tan 1 (lava)
+ lerp_palette_range(232, 239, Color(0.72, 0.20, 0.06), Color(0.97, 0.83, 0.55)) # dark red to light orange/tan 2
+ lerp_palette_range(240, 243, Color(167.0/255, 123.0/255, 59.0/255), Color(231.0/255, 227.0/255, 87.0/255))
+ lerp_palette_range(244, 249, Color(127.0/255, 191.0/255, 255.0/255), Color(215.0/255, 255.0/255, 255.0/255))
+ lerp_palette_range(247, 251, Color(0.40, 0.00, 0.00), Color(1.0, 0.0, 0.0)) # bright red
+ lerp_palette_range(252, 254, Color(255.0/255, 243.0/255, 147.0/255), Color.WHITE)
+ default_palette[255*3+0] = 160
+ default_palette[255*3+1] = 92
+ default_palette[255*3+2] = 84
+ return default_palette
+
+
+# CSLR's Q2BSP importer code -- probably lots of redundant stuff here that should be merged into a common code path.
+
+enum {LUMP_OFFSET, LUMP_LENGTH}
+var geometry := {}
+var textures := {}
+var lightmap_texture : Image
+
+var entities := []
+
+var models := []
+
+
+class BSPPlane:
+ var normal := Vector3.ZERO
+ var distance : float = 0
+ var type : int = 0 # ?
+
+class BSPBrush:
+ var first_brush_side : int = 0
+ var num_brush_side : int = 0
+ var flags : int = 0
+
+class BSPBrushSide:
+ var plane_index : int = 0
+ var texture_information : int = 0
+
+
+
+func convertBSPtoScene(file_path : String) -> Node:
+ prints("Converting File", file_path, ". Please Keep in Mind Quake 2 Support is Still in Development and has some issues. file an issue on github if an issue occurs -cs")
+
+ var file_name = file_path.get_base_dir()
+ print(file_name)
+
+ root_node = StaticBody3D.new()
+ var MeshInstance = convert_to_mesh(file_path)
+ var CollisionShape = CollisionShape3D.new()
+
+ var cnn = str("BSP_", file_path.get_basename().trim_prefix(file_path.get_base_dir())).replace("/", "")
+ root_node.name = cnn
+
+ root_node.add_child(MeshInstance)
+
+ MeshInstance.owner = root_node
+
+ var collisions = create_collisions()
+
+ for collision in collisions:
+ var cs = CollisionShape3D.new()
+ root_node.add_child(cs)
+ cs.owner = root_node
+ cs.shape = collision
+ cs.name = str('brush', RID(collision).get_id())
+
+ root_node.set_collision_layer_value(2, true)
+ root_node.set_collision_mask_value(2, true)
+
+
+ return root_node
+
+const Q2_TABLE = [
+ "LUMP_ENTITIES",
+ "LUMP_PLANE",
+ "LUMP_VERTEX",
+ "LUMP_VIS",
+ "LUMP_NODE",
+ "LUMP_TEXTURE",
+ "LUMP_FACE",
+ "LUMP_LIGHTMAP",
+ "LUMP_LEAVES",
+ "LUMP_LEAF_FACE_TABLE",
+ "LUMP_LEAF_BRUSH_TABLE",
+ "LUMP_EDGE",
+ "LUMP_FACE_EDGE",
+ "LUMP_MODEL",
+ "LUMP_BRUSH",
+ "LUMP_BRUSH_SIDE"
+];
+
+const Q3_TABLE = [
+ "LUMP_ENTITIES",
+ "LUMP_TEXTURE",
+ "LUMP_PLANE",
+ "LUMP_NODES",
+ "LUMP_LEAVES",
+ "LUMP_LEAF_FACE_TABLE",
+ "LUMP_LEAF_BRUSH_TABLE",
+ "LUMP_MODEL",
+ "LUMP_BRUSH",
+ "LUMP_BRUSH_SIDE",
+ "LUMP_VERTEX",
+ "LUMP_MESH_VERTEX",
+ "LUMP_EFFECT",
+ "LUMP_FACE",
+ "LUMP_LIGHTMAP",
+ "LUMP_LIGHTVOL",
+ "LUMP_VISDATA",
+]
+
+var QBSPi3 = false
+var QBSPi2 = false
+
+## Central Function
+func convert_to_mesh(file, table : PackedStringArray = Q2_TABLE):
+ var bsp_bytes : PackedByteArray = FileAccess.get_file_as_bytes(file)
+ var bsp_version = str(convert_from_uint32(bsp_bytes.slice(4, 8)))
+ var magic_num = bsp_bytes.slice(0, 4).get_string_from_utf8()
+ QBSPi2 = bsp_version == "38"
+
+ prints("QBSPi2 Found BSP Version %s %s" % [magic_num, bsp_version])
+
+ if bsp_version == "46":
+ print("Quake 3 Magic num detected, switching to QBSPi3. yeah theres 3 now.")
+ QBSPi3 = true
+ table = Q3_TABLE
+
+ #return MeshInstance3D.new();
+
+
+ var directory : Dictionary = fetch_directory(bsp_bytes)
+ var lmp_table : Dictionary = {}
+
+
+ for entry in table:
+ var entry_key = table.find(entry)
+ lmp_table[entry] = range(directory[entry_key].get(LUMP_OFFSET), directory[entry_key].get(LUMP_OFFSET)+directory[entry_key].get(LUMP_LENGTH))
+
+ geometry = {}
+ textures = {}
+
+ var mi := MeshInstance3D.new()
+
+ process_entity_lmp(bytes(bsp_bytes, lmp_table.LUMP_ENTITIES))
+
+
+ if QBSPi3:
+ textures["lumps"] = get_texture_lmp(bytes(bsp_bytes, lmp_table.LUMP_TEXTURE))
+ geometry["vertex"] = get_verts(bytes(bsp_bytes, lmp_table.LUMP_VERTEX))
+ geometry["mesh_vertex"] = get_mesh_verts(bytes(bsp_bytes, lmp_table.LUMP_MESH_VERTEX))
+
+ OS.delay_msec(100) # some weird issue here, delaying seems to fix it
+ geometry["face"] = get_face_lump(bytes(bsp_bytes, lmp_table.LUMP_FACE))
+
+ lightmap_texture = get_lightmap_lump(bytes(bsp_bytes, lmp_table.LUMP_LIGHTMAP))
+ geometry["plane"] = get_planes(bytes(bsp_bytes, lmp_table.LUMP_PLANE))
+
+ geometry["brush_side"] = get_brush_sides(bytes(bsp_bytes, lmp_table.LUMP_BRUSH_SIDE))
+ geometry["brush"] = get_brushes(bytes(bsp_bytes, lmp_table.LUMP_BRUSH))
+
+
+
+ if QBSPi2:
+
+ models = get_models(bytes(bsp_bytes, lmp_table.LUMP_MODEL))
+
+ geometry["plane"] = get_planes(bytes(bsp_bytes, lmp_table.LUMP_PLANE))
+ geometry["vertex"] = get_verts(bytes(bsp_bytes, lmp_table.LUMP_VERTEX))
+ geometry["face"] = get_face_lump(bytes(bsp_bytes, lmp_table.LUMP_FACE))
+ geometry["edge"] = get_edges(bytes(bsp_bytes, lmp_table.LUMP_EDGE))
+ geometry["face_edge"] = get_face_edges(bytes(bsp_bytes, lmp_table.LUMP_FACE_EDGE))
+ geometry["brush"] = get_brushes(bytes(bsp_bytes, lmp_table.LUMP_BRUSH))
+ geometry["brush_side"] = get_brush_sides(bytes(bsp_bytes, lmp_table.LUMP_BRUSH_SIDE))
+ textures["lumps"] = get_texture_lmp(bytes(bsp_bytes, lmp_table.LUMP_TEXTURE))
+
+ process_to_mesh_array(geometry)
+
+ var mesh := create_mesh(geometry["face"])
+ var arm := ArrayMesh.new()
+
+ for surface in mesh.get_surface_count():
+ arm.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, mesh.surface_get_arrays(surface))
+ arm.surface_set_material(surface, mesh.surface_get_material(surface))
+ if (generate_lightmap_uv2):
+ arm.lightmap_unwrap(mi.global_transform, unit_scale * 4.0)
+ mi.mesh = arm
+
+ return mi
+
+func origin_to_vec(origin : String) -> Vector3:
+ var v = Vector3.ZERO
+ var pos = origin.split(" ")
+ var vec = Vector3(pos[0].to_int(), pos[1].to_int(), pos[2].to_int())
+ v = BSPReader.new().convert_vector_from_quake_unscaled(vec)
+ return v
+
+
+func get_lightmap_lump(data : PackedByteArray) -> Image:
+ var texture : Image = Image.create(1, 1, false, Image.FORMAT_RGB8)
+ if QBSPi3:
+ var count = data.size() / 49152
+ texture = Image.create(128 * count + 128, 128, false, Image.FORMAT_RGB8)
+ print(count, texture.get_size())
+ for i in range(0, count, 1):
+ for x in range(0, 128):
+ for y in range(0, 128):
+ var index : int = i * 49152 + y * (128 * 3) + x * 3
+ var r : int = data[index]
+ var g : int = data[index + 1]
+ var b : int = data[index + 2]
+ #prints(r, g, b)
+
+ texture.set_pixel(x + (i * 128), y, Color(r, g, b) / 255.0)
+ #texture.save_png("user://lightmap_data.png")
+ #output.append(ImageTexture.create_from_image(texture))
+ return texture
+
+## takes the vertex, face, edge and face edge arrays and outputs an array of all the edge points.
+func process_to_mesh_array(geometry : Dictionary) -> void:
+ var output_verts = []
+ var face_vertex_indices = []
+
+ var verts = geometry.get("vertex")
+ var edges = geometry.get("edge")
+ var face_edges = geometry.get("face_edge")
+
+ for face_index in geometry.get("face"):
+ var face = face_index as BSPFace
+ var first_edge = face.edge_list_id
+ var num_edges = face.num_edges
+
+ var edge_range = range(first_edge, first_edge + num_edges)
+
+ var face_vert_list = []
+ var face_vert_out = []
+
+ for edge in edge_range:
+
+ var face_edge = face_edges[edge]
+
+ edge = edges[abs(face_edge)]
+
+ var edge0 = edge[0]
+ var edge1 = edge[1]
+
+ if face_edge > 0:
+ edge0 = edge[0]
+ edge1 = edge[1]
+
+ if face_edge < 0:
+ edge0 = edge[1]
+ edge1 = edge[0]
+
+ var vert0 = verts[edge0]
+ var vert1 = verts[edge1]
+
+ face_vert_list.append_array([vert0, vert1])
+
+
+ for v in range(0, face_vert_list.size()-2):
+
+ var vert0 = face_vert_list[0]
+ var vert1 = face_vert_list[v + 1]
+ var vert2 = face_vert_list[v + 2]
+
+ face_vert_out.append(vert0)
+ face_vert_out.append(vert1)
+ face_vert_out.append(vert2)
+
+ face.verts = face_vert_out
+
+func process_entity_lmp(ent_bytes : PackedByteArray) -> void:
+ prints("a unicode passing error may accur, this is 'normal'.")
+ var entity_string : String = ent_bytes.get_string_from_utf8()
+ var entity_output = parse_entity_string(entity_string)
+ var parsed = convert_entity_dict_to_scene(entity_output)
+
+
+## grabs the directory
+func fetch_directory(bsp_bytes):
+ prints("QBSPi2 BSP File Size:", bsp_bytes.size())
+ var i = 0
+ var dir = {}
+ var dir_lump = bytes( bsp_bytes, range(8, ( 19 * 8 ) ))
+
+ for lump in range(0, dir_lump.size()-8, 8):
+
+ var offset = bytes(dir_lump, range(lump+0, lump+4)).decode_u32(0)
+ var length = bytes(dir_lump, range(lump+4, lump+8)).decode_u32(0)
+
+ dir[lump / 8] = {LUMP_OFFSET: offset, LUMP_LENGTH: length}
+
+
+ return dir
+
+func get_planes(plane_bytes : PackedByteArray) -> Array[BSPPlane]:
+ var planes : Array[BSPPlane] = []
+
+ # basically
+
+ if QBSPi3:
+
+ var count = plane_bytes.size() / 16
+ print("QBSPi3 Calculated Estimate of %s Planes." % count)
+ for index in range(0, plane_bytes.size(), 16):
+ var norm_x = bytes(plane_bytes, range(index + 0, index + 4)).decode_float(0)
+ var norm_y = bytes(plane_bytes, range(index + 4, index + 8)).decode_float(0)
+ var norm_z = bytes(plane_bytes, range(index + 8, index + 12)).decode_float(0)
+
+ var distance = bytes(plane_bytes, range(index + 12, index + 16)).decode_float(0)
+
+ var plane = BSPPlane.new()
+ plane.normal = convert_vector_from_quake_unscaled(Vector3(norm_x, norm_y, norm_z))
+ plane.distance = distance
+
+ planes.append(plane)
+
+ if QBSPi2:
+ var count = plane_bytes.size() / 20
+ print("QBSPi2 Calculated Estimate of %s Planes." % count)
+ for index in range(0, plane_bytes.size(), 20):
+ var norm_x = bytes(plane_bytes, range(index + 0, index + 4)).decode_float(0)
+ var norm_y = bytes(plane_bytes, range(index + 4, index + 8)).decode_float(0)
+ var norm_z = bytes(plane_bytes, range(index + 8, index + 12)).decode_float(0)
+
+ var distance = bytes(plane_bytes, range(index + 12, index + 16)).decode_float(0)
+
+ var type = bytes(plane_bytes, range(index + 16, index + 20)).decode_u32(0)
+
+ var plane = BSPPlane.new()
+ plane.normal = convert_vector_from_quake_unscaled(Vector3(norm_x, norm_y, norm_z))
+ plane.distance = distance
+ plane.type = type
+ planes.append(plane)
+ return planes
+
+
+func get_brushes(brush_bytes : PackedByteArray):
+ var count = brush_bytes.size() / 12
+ print("QBSPi2 Calculated Estimate of %s Brushes" % count)
+ var brushes = []
+
+ for index in range(0, brush_bytes.size(), 12):
+ var brush = BSPBrush.new()
+ var first_brush_side = bytes(brush_bytes, range(index + 0, index + 4)).decode_u32(0)
+ var num_brush_side = bytes(brush_bytes, range(index + 4, index + 8)).decode_u32(0)
+ var flags = bytes(brush_bytes, range(index + 8, index + 10)).decode_u16(0)
+
+ if QBSPi3:
+ first_brush_side = bytes(brush_bytes, range(index + 0, index + 4)).decode_s32(0) # Quake 3 moved to s32 for everything by the looks of it, accounting for it here
+ num_brush_side = bytes(brush_bytes, range(index + 4, index + 8)).decode_s32(0)
+ flags = bytes(brush_bytes, range(index + 8, index + 12)).decode_s32(0) # seems to be responsible for texture path in quake 3.
+ #prints("brush flags:", flags, textures["lumps"][flags].texture_path)
+
+
+ brush.first_brush_side = first_brush_side
+ brush.num_brush_side = num_brush_side
+ brush.flags = flags
+
+
+ brushes.append(brush)
+ return brushes
+
+func get_brush_sides(brush_side_bytes : PackedByteArray):
+ var count = brush_side_bytes.size() / 4
+ print("QBSPi2 Calculated Estimate of %s Brush Sides" % count)
+ var brush_sides = []
+ for index in range(0, brush_side_bytes.size(), 8 if QBSPi3 else 4):
+
+ var plane_index = bytes(brush_side_bytes, range(index + 0, index + 2)).decode_u16(0)
+ var texture_information = bytes(brush_side_bytes, range(index + 2, index + 4)).decode_s16(0)
+
+ if QBSPi3:
+ plane_index = bytes(brush_side_bytes, range(index + 0, index + 4)).decode_u32(0)
+ texture_information = bytes(brush_side_bytes, range(index + 4, index + 8)).decode_s32(0)
+
+
+ var brush_side = BSPBrushSide.new()
+
+ brush_side.plane_index = plane_index
+ brush_side.texture_information = texture_information
+
+ brush_sides.append(brush_side)
+ return brush_sides
+
+func get_mesh_verts(vert_bytes : PackedByteArray) -> PackedInt64Array:
+ var vertex_array : PackedInt64Array = []
+
+ if QBSPi3:
+ var count = vert_bytes.size() / 4
+ for i in range(0, vert_bytes.size(), 4):
+ var vert = bytes( vert_bytes, range(i, i + 4) ).decode_s32(0)
+ vertex_array.append(vert)
+
+ return vertex_array
+
+## returns vertex lump
+func get_verts(vert_bytes : PackedByteArray) -> PackedVector3Array:
+ var vertex_array : PackedVector3Array = []
+ #return vertex_array
+ if QBSPi3:
+ geometry["vertex_uv_q3"] = []
+ geometry["vertex_uv2_q3"] = []
+ geometry["normal"] = []
+ geometry["color"] = []
+ #return vertex_array
+ var count = vert_bytes.size() / 44
+ print("QBSPi3 Calculated Estimate of %s Vertices, THIS MAY TAKE A WHILE" % count)
+
+ var v = 0
+
+ while v < count:
+ var index = (v * 44)
+ var xbytes = bytes(vert_bytes, range( index + 0, index + 4 )).decode_float(0)
+ var ybytes = bytes(vert_bytes, range( index + 4, index + 8 )).decode_float(0)
+ var zbytes = bytes(vert_bytes, range( index + 8, index + 12 )).decode_float(0)
+ var vertex_vec = convert_vector_from_quake_unscaled(Vector3(xbytes, ybytes, zbytes))
+
+ var u1 = (bytes(vert_bytes, range( index + 12, index + 16 )).decode_float(0))
+ var v1 = (bytes(vert_bytes, range( index + 16, index + 20 )).decode_float(0))
+ var u2 = bytes(vert_bytes, range( index + 20, index + 24 )).decode_float(0)
+ var v2 = bytes(vert_bytes, range( index + 24, index + 28 )).decode_float(0)
+
+ var nx = bytes(vert_bytes, range( index + 28, index + 32 )).decode_float(0)
+ var ny = bytes(vert_bytes, range( index + 32, index + 36)).decode_float(0)
+ var nz = bytes(vert_bytes, range( index + 36, index + 40)).decode_float(0)
+ var normal_vec = convert_vector_from_quake_unscaled(Vector3(xbytes, ybytes, zbytes))
+
+ var CR = bytes(vert_bytes, range( index + 40, index + 41)).decode_u8(0)
+ var CG = bytes(vert_bytes, range( index + 41, index + 42)).decode_u8(0)
+ var CB = bytes(vert_bytes, range( index + 42, index + 43)).decode_u8(0)
+ var CA = bytes(vert_bytes, range( index + 43, index + 44)).decode_u8(0)
+ var color = Color(CR / 255.0, CG / 255.0, CB / 255.0, CA / 255.0)
+
+
+ geometry["vertex_uv_q3"].append(Vector2(u1, v1))
+ geometry["vertex_uv2_q3"].append(Vector2(u2, v2))
+ geometry["color"].append(color)
+ geometry["normal"].append(normal_vec)
+
+ vertex_array.append(vertex_vec)
+
+ v += 1
+
+ prints("QBPSi3 Vert construction complete", vertex_array.size())
+
+
+ if QBSPi2:
+ var count = vert_bytes.size() / 12
+
+ print("QBSPi2 Calculated Estimate of %s Vertices" % count)
+
+ var v = 0
+ while v < count:
+
+ var xbytes = bytes(vert_bytes, range( (v * 12) + 0, (v * 12) + 4 )).decode_float(0)
+ var ybytes = bytes(vert_bytes, range( (v * 12) + 4, (v * 12) + 8 )).decode_float(0)
+ var zbytes = bytes(vert_bytes, range( (v * 12) + 8, (v * 12) + 12 )).decode_float(0)
+
+ var vec = convert_vector_from_quake_unscaled(Vector3(xbytes, ybytes, zbytes))
+ vertex_array.append(vec)
+ v += 1
+ return vertex_array
+
+## returns face lump
+func get_face_lump(lump_bytes : PackedByteArray):
+ var faces : Array[BSPFace] = []
+ #prints("geometry", geometry)
+
+ if QBSPi3:
+ var count = lump_bytes.size() / 104
+ var f = 0
+ while f < count:
+ var new_face := BSPFace.new()
+ var base_index = f * 104
+ var by = bytes(lump_bytes, range(base_index, base_index + 104))
+
+ var texture = by.decode_s32(0)
+ var effect = by.decode_s32(4)
+ var type = by.decode_s32(8)
+
+ var first_vert = by.decode_s32(12)
+ var num_verts = by.decode_s32(16)
+
+ var first_mesh_vert = by.decode_s32(20)
+ var num_mesh_verts = by.decode_s32(24)
+
+ var lightmap_index = by.decode_s32(28)
+
+ var lightmap_stx = by.decode_s32(32)
+ var lightmap_sty = by.decode_s32(36)
+
+ var lightmap_six = by.decode_s32(40)
+ var lightmap_siy = by.decode_s32(44)
+
+ var lightmap_start = Vector2(lightmap_stx, lightmap_sty)
+ var lightmap_size = Vector2(lightmap_six, lightmap_siy)
+
+
+ var vert_range = range(first_vert, first_vert + num_verts)
+ var mesh_vert_range = range(first_mesh_vert, first_mesh_vert + num_mesh_verts)
+
+ var fnx = by.decode_float(88)
+ var fny = by.decode_float(92)
+ var fnz = by.decode_float(96)
+ var face_normal = convert_vector_from_quake_unscaled(Vector3(fnx, fny, fnz))
+
+ var out_verts : PackedVector3Array = []
+ var out_uv = []
+ var out_uv2 = []
+ var temp_uv = []
+ var temp_uv2 = []
+ var polygon_verts : PackedVector3Array = []
+ var mesh_verts = []
+
+ for j in mesh_vert_range:
+ mesh_verts.append(geometry["mesh_vertex"][j])
+ match type:
+ 1: # Polygon face
+ for i in vert_range:
+ polygon_verts.append(geometry["vertex"][i])
+ temp_uv.append(geometry["vertex_uv_q3"][i])
+ temp_uv2.append(geometry["vertex_uv2_q3"][i])
+
+ for v in mesh_verts:
+ out_verts.append(polygon_verts[v])
+ out_uv.append(temp_uv[v])
+ out_uv2.append(temp_uv2[v])
+
+ new_face.lightmap = lightmap_index
+ new_face.lightmap_start = lightmap_start
+ new_face.lightmap_size = lightmap_size
+ new_face.texinfo_id = texture
+ new_face.verts = out_verts
+ new_face.face_normal = face_normal
+ new_face.q3_uv = out_uv
+ new_face.q3_uv2 = out_uv
+ faces.append(new_face)
+ f += 1
+
+ if QBSPi2:
+ var count = lump_bytes.size() / 20
+ prints("QBSPi2 Calculated Estimate of %s Faces" % count)
+ var f = 0
+
+
+ while f < count:
+ var new_face := BSPFace.new()
+ var base_index = f * 20
+
+ var by = bytes(lump_bytes, range(base_index, base_index + 20))
+
+ new_face.plane_id = by.decode_u16(0)
+ new_face.plane_side = by.decode_u16(2)
+ new_face.edge_list_id = by.decode_u32(4)
+ new_face.num_edges = by.decode_u16(8)
+ new_face.texinfo_id = by.decode_u16(10)
+
+ faces.append(new_face)
+ f += 1
+
+ return faces
+
+
+
+## returns texture lump
+func get_texture_lmp(tex_bytes : PackedByteArray) -> Array:
+
+ var output = []
+
+ if QBSPi3:
+ var count = float(tex_bytes.size()) / 72.0
+ prints("QBSPi2 Calculated Estimate of %s Texture References" % count)
+ for b in range(0, tex_bytes.size(), 72):
+ var BSPTI := BSPTextureInfo.new()
+ var texture_name = bytes(tex_bytes, range(b, b + 64)).get_string_from_ascii()
+ BSPTI.texture_path = texture_name
+ BSPTI.flags = bytes(tex_bytes, range(b + 64, b + 68)).decode_s32(0)
+ #V not integrated V
+ #BSPTI.contents = bytes(tex_bytes, range(b + 68, b + 72)).decode_s32(0)
+ #^ not integrated ^
+
+ output.append(BSPTI)
+
+ if QBSPi2:
+ var count = tex_bytes.size() / 76
+ prints("QBSPi2 Calculated Estimate of %s Texture References" % count)
+
+
+ for b in range(0, tex_bytes.size(), 76):
+ var BSPTI := BSPTextureInfo.new()
+
+ var ux = bytes(tex_bytes, range(b, b + 4)).decode_float(0)
+ var uy = bytes(tex_bytes, range(b + 4, b + 8)).decode_float(0)
+ var uz = bytes(tex_bytes, range(b + 8, b + 12)).decode_float(0)
+
+ var uoffset = bytes(tex_bytes, range(b + 12, b + 16)).decode_float(0)
+
+ var vx = bytes(tex_bytes, range(b + 16, b + 20)).decode_float(0)
+ var vy = bytes(tex_bytes, range(b + 20, b + 24)).decode_float(0)
+ var vz = bytes(tex_bytes, range(b + 24, b + 28)).decode_float(0)
+
+ var voffset = bytes(tex_bytes, range(b + 28, b + 32)).decode_float(0)
+
+ var flags = bytes(tex_bytes, range(b + 32, b + 36)).decode_u32(0)
+ var value = bytes(tex_bytes, range(b + 36, b + 40)).decode_u32(0)
+
+ var texture_path = bytes(tex_bytes, range(b + 40, b + 72)).get_string_from_utf8()
+
+ var next_texinfo = bytes(tex_bytes, range(b + 72, b + 76)).decode_s32(0)
+
+ BSPTI.vec_s = convert_vector_from_quake_unscaled(Vector3(ux, uy, uz))
+ BSPTI.offset_s = uoffset
+ BSPTI.vec_t = convert_vector_from_quake_unscaled(Vector3(vx, vy, vz))
+ BSPTI.offset_t = voffset
+ BSPTI.flags = flags
+ BSPTI.value = value
+ BSPTI.texture_path = texture_path
+
+ output.append(BSPTI)
+
+
+ return output
+
+## returns edge lump
+func get_edges(edge_bytes : PackedByteArray):
+ var count = edge_bytes.size() / 4
+ var e = 0
+ var edges = []
+ while e < count:
+ var index = e * 4
+ var edge_1 = bytes(edge_bytes, range(index + 0, index + 2)).decode_u16(0)
+ var edge_2 = bytes(edge_bytes, range(index + 2, index + 4)).decode_u16(0)
+
+
+ edges.append([edge_1, edge_2])
+ e += 1
+
+ return edges
+
+## returns face edge lump
+func get_face_edges(face_bytes : PackedByteArray):
+ var count = face_bytes.size() / 4
+ prints("QBSPi2 Calculated Estimate of %s Face Edges" % count)
+ var f = 0
+ var face_edges = []
+ while f < count:
+ var index = f * 4
+ var f1 = bytes(face_bytes, range(index + 0, index + 4)).decode_s32(0)
+ face_edges.append(f1)
+ f += 1
+
+ return face_edges
+## i dont know what models are used for but if someone could tell me that would be good.
+func get_models(model_bytes : PackedByteArray):
+ var count = model_bytes.size() / 48
+ prints("QBSPi2 Calculated Estimate of %s Models" % count)
+
+ for m in range(0, model_bytes.size(), 48):
+ var a1 = bytes(model_bytes, range(m + 0, m + 4)).decode_float(0)
+ var a2 = bytes(model_bytes, range(m + 4, m + 8)).decode_float(0)
+ var b1 = bytes(model_bytes, range(m + 8, m + 12)).decode_float(0)
+ var b2 = bytes(model_bytes, range(m + 12, m + 16)).decode_float(0)
+ var c1 = bytes(model_bytes, range(m + 16, m + 20)).decode_float(0)
+ var c2 = bytes(model_bytes, range(m + 20, m + 24)).decode_float(0)
+
+ var ox = bytes(model_bytes, range(m + 24, m + 28)).decode_float(0)
+ var oy = bytes(model_bytes, range(m + 28, m + 32)).decode_float(0)
+ var oz = bytes(model_bytes, range(m + 32, m + 36)).decode_float(0)
+
+ var head = bytes(model_bytes, range(m + 36, m + 40)).decode_s32(0)
+
+ var first_face = bytes(model_bytes, range(m + 40, m + 44)).decode_u32(0)
+ var num_faces = bytes(model_bytes, range(m + 44, m + 48)).decode_u32(0)
+
+ return []
+
+func create_collisions():
+ var collisions = []
+ var final_verts = []
+ if geometry.has("brush"):
+ for brush in geometry["brush"]:
+ var brush_planes : Array[Plane] = []
+ brush = brush as BSPBrush
+ var brush_side_range = range(brush.first_brush_side, (brush.first_brush_side + brush.num_brush_side))
+ var q3_compliant : bool = false
+
+ if QBSPi3:
+ var file_name = str(textures.lumps[brush.flags].texture_path).get_file()
+ q3_compliant = !ignored_flags.has(brush.flags)
+
+
+ if (QBSPi2 && brush.flags == 1) or q3_compliant:
+ for brush_side_index in brush_side_range:
+ var brush_side = geometry["brush_side"][brush_side_index]
+ var plane = geometry["plane"][brush_side.plane_index] as BSPPlane
+
+ var plane_vec = Plane(plane.normal, plane.distance * unit_scale)
+
+ brush_planes.append(plane_vec)
+
+ var verts = Geometry3D.compute_convex_mesh_points(brush_planes)
+ var collision = ConvexPolygonShape3D.new()
+
+ collision.set_points(verts)
+ collisions.append(collision)
+
+ return collisions
+
+func convert_face_uv2_for_lightmap(lightmap_index : int, lm_start : Vector2i, lm_size : Vector2i, lightmap_uv : Vector2) -> Vector2:
+ var atlas_size = Vector2(lightmap_texture.get_size()) # Size of the entire atlas
+ var lightmap_offset_in_atlas = Vector2i(lightmap_index * 128, 0)
+ var absolute_lm_start = Vector2(lightmap_offset_in_atlas) + Vector2(lm_start)
+ var uv_offset_in_lightmap = Vector2(lightmap_uv) * Vector2(lm_size)
+ var absolute_uv = Vector2(absolute_lm_start) + Vector2(uv_offset_in_lightmap)
+ var normalized_uv = Vector2(absolute_uv) / Vector2(atlas_size)
+ return normalized_uv
+
+
+func create_mesh(face_data : Array[BSPFace]) -> Mesh:
+ var mesh = ArrayMesh.new()
+ var texture_list = textures["lumps"] if textures.has("lumps") else []
+ var surface_list := {}
+ var material_info_lookup := {}
+ var missing_textures := []
+ var mesh_arrays := []
+ mesh_arrays.resize(Mesh.ARRAY_MAX)
+
+ # seperating them for reasons
+ if QBSPi3:
+ for texture in texture_list:
+ texture = texture as BSPTextureInfo
+
+ if not surface_list.has(texture.texture_path):
+ var st = SurfaceTool.new()
+ #prints("creating new tool for", texture.texture_path)
+ surface_list[texture.texture_path] = st
+ st.begin(Mesh.PRIMITIVE_TRIANGLES)
+
+ for face in face_data:
+ var texture : BSPTextureInfo = texture_list[face.texinfo_id]
+ var ignore_surface := ignored_flags.has(texture.flags) # Can probably get rid of this once all the normal skipping flags are added
+ if (texture.flags & (SURFACE_FLAG_NODRAW | SURFACE_FLAG_HINT | SURFACE_FLAG_SKIP)):
+ ignore_surface = true
+ if (!include_sky_surfaces && (texture.flags & SURFACE_FLAG_SKY)):
+ ignore_surface = true
+ if surface_list.has(texture.texture_path) and !ignore_surface:
+ var surface_tool : SurfaceTool = surface_list.get(texture.texture_path)
+ var material_info : MaterialInfo = material_info_lookup.get(surface_tool, null)
+ if (!material_info):
+ material_info = load_or_create_material(texture.texture_path)
+ material_info_lookup[surface_tool] = material_info
+ var material : StandardMaterial3D = material_info.material
+ var width := material_info.width
+ var height := material_info.height
+ var verts = face.verts
+
+ var tex_size_vec = Vector2(material_info.width, material_info.height)
+ for vertIndex in range(0, verts.size(), 3):
+ var v0 = verts[vertIndex + 0]
+ var v1 = verts[vertIndex + 1]
+ var v2 = verts[vertIndex + 2]
+
+ var uv0 : Vector2 = face.q3_uv[vertIndex + 0]
+ var uv1 : Vector2 = face.q3_uv[vertIndex + 1]
+ var uv2 : Vector2 = face.q3_uv[vertIndex + 2]
+
+ var lm_uv0 = convert_face_uv2_for_lightmap(face.lightmap, face.lightmap_start, face.lightmap_size, face.q3_uv2[vertIndex + 0])
+ var lm_uv1 = convert_face_uv2_for_lightmap(face.lightmap, face.lightmap_start, face.lightmap_size, face.q3_uv2[vertIndex + 1])
+ var lm_uv2 = convert_face_uv2_for_lightmap(face.lightmap, face.lightmap_start, face.lightmap_size, face.q3_uv2[vertIndex + 2])
+
+ surface_tool.set_material(material)
+ surface_tool.set_normal(face.face_normal)
+ surface_tool.set_uv(uv0)
+ surface_tool.set_uv2(lm_uv0)
+ surface_tool.add_vertex(v0 * unit_scale)
+ surface_tool.set_uv(uv1)
+ surface_tool.set_uv2(lm_uv1)
+ surface_tool.add_vertex(v1 * unit_scale)
+ surface_tool.set_uv(uv2)
+ surface_tool.set_uv2(lm_uv2)
+ surface_tool.add_vertex(v2 * unit_scale)
+
+ if QBSPi2:
+ for texture in texture_list:
+ texture = texture as BSPTextureInfo
+
+ if not surface_list.has(texture.texture_path):
+ var st = SurfaceTool.new()
+ surface_list[texture.texture_path] = st
+ st.begin(Mesh.PRIMITIVE_TRIANGLES)
+
+ for face in face_data:
+ var texture : BSPTextureInfo = texture_list[face.texinfo_id]
+
+ if surface_list.has(texture.texture_path):
+ var surface_tool : SurfaceTool = surface_list.get(texture.texture_path)
+ var material_info : MaterialInfo = material_info_lookup.get(surface_tool, null)
+ if (!material_info):
+ material_info = load_or_create_material(texture.texture_path)
+ material_info_lookup[surface_tool] = material_info
+ var material := material_info.material
+ var width := material_info.width
+ var height := material_info.height
+ var verts : PackedVector3Array = face.verts
+ var ignore_surface := ignored_flags.has(texture.flags) # Can probably get rid of this once all the normal skipping flags are added
+ if (texture.flags & (SURFACE_FLAG_NODRAW | SURFACE_FLAG_HINT | SURFACE_FLAG_SKIP)):
+ ignore_surface = true
+ if (!include_sky_surfaces && (texture.flags & SURFACE_FLAG_SKY)):
+ ignore_surface = true
+ if (!ignore_surface):
+ for vertIndex in range(0, verts.size(), 3):
+ var v0 = verts[vertIndex + 0]
+ var v1 = verts[vertIndex + 1]
+ var v2 = verts[vertIndex + 2]
+
+ var uv0 = get_uv_q(v0, texture, width, height)
+ var uv1 = get_uv_q(v1, texture, width, height)
+ var uv2 = get_uv_q(v2, texture, width, height)
+
+ #var plane = geometry["plane"][face.plane_id] as BSPPlane
+ var normal : Vector3 = (v1 - v0).cross((v0 - v2))#FIXME: planes dont work for quake 2 for some reason, vector calculated by cross product
+ #var normal : Vector3 = plane.normal
+
+ surface_tool.set_material(material)
+ surface_tool.set_normal(normal.normalized())
+ surface_tool.set_uv(uv0)
+ surface_tool.add_vertex(v0 * unit_scale)
+ surface_tool.set_uv(uv1)
+ surface_tool.add_vertex(v1 * unit_scale)
+ surface_tool.set_uv(uv2)
+ surface_tool.add_vertex(v2 * unit_scale)
+
+ for tool in surface_list.values():
+ tool = tool as SurfaceTool
+ mesh = tool.commit(mesh) as ArrayMesh
+ prints("\n\n\n QBSPi2 - Completed Mesh With %s Surfaces" % mesh.get_surface_count())
+ if missing_textures.size() > 0: prints(".\nMissing Textures:", missing_textures, "Some Faces may be invisible, Trust me they're there the surface albedo is just 0!")
+ return mesh
+
+
+func get_uv_q(vertex : Vector3, tex_info : BSPTextureInfo, width : float, height : float) -> Vector2:
+ var u := (vertex.dot(tex_info.vec_s) + tex_info.offset_s) / width
+ var v := (vertex.dot(tex_info.vec_t) + tex_info.offset_t) / height
+ return Vector2(u, v)
+
+
+## converts 2 bytes to a unsigned int16
+func convert_from_uint16(uint16):
+ var uint16_value = uint16.decode_u16(0)
+ if uint16.size() < 4: return 0
+ return uint16_value
+
+
+## converts 4 bytes to a unsigned int32
+func convert_from_uint32(uint32 : PackedByteArray):
+ var uint32_value = uint32.decode_u32(0)
+ if uint32.size() < 4: return 0
+ return uint32_value
+
+
+## Non-zero values are true, as do "t" and "y" for "true" and "yes".
+static func convert_string_to_bool(string : String) -> bool:
+ if (string.length() == 0):
+ return false
+ if (string.to_int() != 0):
+ return true
+ var first_character := string[0].to_lower()
+ if (first_character == 't' || first_character == 'y'):
+ return true
+ return false
+
+
+## returns bytes, indices should be an array e.g. [1, 2, 3, 4]
+# TODO: Unoptimal, use slice() directly instead.
+func bytes(input_array : PackedByteArray, indices : Array) -> PackedByteArray:
+ if (indices.size() > 0):
+ return input_array.slice(indices[0], indices[indices.size() - 1] + 1)
+ else:
+ return []
diff --git a/3d/first_person_shooter/addons/bsp_importer/bsp_reader.gd.uid b/3d/first_person_shooter/addons/bsp_importer/bsp_reader.gd.uid
new file mode 100644
index 00000000000..3b78bea516d
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/bsp_reader.gd.uid
@@ -0,0 +1 @@
+uid://ve2rehy8u3ww
diff --git a/3d/first_person_shooter/addons/bsp_importer/clipper.gd b/3d/first_person_shooter/addons/bsp_importer/clipper.gd
new file mode 100644
index 00000000000..615e69b7e2b
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/clipper.gd
@@ -0,0 +1,193 @@
+extends RefCounted
+class_name BspClipper
+
+# from https://github.com/gongpha/gdQmapbsp/blob/master/addons/qmapbsp/util/clipper.gd
+# Only necessary if you're using Godot 4.1 or older and don't have access to the
+# Geometry3D.compute_convex_mesh_points function.
+
+# from wootguy's bspguy
+# 670fca408b7d376b28da97daa323aade2ea649d7 src/editor/Clipper.cpp
+
+const TESTMAX := 5555
+const EPS := 0.000001
+
+var vertices : PackedVector3Array
+var edges : Array[Vector4i] # [v0, v1, f0, f1]...
+var faces : Array[Array] # [edge_ids : PIA32, normal : Vector3]...
+
+var verts_v : PackedByteArray
+var edges_v : PackedByteArray
+var faces_v : PackedByteArray
+
+var verts_o : PackedInt32Array
+
+func clip_plane(p : Plane) -> bool :
+ p.normal *= -1
+ p.d *= -1
+ var res := clip_vertices(p)
+ if res == -1 : return true
+ if res == 1 : return false
+ clip_edges(p)
+ clip_faces(p)
+ return false
+
+func clip_planes(planes : Array[Plane]) -> void :
+ for p in planes :
+ if clip_plane(p) : break
+ filter_and_clean()
+
+func filter_and_clean() -> void :
+ var vvv : PackedVector3Array
+ for i in faces.size() :
+ if !faces_v[i] : continue
+ for j in faces[i][0] :
+ var edge : Vector4i = edges[j]
+ if verts_v[edge.x] : vvv.append(vertices[edge.x])
+ if verts_v[edge.y] : vvv.append(vertices[edge.y])
+
+ vertices = vvv
+
+ verts_v.clear()
+ edges_v.clear()
+ faces_v.clear()
+ verts_o.clear()
+
+func clip_vertices(plane : Plane) -> int :
+ var pos := 0
+ var neg := 0
+ for i in vertices.size() :
+ if verts_v[i] == 0 : continue
+
+ var dist := plane.distance_to(vertices[i])
+
+ if dist >= EPS : pos += 1
+ elif dist < EPS :
+ neg += 1
+ verts_v[i] = 0
+ if neg == 0 : return 1
+ if pos == 0 : return -1
+ return 0
+
+func clip_edges(plane : Plane) -> void :
+ for i in edges.size() :
+ var e : Vector4i = edges[i]
+ var v0 := e[0]
+ var v1 := e[1]
+
+ if edges_v[i] :
+ var d0 := plane.distance_to(vertices[v0])
+ var d1 := plane.distance_to(vertices[v1])
+
+ if d0 <= 0 and d1 <= 0 :
+ for k in 2 :
+ var face : Array = faces[e[2 + k]]
+ var f : int = face[0].find(i)
+ if f != -1 :
+ face[0].remove_at(f)
+ if face[0].is_empty() :
+ faces_v[e[2 + k]] = 0
+ edges_v[i] = 0
+ continue
+ if d0 >= 0 and d1 >= 0 :
+ continue
+ var t := d0 / (d0 - d1)
+ var v := vertices[v0].lerp(vertices[v1], t)
+ vertices.append(v)
+ verts_v.append(1)
+ verts_o.append(0)
+ if d0 > 0 :
+ e[1] = vertices.size() - 1
+ else :
+ e[0] = vertices.size() - 1
+ edges[i] = e
+
+func clip_faces(plane : Plane) -> void :
+ var closef := [PackedInt32Array(), plane.normal * -1]
+ var fsize := faces.size()
+ for i in fsize :
+ if faces_v[i] == 1 :
+ var face : Array = faces[i]
+ for j in face[0].size() :
+ var edge : Vector4i = edges[face[0][j]]
+ verts_o[edge[0]] = 0
+ verts_o[edge[1]] = 0
+ var ref := PackedInt32Array([-1, -1])
+
+ if get_open_polyline(face, ref) :
+ var nedge := Vector4i(ref[0], ref[1], i, fsize)
+ edges.append(nedge)
+ edges_v.append(1)
+ face[0].append(edges.size() - 1)
+ closef[0].append(edges.size() - 1)
+ faces.append(closef)
+ faces_v.append(1)
+
+func get_open_polyline(face : Array, ref : PackedInt32Array) -> bool :
+ for i in face[0].size() :
+ var edge : Vector4i = edges[face[0][i]]
+ verts_o[edge[0]] += 1
+ verts_o[edge[1]] += 1
+ for i in face[0].size() :
+ var edge : Vector4i = edges[face[0][i]]
+ var v0 := edge[0]
+ var v1 := edge[1]
+ if verts_o[v0] == 1 :
+ if ref[0] == -1 :
+ ref[0] = v0
+ elif ref[1] == -1 :
+ ref[1] = v0
+ if verts_o[v1] == 1 :
+ if ref[0] == -1 :
+ ref[0] = v1
+ elif ref[1] == -1 :
+ ref[1] = v1
+ return ref[0] != -1 and ref[1] != -1
+
+func begin(bound := AABB(
+ -Vector3(TESTMAX, TESTMAX, TESTMAX),
+ Vector3(TESTMAX, TESTMAX, TESTMAX) * 2.0,
+)) -> void :
+ vertices = [
+ bound.position,
+ Vector3(bound.end.x, bound.position.y, bound.position.z),
+ Vector3(bound.end.x, bound.end.y, bound.position.z),
+ Vector3(bound.position.x, bound.end.y, bound.position.z),
+
+ Vector3(bound.position.x, bound.position.y, bound.end.z),
+ Vector3(bound.end.x, bound.position.y, bound.end.z),
+ bound.end,
+ Vector3(bound.position.x, bound.end.y, bound.end.z),
+ ]
+ verts_v.resize(8)
+ verts_v.fill(1)
+ verts_o.resize(8)
+ verts_o.fill(0.0)
+
+ edges = [
+ Vector4i(0, 1, 0, 5),
+ Vector4i(0, 4, 0, 2),
+ Vector4i(4, 5, 0, 4),
+ Vector4i(5, 1, 0, 3),
+
+ Vector4i(3, 2, 1, 5),
+ Vector4i(3, 7, 1, 2),
+ Vector4i(6, 7, 1, 4),
+ Vector4i(2, 6, 1, 3),
+
+ Vector4i(0, 3, 2, 5),
+ Vector4i(4, 7, 2, 4),
+ Vector4i(1, 2, 3, 5),
+ Vector4i(5, 6, 3, 4)
+ ]
+ edges_v.resize(12)
+ edges_v.fill(1)
+ faces = [
+ [PackedInt32Array([0, 1, 2, 3]), Vector3( 0, -1, 0)],
+ [PackedInt32Array([4, 5, 6, 7]), Vector3( 0, 1, 0)],
+ [PackedInt32Array([1, 5, 8, 9]), Vector3(-1, 0, 0)],
+ [PackedInt32Array([3, 7, 10, 11]), Vector3( 1, 0, 0)],
+ [PackedInt32Array([2, 6, 9, 11]), Vector3( 0, 0, 1)],
+ [PackedInt32Array([0, 4, 8, 10]), Vector3( 0, 0, -1)]
+ ]
+ faces_v.resize(6)
+ faces_v.fill(1)
diff --git a/3d/first_person_shooter/addons/bsp_importer/clipper.gd.uid b/3d/first_person_shooter/addons/bsp_importer/clipper.gd.uid
new file mode 100644
index 00000000000..5208fc880ba
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/clipper.gd.uid
@@ -0,0 +1 @@
+uid://d12qhl3vubogs
diff --git a/3d/first_person_shooter/addons/bsp_importer/examples/lava_example_template.tscn b/3d/first_person_shooter/addons/bsp_importer/examples/lava_example_template.tscn
new file mode 100644
index 00000000000..d1003f36722
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/examples/lava_example_template.tscn
@@ -0,0 +1,19 @@
+[gd_scene format=3 uid="uid://bq7hi3koeh0ua"]
+
+[node name="LavaExampleTemplate" type="Area3D"]
+gravity_space_override = 3
+gravity = 0.0
+linear_damp_space_override = 3
+linear_damp = 11.464
+angular_damp_space_override = 3
+angular_damp = 7.676
+
+[node name="make your own lava template with a script" type="Node3D" parent="."]
+
+[node name="for entering the area or whatever you need" type="Node3D" parent="."]
+
+[node name="for your game, specifically and set it in the" type="Node3D" parent="."]
+
+[node name="bsp import options" type="Node3D" parent="."]
+
+[node name="Collision shapes will be added as children" type="Node3D" parent="."]
diff --git a/3d/first_person_shooter/addons/bsp_importer/examples/preset_example.tres b/3d/first_person_shooter/addons/bsp_importer/examples/preset_example.tres
new file mode 100644
index 00000000000..f1df55215f6
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/examples/preset_example.tres
@@ -0,0 +1,47 @@
+[gd_resource type="Resource" script_class="BSPImportPreset" load_steps=6 format=3 uid="uid://cqh32qika2saw"]
+
+[ext_resource type="PackedScene" uid="uid://d3nve3gu13gp" path="res://addons/bsp_importer/examples/trigger_example.tscn" id="1_5lmtp"]
+[ext_resource type="PackedScene" uid="uid://bq7hi3koeh0ua" path="res://addons/bsp_importer/examples/lava_example_template.tscn" id="2_amq21"]
+[ext_resource type="Script" uid="uid://bblkqbg3tu5cm" path="res://addons/bsp_importer/bsp_import_preset.gd" id="3_3jh6d"]
+[ext_resource type="PackedScene" uid="uid://bfpqit3ge55dc" path="res://addons/bsp_importer/examples/slime_example_template.tscn" id="4_hntkd"]
+[ext_resource type="PackedScene" uid="uid://c1sip6qdohlf8" path="res://addons/bsp_importer/examples/water_example_template.tscn" id="5_5me6m"]
+
+[resource]
+script = ExtResource("3_3jh6d")
+inverse_scale_factor = 32.0
+ignored_flags = []
+generate_texture_materials = true
+material_path_pattern = "res://materials/{texture_name}_material.tres"
+texture_material_rename = {
+"texture_name1": "res://material/texture_name1_material.tres"
+}
+save_separate_materials = true
+overwrite_existing_materials = false
+texture_path_pattern = "res://textures/{texture_name}.png"
+texture_emission_path_pattern = "res://textures/{texture_name}_emission.png"
+texture_path_remap = {
+&"texture_name1_example": "res://textures/texture_name1_example.png"
+}
+transparent_texture_prefix = "{"
+palette_palette_path = "res://textures/palette.lmp"
+fullbright_range = [224, 255]
+overwrite_existing_textures = false
+water_scene_template = ExtResource("5_5me6m")
+slime_scene_template = ExtResource("4_hntkd")
+lava_scene_template = ExtResource("2_amq21")
+entity_path_pattern = "res://entities/{classname}.tscn"
+entity_remap = {
+&"trigger_example": ExtResource("1_5lmtp")
+}
+entity_offsets_quake_units = {
+&"example_offset_entity_classname": Vector3(16, 16, 0)
+}
+import_lights = true
+light_brightness_scale = 16.0
+generate_occlusion_culling = true
+culling_textures_exclude = Array[StringName]([])
+separate_mesh_on_grid = false
+mesh_separation_grid_size = 256.0
+use_triangle_collision = false
+ignore_missing_entities = false
+post_import_script = ""
diff --git a/3d/first_person_shooter/addons/bsp_importer/examples/slime_example_template.tscn b/3d/first_person_shooter/addons/bsp_importer/examples/slime_example_template.tscn
new file mode 100644
index 00000000000..428e2165860
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/examples/slime_example_template.tscn
@@ -0,0 +1,19 @@
+[gd_scene format=3 uid="uid://bfpqit3ge55dc"]
+
+[node name="SlimeExampleTemplate" type="Area3D"]
+gravity_space_override = 3
+gravity = 0.0
+linear_damp_space_override = 3
+linear_damp = 11.464
+angular_damp_space_override = 3
+angular_damp = 7.676
+
+[node name="make your own slime template with a script" type="Node3D" parent="."]
+
+[node name="for entering the area or whatever you need" type="Node3D" parent="."]
+
+[node name="for your game, specifically and set it in the" type="Node3D" parent="."]
+
+[node name="bsp import options" type="Node3D" parent="."]
+
+[node name="Collision shapes will be added as children" type="Node3D" parent="."]
diff --git a/3d/first_person_shooter/addons/bsp_importer/examples/trigger_example.tscn b/3d/first_person_shooter/addons/bsp_importer/examples/trigger_example.tscn
new file mode 100644
index 00000000000..671c7cd9f8c
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/examples/trigger_example.tscn
@@ -0,0 +1,17 @@
+[gd_scene format=3 uid="uid://d3nve3gu13gp"]
+
+[node name="TriggerExample" type="Area3D"]
+gravity_space_override = 3
+gravity = 0.0
+linear_damp_space_override = 3
+linear_damp = 11.464
+angular_damp_space_override = 3
+angular_damp = 7.676
+
+[node name="make your own trigger template with a script" type="Node3D" parent="."]
+
+[node name="for entering the area or whatever you need" type="Node3D" parent="."]
+
+[node name="for your game" type="Node3D" parent="."]
+
+[node name="Collision shapes will be added as children" type="Node3D" parent="."]
diff --git a/3d/first_person_shooter/addons/bsp_importer/examples/water_example_template.tscn b/3d/first_person_shooter/addons/bsp_importer/examples/water_example_template.tscn
new file mode 100644
index 00000000000..80ca36c43e5
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/examples/water_example_template.tscn
@@ -0,0 +1,19 @@
+[gd_scene format=3 uid="uid://c1sip6qdohlf8"]
+
+[node name="WaterExampleTemplate" type="Area3D"]
+gravity_space_override = 3
+gravity = 0.0
+linear_damp_space_override = 3
+linear_damp = 11.464
+angular_damp_space_override = 3
+angular_damp = 7.676
+
+[node name="make your own water template with a script" type="Node3D" parent="."]
+
+[node name="for entering the area or whatever you need" type="Node3D" parent="."]
+
+[node name="for your game, specifically and set it in the" type="Node3D" parent="."]
+
+[node name="bsp import options" type="Node3D" parent="."]
+
+[node name="Water collision shapes will be added as children" type="Node3D" parent="."]
diff --git a/3d/first_person_shooter/addons/bsp_importer/plugin.cfg b/3d/first_person_shooter/addons/bsp_importer/plugin.cfg
new file mode 100644
index 00000000000..94f578fc7c6
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/plugin.cfg
@@ -0,0 +1,7 @@
+[plugin]
+
+name="BSPImport"
+description="Quake .bsp file importer."
+author="jitspoe"
+version="0.20"
+script="bsp_editor_plugin.gd"
diff --git a/3d/first_person_shooter/addons/bsp_importer/wad_reader.gd b/3d/first_person_shooter/addons/bsp_importer/wad_reader.gd
new file mode 100644
index 00000000000..9d557025473
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/wad_reader.gd
@@ -0,0 +1,135 @@
+@tool
+extends Node
+
+class_name WADReader
+
+## Raw Data of the File
+@export var data : PackedByteArray
+
+@export var entry_count : int
+@export var table_offset : int
+
+@export var directory : Dictionary
+@export var resources : Dictionary
+
+class MipTexInfo:
+ var texture_string : String
+ var texture_size : Vector2i
+ var color_amt : int
+ var color_palette : PackedColorArray
+ var mip_offsets = []
+ var mip_images = []
+
+func dump_wad_to_textures(file : String):
+ var header_title = read_wad(file)[0]
+ if header_title == "WAD3":
+ read_directory(file)
+ create_resources()
+
+func read_wad(file : String, verbose : bool = false) -> Array:
+ data = FileAccess.get_file_as_bytes(file)
+ directory = {}
+ resources = {}
+ # read header
+ var header_title : String = data.slice(0, 4).get_string_from_ascii()
+ entry_count = data.slice(4, 8).decode_u32(0)
+ table_offset = data.slice(8, 12).decode_u32(0)
+
+ if verbose:
+ prints("Header Magic:", header_title)
+ prints("Entry Count:", entry_count)
+ prints("Table Offset:", table_offset)
+ prints("File Size:", data.size())
+ return [header_title, entry_count, table_offset, data.size()]
+
+func has_texture(file : String, texture_name : String):
+ read_wad(file, false)
+ read_directory(file)
+ return resources.has(texture_name)
+
+func read_directory(file_name : String) -> Dictionary:
+ directory.clear()
+ for entry_index in entry_count:
+ var offset : int = table_offset + (entry_index * 32)
+
+ var f_off : int = data.slice(offset + 0, offset + 4).decode_u32(0) # Offset to the lump data from the beginning of the WAD file
+ var f_siz : int = data.slice(offset + 4, offset + 8).decode_u32(0) # Size of the lump data on disk (can be compressed)
+ var f_org : int = data.slice(offset + 8, offset + 12).decode_u32(0) # Original size of the lump data (uncompressed)
+
+ var f_typ : int = data.slice(offset + 12, offset + 13).decode_u8(0) # 0x43: Miptex (texture) 0x40: Spray decal 0x42: QPic (simple image) 0x46: Font
+ var f_cmp : bool = data.slice(offset + 13, offset + 14).decode_u8(0) == 1 # Compression flag (0 for uncompressed, 1 for compressed)
+
+ var f_pad : PackedByteArray = data.slice(offset + 14, offset + 16) # dummy bytes
+ var f_nam : String = data.slice(offset + 16, offset + 32).get_string_from_ascii() # Null-terminated texture name
+
+ directory[entry_index] = {
+ "offset": f_off,
+ "disk_size": f_siz,
+ "original_size": f_org,
+ "type": f_typ,
+ "compressed": f_cmp,
+ "name": f_nam,
+ "file_name": file_name.get_file().to_lower().replace(".wad", "")
+ }
+
+ if not resources.has(f_nam.to_lower()):
+ resources[f_nam.to_lower()] = directory[entry_index]
+ return directory
+
+func create_resources():
+
+ var bc = 0
+ for entry in directory.values():
+ var miptexes = []
+
+ match entry.type:
+ 67: # Miptex Image.
+ load_texture(entry, "res://textures/", false)
+
+func load_texture(entry : Dictionary, save_path : String, save_to_file := false) -> ImageTexture:
+ var offset = entry.offset
+ var mti = MipTexInfo.new()
+ var texture_string = data.slice(offset + 0, offset + 16).get_string_from_ascii()
+ prints("Loading Miptexture %s for %s" % [texture_string, entry.file_name])
+ mti.texture_string = texture_string
+
+
+ var width = data.slice(offset + 16, offset + 20).decode_u16(0)
+ var height = data.slice(offset + 20, offset + 24).decode_u16(0)
+ var texture_size = Vector2i(width, height)
+
+ var mipmap_sizes = [
+ texture_size,
+ texture_size / 2,
+ texture_size / 4,
+ texture_size / 8
+ ]
+
+ var total_mipmap_size : int = 0
+ for size in mipmap_sizes:
+ total_mipmap_size += size.x * size.y
+
+ var mip_images = []
+ var palette_offset = entry.offset + 24 + 4 * 4 + total_mipmap_size
+
+ var color_amt : int = data.slice(palette_offset + 0, palette_offset + 2).decode_u16(0) # if this isnt 256, something is deeply wrong.
+ var palette : PackedColorArray = []
+
+ for index in color_amt:
+ var o = palette_offset + 2 + (index * 3)
+ var r = (float(data.slice(o + 0, o + 1).decode_u8(0)) / 255.0)
+ var g = (float(data.slice(o + 1, o + 2).decode_u8(0)) / 255.0)
+ var b = (float(data.slice(o + 2, o + 3).decode_u8(0)) / 255.0)
+ palette.append(Color(r, g, b))
+
+ var img = Image.create_empty(width, height, false, Image.FORMAT_RGB8)
+
+ var mm_o = data.slice(offset + 24, offset + 24 + 4).decode_u32(0)
+ for x in width:
+ for y in height:
+ var o = offset + mm_o + (y * texture_size.x + x)
+ img.set_pixel(x, y, palette[data.slice(o, o+1).decode_u8(0)])
+
+ if save_to_file:
+ img.save_png(save_path.to_lower())
+ return ImageTexture.create_from_image(img)
diff --git a/3d/first_person_shooter/addons/bsp_importer/wad_reader.gd.uid b/3d/first_person_shooter/addons/bsp_importer/wad_reader.gd.uid
new file mode 100644
index 00000000000..640d392108a
--- /dev/null
+++ b/3d/first_person_shooter/addons/bsp_importer/wad_reader.gd.uid
@@ -0,0 +1 @@
+uid://bop17f2utoki4
diff --git a/3d/first_person_shooter/blob_shadow.tscn b/3d/first_person_shooter/blob_shadow.tscn
new file mode 100644
index 00000000000..00b327f032e
--- /dev/null
+++ b/3d/first_person_shooter/blob_shadow.tscn
@@ -0,0 +1,19 @@
+[gd_scene load_steps=3 format=3 uid="uid://b4g77r67peq11"]
+
+[sub_resource type="Gradient" id="Gradient_voc73"]
+colors = PackedColorArray(0, 0, 0, 1, 0, 0, 0, 0)
+
+[sub_resource type="GradientTexture2D" id="GradientTexture2D_rpfu5"]
+gradient = SubResource("Gradient_voc73")
+fill = 1
+fill_from = Vector2(0.5, 0.5)
+fill_to = Vector2(0.5, 0.01)
+
+[node name="Decal" type="Decal"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0)
+size = Vector3(1.2, 2.4, 1.2)
+texture_albedo = SubResource("GradientTexture2D_rpfu5")
+albedo_mix = 0.5
+upper_fade = 1.0
+lower_fade = 1.0
+cull_mask = 1048573
diff --git a/3d/first_person_shooter/box.gd b/3d/first_person_shooter/box.gd
new file mode 100644
index 00000000000..8bcb259b18b
--- /dev/null
+++ b/3d/first_person_shooter/box.gd
@@ -0,0 +1,3 @@
+# This is a dummy script to give the box a `class_name`.
+class_name Box
+extends RigidBody3D
diff --git a/3d/first_person_shooter/box.gd.uid b/3d/first_person_shooter/box.gd.uid
new file mode 100644
index 00000000000..6acf73d1045
--- /dev/null
+++ b/3d/first_person_shooter/box.gd.uid
@@ -0,0 +1 @@
+uid://bwisehdvdbxf8
diff --git a/3d/first_person_shooter/box.tscn b/3d/first_person_shooter/box.tscn
new file mode 100644
index 00000000000..2275552ff6b
--- /dev/null
+++ b/3d/first_person_shooter/box.tscn
@@ -0,0 +1,56 @@
+[gd_scene load_steps=10 format=3 uid="uid://bly64h687ino4"]
+
+[ext_resource type="Script" uid="uid://bwisehdvdbxf8" path="res://box.gd" id="1_iqw5t"]
+
+[sub_resource type="BoxMesh" id="BoxMesh_ey7wh"]
+size = Vector3(1.25, 1.25, 1.25)
+
+[sub_resource type="FastNoiseLite" id="FastNoiseLite_vemq1"]
+fractal_type = 2
+fractal_lacunarity = 16.782
+fractal_gain = 1.4
+
+[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_nepn7"]
+seamless = true
+noise = SubResource("FastNoiseLite_vemq1")
+
+[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_w2v74"]
+seamless = true
+as_normal_map = true
+bump_strength = 0.1
+noise = SubResource("FastNoiseLite_vemq1")
+
+[sub_resource type="Gradient" id="Gradient_soa80"]
+colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
+
+[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_rmhqn"]
+seamless = true
+color_ramp = SubResource("Gradient_soa80")
+noise = SubResource("FastNoiseLite_vemq1")
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ka0y5"]
+albedo_color = Color(1.2, 0.85, 0.5, 1)
+albedo_texture = SubResource("NoiseTexture2D_nepn7")
+roughness = 0.5
+roughness_texture = SubResource("NoiseTexture2D_rmhqn")
+normal_enabled = true
+normal_texture = SubResource("NoiseTexture2D_w2v74")
+uv1_scale = Vector3(0.2, 0.133, 1)
+uv1_triplanar_sharpness = 15.455
+texture_filter = 4
+
+[sub_resource type="BoxShape3D" id="BoxShape3D_abq30"]
+size = Vector3(1.25, 1.25, 1.25)
+
+[node name="Box" type="RigidBody3D"]
+script = ExtResource("1_iqw5t")
+
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
+mesh = SubResource("BoxMesh_ey7wh")
+surface_material_override/0 = SubResource("StandardMaterial3D_ka0y5")
+
+[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
+shape = SubResource("BoxShape3D_abq30")
+
+[node name="GPUParticlesCollisionBox3D" type="GPUParticlesCollisionBox3D" parent="."]
+size = Vector3(1.26, 1.26, 1.26)
diff --git a/3d/first_person_shooter/bullet.gd b/3d/first_person_shooter/bullet.gd
new file mode 100644
index 00000000000..cf5dc38090f
--- /dev/null
+++ b/3d/first_person_shooter/bullet.gd
@@ -0,0 +1,52 @@
+extends RayCast3D
+
+# Damage dealt per bullet hit.
+const DAMAGE = 9
+
+
+func _physics_process(_delta: float) -> void:
+ var distance := 0.0
+
+ # The collision check must be performed in `_physics_process()`, not `_ready()` or `_process()`.
+ # Otherwise, it may be performed before the RayCast has time to update its collisions.
+ if is_colliding():
+ # Bullet hit something (enemy or solid surface).
+ $HitLocation.global_position = get_collision_point()
+ $HitLocation/GPUParticles3D.emitting = true
+
+ if get_collider() is Enemy:
+ var enemy := get_collider() as Enemy
+ enemy.damage(DAMAGE)
+
+ if get_collider() is Player:
+ var player := get_collider() as Player
+ player.health -= DAMAGE
+ # Push player away from the bullet's direction.
+ player.velocity -= transform.basis.z * 1.5
+
+ if get_collider() is Box:
+ var box := get_collider() as Box
+ # Push box away from the player's shot.
+ box.apply_central_impulse(-transform.basis.z)
+ # Apply small upwards motion to make the box slide more with horizontal shots.
+ box.apply_central_impulse(Vector3.UP * 0.5)
+
+ distance = global_position.distance_to($HitLocation.global_position)
+ else:
+ # Bullet missed.
+ distance = abs(target_position.z)
+
+ # Set up tracer round visual effect.
+ # The tracer is faded over time using an autoplaying AnimationPlayer.
+ $Tracer.scale.y = distance
+ $Tracer.position.z -= distance * 0.5
+
+ # We've hit or missed something, no need to keep checking.
+ # However, keep the bullet present in the scene for wall decals and particle effects.
+ enabled = false
+ set_physics_process(false)
+
+
+func _on_expire_timer_timeout() -> void:
+ # Bullet is no longer needed as its sound and particles have fully played.
+ queue_free()
diff --git a/3d/first_person_shooter/bullet.gd.uid b/3d/first_person_shooter/bullet.gd.uid
new file mode 100644
index 00000000000..ba1581ecdd8
--- /dev/null
+++ b/3d/first_person_shooter/bullet.gd.uid
@@ -0,0 +1 @@
+uid://cmm0d3i3dmejy
diff --git a/3d/first_person_shooter/bullet.tscn b/3d/first_person_shooter/bullet.tscn
new file mode 100644
index 00000000000..3a8776f9400
--- /dev/null
+++ b/3d/first_person_shooter/bullet.tscn
@@ -0,0 +1,159 @@
+[gd_scene load_steps=14 format=3 uid="uid://cfb66sviolbur"]
+
+[ext_resource type="Script" uid="uid://cmm0d3i3dmejy" path="res://bullet.gd" id="1_2qff5"]
+
+[sub_resource type="Gradient" id="Gradient_ebjhe"]
+interpolation_mode = 2
+offsets = PackedFloat32Array(0, 0.779221, 1)
+colors = PackedColorArray(1, 0.780392, 0, 1, 0.752941, 0, 0, 0.12549, 0, 0, 0, 0)
+
+[sub_resource type="GradientTexture1D" id="GradientTexture1D_uyrlj"]
+gradient = SubResource("Gradient_ebjhe")
+
+[sub_resource type="Curve" id="Curve_40aca"]
+_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
+point_count = 2
+
+[sub_resource type="CurveTexture" id="CurveTexture_iycpa"]
+curve = SubResource("Curve_40aca")
+
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_n2t5r"]
+emission_shape = 1
+emission_sphere_radius = 0.1
+direction = Vector3(0, 1, 0)
+spread = 90.0
+initial_velocity_min = 1.5
+initial_velocity_max = 1.5
+scale_min = 0.15
+scale_max = 0.15
+scale_curve = SubResource("CurveTexture_iycpa")
+color_ramp = SubResource("GradientTexture1D_uyrlj")
+collision_mode = 1
+collision_friction = 0.0
+collision_bounce = 0.5
+collision_use_scale = true
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_36rcs"]
+transparency = 1
+shading_mode = 0
+vertex_color_use_as_albedo = true
+billboard_mode = 1
+billboard_keep_scale = true
+
+[sub_resource type="QuadMesh" id="QuadMesh_af28p"]
+material = SubResource("StandardMaterial3D_36rcs")
+
+[sub_resource type="CylinderMesh" id="CylinderMesh_a6ysu"]
+top_radius = 0.04
+bottom_radius = 0.0
+height = 1.0
+radial_segments = 6
+rings = 1
+cap_top = false
+cap_bottom = false
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0twnr"]
+transparency = 1
+shading_mode = 0
+albedo_color = Color(1, 0.94902, 0.85098, 0.0627451)
+proximity_fade_distance = 0.1
+distance_fade_mode = 1
+distance_fade_max_distance = 5.0
+
+[sub_resource type="Animation" id="Animation_kkxjh"]
+length = 0.001
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Tracer:scale")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [Vector3(1, 1, 1)]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Tracer:sorting_offset")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [2.0]
+}
+
+[sub_resource type="Animation" id="Animation_q06vx"]
+resource_name = "fade"
+length = 0.6
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Tracer:scale:x")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.6),
+"transitions": PackedFloat32Array(1, 1),
+"update": 0,
+"values": [1.0, 0.0]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Tracer:scale:z")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0, 0.6),
+"transitions": PackedFloat32Array(1, 1),
+"update": 0,
+"values": [1.0, 0.0]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_0tdae"]
+_data = {
+&"RESET": SubResource("Animation_kkxjh"),
+&"fade": SubResource("Animation_q06vx")
+}
+
+[node name="Bullet" type="RayCast3D"]
+target_position = Vector3(0, 0, -100)
+collision_mask = 7
+script = ExtResource("1_2qff5")
+
+[node name="HitLocation" type="Node3D" parent="."]
+
+[node name="GPUParticles3D" type="GPUParticles3D" parent="HitLocation"]
+layers = 2
+cast_shadow = 0
+emitting = false
+amount = 20
+one_shot = true
+explosiveness = 1.0
+fixed_fps = 0
+interpolate = false
+process_material = SubResource("ParticleProcessMaterial_n2t5r")
+draw_pass_1 = SubResource("QuadMesh_af28p")
+
+[node name="Tracer" type="MeshInstance3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, -4.371139e-08, 1, 0, -1, -4.371139e-08, 0, 0, 0)
+sorting_offset = 2.0
+mesh = SubResource("CylinderMesh_a6ysu")
+surface_material_override/0 = SubResource("StandardMaterial3D_0twnr")
+
+[node name="ExpireTimer" type="Timer" parent="."]
+wait_time = 1.2
+autostart = true
+
+[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
+libraries = {
+&"": SubResource("AnimationLibrary_0tdae")
+}
+autoplay = "fade"
+
+[connection signal="timeout" from="ExpireTimer" to="." method="_on_expire_timer_timeout"]
diff --git a/3d/first_person_shooter/crosshair.png b/3d/first_person_shooter/crosshair.png
new file mode 100644
index 00000000000..41838dee87f
Binary files /dev/null and b/3d/first_person_shooter/crosshair.png differ
diff --git a/3d/first_person_shooter/crosshair.png.import b/3d/first_person_shooter/crosshair.png.import
new file mode 100644
index 00000000000..148ccf6a07e
--- /dev/null
+++ b/3d/first_person_shooter/crosshair.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d0h6we75g3l0h"
+path="res://.godot/imported/crosshair.png-b7f9cb2e0fc32a087972fec001d3421e.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://crosshair.png"
+dest_files=["res://.godot/imported/crosshair.png-b7f9cb2e0fc32a087972fec001d3421e.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/3d/first_person_shooter/default_bus_layout.tres b/3d/first_person_shooter/default_bus_layout.tres
new file mode 100644
index 00000000000..963f6c00c97
--- /dev/null
+++ b/3d/first_person_shooter/default_bus_layout.tres
@@ -0,0 +1,8 @@
+[gd_resource type="AudioBusLayout" load_steps=2 format=3 uid="uid://det8rjoq2avpd"]
+
+[sub_resource type="AudioEffectLowPassFilter" id="AudioEffectLowPassFilter_mtohd"]
+resource_name = "LowPassFilter"
+
+[resource]
+bus/0/effect/0/effect = SubResource("AudioEffectLowPassFilter_mtohd")
+bus/0/effect/0/enabled = false
diff --git a/3d/first_person_shooter/e1m1.bsp b/3d/first_person_shooter/e1m1.bsp
new file mode 100644
index 00000000000..ec9fc80576f
Binary files /dev/null and b/3d/first_person_shooter/e1m1.bsp differ
diff --git a/3d/first_person_shooter/e1m1.bsp.import b/3d/first_person_shooter/e1m1.bsp.import
new file mode 100644
index 00000000000..a67c8ff3f1c
--- /dev/null
+++ b/3d/first_person_shooter/e1m1.bsp.import
@@ -0,0 +1,52 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://bsm3bc2kg4yk4"
+path="res://.godot/imported/e1m1.bsp-36826799781ae8eadfd2a7b1be26c18a.scn"
+
+[deps]
+
+source_file="res://e1m1.bsp"
+dest_files=["res://.godot/imported/e1m1.bsp-36826799781ae8eadfd2a7b1be26c18a.scn"]
+
+[params]
+
+inverse_scale_factor=32.0
+ignored_flags=PackedInt64Array()
+include_sky_surfaces=true
+generate_texture_materials=true
+save_separate_materials=true
+overwrite_existing_materials=false
+material_path_pattern="res://materials/{texture_name}_material.tres"
+texture_material_rename={
+"texture_name1_example": "res://material/texture_name1_material.tres"
+}
+texture_path_pattern="res://textures/{texture_name}.png"
+texture_emission_path_pattern="res://textures/{texture_name}_emission.png"
+texture_path_remap={
+"texture_name1_example": "res://textures/texture_name1.png"
+}
+transparent_texture_prefix="{"
+texture_palette_path="res://textures/palette.lmp"
+fullbright_range=PackedInt32Array(224, 255)
+overwrite_existing_textures=false
+water_scene_template="res://addons/bsp_importer/examples/water_example_template.tscn"
+slime_scene_template="res://addons/bsp_importer/examples/slime_example_template.tscn"
+lava_scene_template="res://addons/bsp_importer/examples/lava_example_template.tscn"
+entity_path_pattern="res://entities/{classname}.tscn"
+entity_remap={
+&"trigger_example": "res://triggers/trigger_example.tres"
+}
+entity_offsets_quake_units={
+&"example_offset_entity": Vector3(16, 16, 0)
+}
+import_lights=true
+light_brightness_scale=16.0
+generate_occlusion_culling=true
+culling_textures_exclude=Array[StringName]([])
+use_triangle_collision=false
+separate_mesh_on_grid=false
+mesh_separation_grid_size=256.0
+ignore_missing_entities=false
+post_import_script=""
diff --git a/3d/first_person_shooter/enemy/enemy.gd b/3d/first_person_shooter/enemy/enemy.gd
new file mode 100644
index 00000000000..623396bf352
--- /dev/null
+++ b/3d/first_person_shooter/enemy/enemy.gd
@@ -0,0 +1,100 @@
+class_name Enemy
+extends CharacterBody3D
+
+## Number of health points the enemy has.
+@export var health := 100
+
+# Get the gravity from the project settings to be synced with RigidBody nodes.
+var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
+
+# Reference to the player (determined on initialization).
+var player: Player = null
+
+# If `true`, the enemy can currently see the player (and should act upon it).
+var can_see_player := false
+
+# Target position for the next bullet to fire (in global coordinates).
+@onready var bullet_target_position := Vector3.ZERO
+
+# Used for resetting the fixed wait time after the initial jitter.
+@onready var line_of_sight_timer_initial_wait_time: float = $LineOfSightTimer.wait_time
+
+## Maximum distance at which enemies will attempt to fire their weapon.
+const MAX_FIRING_DISTANCE = 25.0
+
+func _ready():
+ player = get_tree().get_first_node_in_group("player")
+
+ # Jitter line of sight timer to avoid stuttering due to performing lots of RayCasts in the same frame.
+ $LineOfSightTimer.wait_time *= randf()
+
+
+func _physics_process(delta):
+ # Add the gravity.
+ if not is_on_floor():
+ velocity.y -= gravity * delta
+
+ if can_see_player:
+ var distance := global_position.distance_to(player.global_position)
+ # Look towards the player (the mesh's rotation affects the currently shown 2.5D sprite).
+ $Sprite.global_transform = global_transform.looking_at(player.global_position)
+
+ # Don't move towards the player if very close already, or if currently playing a firing or pain animation.
+ if distance > 2.0 and $AnimationPlayer.current_animation == &"walk":
+ var direction := global_position.direction_to(player.global_position)
+ velocity.x = direction.x * 4
+ velocity.z = direction.z * 4
+ move_and_slide()
+
+ if is_zero_approx($ShootTimer.time_left) and distance < MAX_FIRING_DISTANCE:
+ # Set the target position for the bullet before the animation is played.
+ # This allows the final shot to be visibly delayed, allowing players to dodge bullets
+ # by strafing.
+ bullet_target_position = player.global_position
+
+ # Shot frequency is proportional to distance.
+ # The closer the enemy is to the player, the more frequently they will fire.
+ $ShootTimer.start(remap(distance, 0.0, MAX_FIRING_DISTANCE, 0.6, 2.0))
+ # Note: For enemy animations to play independently of other enemies,
+ # the mesh's material must be set as Local To Scene in the inspector.
+ # The `fire` animation handles the actual bullet firing with a Call Method track.
+ $AnimationPlayer.play("fire")
+ $AnimationPlayer.queue("walk")
+
+ if health <= 0:
+ queue_free()
+
+
+func _on_line_of_sight_timer_timeout() -> void:
+ # Set the fixed wait time back, now that the first iteration with jittered wait time has passed.
+ $LineOfSightTimer.wait_time = line_of_sight_timer_initial_wait_time
+
+ # Convert player position to be relative to the enemy's position (as `target_position` is in local space).
+ # This line of sight is used to check whether the enemy should chase and shoot the player.
+ $LineOfSight.enabled = true
+ $LineOfSight.target_position = player.global_position - position
+ # Allow performing queries immediately after enabling the RayCast.
+ # Otherwise, we would have to wait one physics frame.
+ $LineOfSight.force_raycast_update()
+ can_see_player = player.health >= 1 and not $LineOfSight.is_colliding()
+
+ # Disable RayCast once it's not needed anymore (until the next timer timeout) to improve performance.
+ $LineOfSight.enabled = false
+
+
+## Fires a bullet towards the position stored in `bullet_target_position` (method called by AnimationPlayer).
+func fire_bullet() -> void:
+ var bullet := preload("res://bullet.tscn").instantiate()
+ # Bullets are not child of the player to prevent moving along the player.
+ get_parent().add_child(bullet)
+ bullet.global_transform = global_transform.looking_at(bullet_target_position)
+ # Apply random spread (twice as much spread horizontally than vertically).
+ bullet.rotation.y += -0.1 + randf() * 0.2
+ bullet.rotation.x += -0.05 + randf() * 0.1
+
+
+## Called when receiving damage.
+func damage(p_damage: int) -> void:
+ health -= p_damage
+ $AnimationPlayer.play("pain")
+ $AnimationPlayer.queue("walk")
diff --git a/3d/first_person_shooter/enemy/enemy.gd.uid b/3d/first_person_shooter/enemy/enemy.gd.uid
new file mode 100644
index 00000000000..222df266109
--- /dev/null
+++ b/3d/first_person_shooter/enemy/enemy.gd.uid
@@ -0,0 +1 @@
+uid://do215ft5ta05a
diff --git a/3d/first_person_shooter/enemy/enemy.gdshader b/3d/first_person_shooter/enemy/enemy.gdshader
new file mode 100644
index 00000000000..6484d5ae125
--- /dev/null
+++ b/3d/first_person_shooter/enemy/enemy.gdshader
@@ -0,0 +1,40 @@
+shader_type spatial;
+render_mode specular_disabled, cull_disabled;
+
+// Texture spritesheet.
+uniform sampler2D views : filter_nearest, source_color;
+
+// Number of sides in the spritesheet (horizontal axis on the image).
+uniform int view_count : hint_range(1, 32) = 8;
+
+// Number of frames in the animation (vertical axis on the image).
+uniform int frame_count : hint_range(1, 1000) = 7;
+// Current frame in the animation.
+uniform int frame : hint_range(0, 999) = 0;
+
+const float MIN_BRIGHTNESS = 0.1;
+const float ALBEDO_ENERGY = 4.0;
+
+void vertex() {
+ // Y-billboard.
+ MODELVIEW_MATRIX = VIEW_MATRIX * mat4(vec4(normalize(cross(vec3(0.0, 1.0, 0.0), INV_VIEW_MATRIX[2].xyz)), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(normalize(cross(INV_VIEW_MATRIX[0].xyz, vec3(0.0, 1.0, 0.0))), 0.0), MODEL_MATRIX[3]);
+}
+
+void fragment() {
+ float d = dot(NORMAL.zx, vec2(-1.0, 0.0));
+ float angle = -acos(NORMAL.z) + PI;
+ float current_view = NORMAL.x > 0.0 ? angle / TAU : 1.0 - angle / TAU;
+ float x = round(current_view * float(view_count)) / float(view_count); // UV horizontal start for the view in the atlas.
+ float y = float(frame) / float(frame_count); // UV vertical start for the view in the atlas.
+
+ float view_width = 1.0 / float(view_count); // UV width of the view in the atlas.
+ float view_height = 1.0 / float(frame_count); // UV height of the animation in the atlas.
+ vec4 tex = texture(views, vec2(x + view_width * UV.x, y + view_height * UV.y));
+
+ // Ensure enemies in the darkness are always visible to an extent,
+ // but allow them to be lit by light sources.
+ EMISSION.rgb = tex.rgb * MIN_BRIGHTNESS;
+ ALBEDO = tex.rgb * ALBEDO_ENERGY;
+ ALPHA = tex.a;
+ ALPHA_SCISSOR_THRESHOLD = 0.5;
+}
diff --git a/3d/first_person_shooter/enemy/enemy.gdshader.uid b/3d/first_person_shooter/enemy/enemy.gdshader.uid
new file mode 100644
index 00000000000..54715bc1891
--- /dev/null
+++ b/3d/first_person_shooter/enemy/enemy.gdshader.uid
@@ -0,0 +1 @@
+uid://c3fbfd8sgfoh0
diff --git a/3d/first_person_shooter/enemy/enemy.tscn b/3d/first_person_shooter/enemy/enemy.tscn
new file mode 100644
index 00000000000..7a7ce45aa17
--- /dev/null
+++ b/3d/first_person_shooter/enemy/enemy.tscn
@@ -0,0 +1,240 @@
+[gd_scene load_steps=15 format=3 uid="uid://bbj30jyv46r1t"]
+
+[ext_resource type="Script" uid="uid://do215ft5ta05a" path="res://enemy/enemy.gd" id="1_t0d11"]
+[ext_resource type="Shader" uid="uid://c3fbfd8sgfoh0" path="res://enemy/enemy.gdshader" id="2_frlby"]
+[ext_resource type="Texture2D" uid="uid://bvhfqb51fdy8c" path="res://enemy/spritesheet.png" id="3_catq1"]
+[ext_resource type="PackedScene" uid="uid://b4g77r67peq11" path="res://blob_shadow.tscn" id="4_nscyu"]
+[ext_resource type="AudioStream" uid="uid://lqgi4erf48wg" path="res://player/shotgun/fire.wav" id="5_sh4av"]
+
+[sub_resource type="BoxShape3D" id="BoxShape3D_cwcsd"]
+size = Vector3(1, 2, 1)
+
+[sub_resource type="QuadMesh" id="QuadMesh_he27t"]
+size = Vector2(1.638, 2)
+
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_4tdqe"]
+resource_local_to_scene = true
+render_priority = 0
+shader = ExtResource("2_frlby")
+shader_parameter/views = ExtResource("3_catq1")
+shader_parameter/view_count = 8
+shader_parameter/frame_count = 7
+shader_parameter/frame = 0
+
+[sub_resource type="Animation" id="Animation_ltck1"]
+length = 0.001
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Sprite:surface_material_override/0:shader_parameter/frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [0]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("WeaponLight:visible")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("WeaponLight:light_energy")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [2.0]
+}
+
+[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_5sfw8"]
+streams_count = 1
+stream_0/stream = ExtResource("5_sh4av")
+
+[sub_resource type="Animation" id="Animation_royxd"]
+resource_name = "fire"
+length = 0.6
+step = 0.05
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Sprite:surface_material_override/0:shader_parameter/frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.1, 0.3),
+"transitions": PackedFloat32Array(1, 1, 1),
+"update": 1,
+"values": [4, 5, 4]
+}
+tracks/1/type = "audio"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("WeaponSound")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"clips": [{
+"end_offset": 0.0,
+"start_offset": 0.0,
+"stream": SubResource("AudioStreamRandomizer_5sfw8")
+}],
+"times": PackedFloat32Array(0.1)
+}
+tracks/1/use_blend = true
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("WeaponLight:visible")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0.1, 0.4),
+"transitions": PackedFloat32Array(1, 1),
+"update": 1,
+"values": [true, false]
+}
+tracks/3/type = "value"
+tracks/3/imported = false
+tracks/3/enabled = true
+tracks/3/path = NodePath("WeaponLight:light_energy")
+tracks/3/interp = 1
+tracks/3/loop_wrap = true
+tracks/3/keys = {
+"times": PackedFloat32Array(0.1, 0.2, 0.4),
+"transitions": PackedFloat32Array(-2, -2, -2),
+"update": 0,
+"values": [0.0, 2.0, 0.0]
+}
+tracks/4/type = "method"
+tracks/4/imported = false
+tracks/4/enabled = true
+tracks/4/path = NodePath(".")
+tracks/4/interp = 1
+tracks/4/loop_wrap = true
+tracks/4/keys = {
+"times": PackedFloat32Array(0.1),
+"transitions": PackedFloat32Array(1),
+"values": [{
+"args": [],
+"method": &"fire_bullet"
+}]
+}
+
+[sub_resource type="Animation" id="Animation_qjgq4"]
+resource_name = "pain"
+length = 0.4
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Sprite:surface_material_override/0:shader_parameter/frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [6]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("WeaponLight:visible")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
+}
+
+[sub_resource type="Animation" id="Animation_1ms2s"]
+resource_name = "walk"
+length = 0.45
+loop_mode = 2
+step = 0.05
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Sprite:surface_material_override/0:shader_parameter/frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.45),
+"transitions": PackedFloat32Array(1, 1),
+"update": 0,
+"values": [0, 3]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_1kihh"]
+_data = {
+&"RESET": SubResource("Animation_ltck1"),
+&"fire": SubResource("Animation_royxd"),
+&"pain": SubResource("Animation_qjgq4"),
+&"walk": SubResource("Animation_1ms2s")
+}
+
+[node name="Enemy" type="CharacterBody3D"]
+collision_layer = 4
+collision_mask = 5
+script = ExtResource("1_t0d11")
+
+[node name="LineOfSight" type="RayCast3D" parent="."]
+
+[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
+shape = SubResource("BoxShape3D_cwcsd")
+
+[node name="Sprite" type="MeshInstance3D" parent="."]
+layers = 4
+mesh = SubResource("QuadMesh_he27t")
+surface_material_override/0 = SubResource("ShaderMaterial_4tdqe")
+
+[node name="Decal" parent="." instance=ExtResource("4_nscyu")]
+cull_mask = 1048569
+
+[node name="WeaponSound" type="AudioStreamPlayer3D" parent="."]
+volume_db = -12.0
+unit_size = 20.0
+max_db = -12.0
+attenuation_filter_cutoff_hz = 20500.0
+
+[node name="WeaponLight" type="OmniLight3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0)
+visible = false
+light_color = Color(1, 0.764706, 0.235294, 1)
+light_energy = 2.0
+light_specular = 0.01
+shadow_enabled = true
+shadow_bias = 0.12
+shadow_blur = 2.5
+
+[node name="LineOfSightTimer" type="Timer" parent="."]
+wait_time = 0.25
+autostart = true
+
+[node name="ShootTimer" type="Timer" parent="."]
+wait_time = 0.6
+one_shot = true
+autostart = true
+
+[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
+libraries = {
+&"": SubResource("AnimationLibrary_1kihh")
+}
+autoplay = "walk"
+
+[connection signal="timeout" from="LineOfSightTimer" to="." method="_on_line_of_sight_timer_timeout"]
diff --git a/3d/first_person_shooter/enemy/spritesheet.png b/3d/first_person_shooter/enemy/spritesheet.png
new file mode 100644
index 00000000000..3b50218c850
Binary files /dev/null and b/3d/first_person_shooter/enemy/spritesheet.png differ
diff --git a/3d/first_person_shooter/enemy/spritesheet.png.import b/3d/first_person_shooter/enemy/spritesheet.png.import
new file mode 100644
index 00000000000..b70532a73d7
--- /dev/null
+++ b/3d/first_person_shooter/enemy/spritesheet.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bvhfqb51fdy8c"
+path="res://.godot/imported/spritesheet.png-f3063143692b10bc5ef125d04f8d150a.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://enemy/spritesheet.png"
+dest_files=["res://.godot/imported/spritesheet.png-f3063143692b10bc5ef125d04f8d150a.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/fonts/vga-rom-font.png b/3d/first_person_shooter/fonts/vga-rom-font.png
new file mode 100644
index 00000000000..785dde30831
Binary files /dev/null and b/3d/first_person_shooter/fonts/vga-rom-font.png differ
diff --git a/3d/first_person_shooter/fonts/vga-rom-font.png.import b/3d/first_person_shooter/fonts/vga-rom-font.png.import
new file mode 100644
index 00000000000..41a3a139502
--- /dev/null
+++ b/3d/first_person_shooter/fonts/vga-rom-font.png.import
@@ -0,0 +1,25 @@
+[remap]
+
+importer="font_data_image"
+type="FontFile"
+uid="uid://blm3851cjtjji"
+path="res://.godot/imported/vga-rom-font.png-a8a12971abf9676452f3287bd6c88044.fontdata"
+
+[deps]
+
+source_file="res://fonts/vga-rom-font.png"
+dest_files=["res://.godot/imported/vga-rom-font.png-a8a12971abf9676452f3287bd6c88044.fontdata"]
+
+[params]
+
+character_ranges=PackedStringArray("0-254")
+kerning_pairs=PackedStringArray()
+columns=16
+rows=16
+image_margin=Rect2i(0, 0, 0, 0)
+character_margin=Rect2i(8, 0, 8, 0)
+ascent=0
+descent=0
+fallbacks=[]
+compress=true
+scaling_mode=2
diff --git a/3d/first_person_shooter/lamp_post.tscn b/3d/first_person_shooter/lamp_post.tscn
new file mode 100644
index 00000000000..a644252a23a
--- /dev/null
+++ b/3d/first_person_shooter/lamp_post.tscn
@@ -0,0 +1,51 @@
+[gd_scene load_steps=5 format=3 uid="uid://cosjr7whfc78d"]
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_afgmo"]
+albedo_color = Color(0, 0, 0, 1)
+emission_enabled = true
+emission = Color(1, 1, 1, 1)
+emission_energy_multiplier = 2.5
+
+[sub_resource type="Gradient" id="Gradient_3tq41"]
+interpolation_mode = 2
+offsets = PackedFloat32Array(0, 0.370079, 0.724409, 1)
+colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0.207843, 1, 1, 1, 0.0352941, 1, 1, 1, 0)
+
+[sub_resource type="GradientTexture2D" id="GradientTexture2D_mht1q"]
+gradient = SubResource("Gradient_3tq41")
+fill = 1
+fill_from = Vector2(0.5, 0.5)
+fill_to = Vector2(0.5, 0.01)
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_pmykn"]
+transparency = 1
+blend_mode = 1
+shading_mode = 0
+albedo_texture = SubResource("GradientTexture2D_mht1q")
+texture_filter = 4
+billboard_mode = 1
+
+[node name="LampPost" type="Node3D"]
+
+[node name="Base" type="CSGBox3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.3, 0)
+
+[node name="Pole" type="CSGBox3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, 0)
+use_collision = true
+size = Vector3(0.2, 5, 0.2)
+
+[node name="Light" type="CSGSphere3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 5, 0)
+radial_segments = 6
+rings = 3
+material = SubResource("StandardMaterial3D_afgmo")
+
+[node name="OmniLight3D" type="OmniLight3D" parent="Light"]
+light_specular = 0.1
+omni_range = 15.0
+
+[node name="Sprite3D" type="Sprite3D" parent="Light"]
+material_override = SubResource("StandardMaterial3D_pmykn")
+pixel_size = 0.05
+texture = SubResource("GradientTexture2D_mht1q")
diff --git a/3d/first_person_shooter/level.GPUParticlesCollisionSDF3D_data.exr b/3d/first_person_shooter/level.GPUParticlesCollisionSDF3D_data.exr
new file mode 100644
index 00000000000..70dcf4ce5ff
Binary files /dev/null and b/3d/first_person_shooter/level.GPUParticlesCollisionSDF3D_data.exr differ
diff --git a/3d/first_person_shooter/level.GPUParticlesCollisionSDF3D_data.exr.import b/3d/first_person_shooter/level.GPUParticlesCollisionSDF3D_data.exr.import
new file mode 100644
index 00000000000..31ef03b4b96
--- /dev/null
+++ b/3d/first_person_shooter/level.GPUParticlesCollisionSDF3D_data.exr.import
@@ -0,0 +1,28 @@
+[remap]
+
+importer="3d_texture"
+type="CompressedTexture3D"
+uid="uid://qgj3lwwrrgj"
+path="res://.godot/imported/level.GPUParticlesCollisionSDF3D_data.exr-54404c69370042e4cdd9781f5585e554.ctex3d"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://level.GPUParticlesCollisionSDF3D_data.exr"
+dest_files=["res://.godot/imported/level.GPUParticlesCollisionSDF3D_data.exr-54404c69370042e4cdd9781f5585e554.ctex3d"]
+
+[params]
+
+compress/mode=3
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/channel_pack=1
+mipmaps/generate=false
+mipmaps/limit=-1
+slices/horizontal=1
+slices/vertical=231
diff --git a/3d/first_person_shooter/level.gdshader b/3d/first_person_shooter/level.gdshader
new file mode 100644
index 00000000000..780aba9aabb
--- /dev/null
+++ b/3d/first_person_shooter/level.gdshader
@@ -0,0 +1,69 @@
+// NOTE: Shader automatically converted from Godot Engine 4.0.beta's StandardMaterial3D.
+
+shader_type spatial;
+render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx;
+uniform vec4 albedo : source_color;
+uniform sampler2D texture_albedo : source_color,filter_nearest_mipmap_anisotropic,repeat_enable;
+uniform float point_size : hint_range(0,128);
+uniform float roughness : hint_range(0,1);
+uniform sampler2D texture_metallic : hint_default_white,filter_nearest_mipmap_anisotropic,repeat_enable;
+uniform vec4 metallic_texture_channel;
+uniform sampler2D texture_roughness : hint_roughness_r,filter_nearest_mipmap_anisotropic,repeat_enable;
+uniform float specular;
+uniform float metallic;
+uniform sampler2D texture_normal : hint_roughness_normal,filter_nearest_mipmap_anisotropic,repeat_enable;
+uniform float normal_scale : hint_range(-16,16);
+varying vec3 uv1_triplanar_pos;
+uniform float uv1_blend_sharpness;
+varying vec3 uv1_power_normal;
+uniform vec3 uv1_scale;
+uniform vec3 uv1_offset;
+uniform vec3 uv2_scale;
+uniform vec3 uv2_offset;
+
+
+void vertex() {
+ TANGENT = vec3(0.0,0.0,-1.0) * abs(NORMAL.x);
+ TANGENT+= vec3(1.0,0.0,0.0) * abs(NORMAL.y);
+ TANGENT+= vec3(1.0,0.0,0.0) * abs(NORMAL.z);
+ TANGENT = normalize(TANGENT);
+ BINORMAL = vec3(0.0,1.0,0.0) * abs(NORMAL.x);
+ BINORMAL+= vec3(0.0,0.0,-1.0) * abs(NORMAL.y);
+ BINORMAL+= vec3(0.0,1.0,0.0) * abs(NORMAL.z);
+ BINORMAL = normalize(BINORMAL);
+ uv1_power_normal=pow(abs(NORMAL),vec3(uv1_blend_sharpness));
+ uv1_triplanar_pos = VERTEX * uv1_scale + uv1_offset;
+ uv1_power_normal/=dot(uv1_power_normal,vec3(1.0));
+ uv1_triplanar_pos *= vec3(1.0,-1.0, 1.0);
+
+ // Color walls and ceilings differently from the floor.
+ if (dot(NORMAL, vec3(0.0, 1.0, 0.0)) < 0.2) {
+ COLOR.r = 4.0;
+ COLOR.g = 1.5;
+ }
+}
+
+
+
+
+vec4 triplanar_texture(sampler2D p_sampler,vec3 p_weights,vec3 p_triplanar_pos) {
+ vec4 samp=vec4(0.0);
+ samp+= texture(p_sampler,p_triplanar_pos.xy) * p_weights.z;
+ samp+= texture(p_sampler,p_triplanar_pos.xz) * p_weights.y;
+ samp+= texture(p_sampler,p_triplanar_pos.zy * vec2(-1.0,1.0)) * p_weights.x;
+ return samp;
+}
+
+
+void fragment() {
+ vec4 albedo_tex = triplanar_texture(texture_albedo,uv1_power_normal,uv1_triplanar_pos);
+ ALBEDO = albedo.rgb * albedo_tex.rgb * COLOR.rgb;
+ float metallic_tex = dot(triplanar_texture(texture_metallic,uv1_power_normal,uv1_triplanar_pos),metallic_texture_channel);
+ METALLIC = metallic_tex * metallic;
+ vec4 roughness_texture_channel = vec4(1.0,0.0,0.0,0.0);
+ float roughness_tex = dot(triplanar_texture(texture_roughness,uv1_power_normal,uv1_triplanar_pos),roughness_texture_channel);
+ ROUGHNESS = roughness_tex * roughness;
+ SPECULAR = specular;
+ NORMAL_MAP = triplanar_texture(texture_normal,uv1_power_normal,uv1_triplanar_pos).rgb;
+ NORMAL_MAP_DEPTH = normal_scale;
+}
diff --git a/3d/first_person_shooter/level.gdshader.uid b/3d/first_person_shooter/level.gdshader.uid
new file mode 100644
index 00000000000..f876dcc490f
--- /dev/null
+++ b/3d/first_person_shooter/level.gdshader.uid
@@ -0,0 +1 @@
+uid://d3j1a7u1lrqv0
diff --git a/3d/first_person_shooter/level.tscn b/3d/first_person_shooter/level.tscn
new file mode 100644
index 00000000000..afa24e63f21
--- /dev/null
+++ b/3d/first_person_shooter/level.tscn
@@ -0,0 +1,72 @@
+[gd_scene load_steps=9 format=3 uid="uid://bcmepm05qldy5"]
+
+[ext_resource type="Texture2D" uid="uid://bc3n2sen32mqx" path="res://sky.png" id="1_0n6b1"]
+[ext_resource type="PackedScene" uid="uid://dfyswwfb8j6iv" path="res://player.tscn" id="2_cwuyg"]
+[ext_resource type="PackedScene" uid="uid://bsm3bc2kg4yk4" path="res://e1m1.bsp" id="3_oi3di"]
+[ext_resource type="PackedScene" uid="uid://bbj30jyv46r1t" path="res://enemy/enemy.tscn" id="4_errvf"]
+[ext_resource type="CompressedTexture3D" uid="uid://qgj3lwwrrgj" path="res://level.GPUParticlesCollisionSDF3D_data.exr" id="5_myd3n"]
+
+[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_33kw8"]
+panorama = ExtResource("1_0n6b1")
+filter = false
+
+[sub_resource type="Sky" id="Sky_xd4ok"]
+sky_material = SubResource("PanoramaSkyMaterial_33kw8")
+
+[sub_resource type="Environment" id="Environment_b1dvs"]
+background_mode = 2
+sky = SubResource("Sky_xd4ok")
+ambient_light_color = Color(1, 1, 1, 1)
+ambient_light_sky_contribution = 0.0
+ambient_light_energy = 0.1
+tonemap_mode = 4
+tonemap_exposure = 1.3
+tonemap_white = 6.0
+fog_enabled = true
+fog_light_color = Color(0.117647, 0.156863, 0.196078, 1)
+fog_density = 0.006
+fog_sky_affect = 0.0
+
+[node name="Node3D" type="Node3D"]
+
+[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
+environment = SubResource("Environment_b1dvs")
+
+[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
+transform = Transform3D(0.236491, -0.970858, -0.0388079, 0.265457, 0.0261379, 0.963768, -0.934668, -0.238224, 0.263902, 2.61962, -0.479115, -1.60764)
+light_color = Color(0.308, 0.369333, 0.4, 1)
+light_energy = 10.0
+light_cull_mask = 4294967291
+shadow_enabled = true
+shadow_bias = 0.04
+directional_shadow_mode = 0
+directional_shadow_fade_start = 1.0
+directional_shadow_max_distance = 75.0
+
+[node name="Player" parent="." instance=ExtResource("2_cwuyg")]
+transform = Transform3D(-4.371139e-08, 0, 1, 0, 1, 0, -1, 0, -4.371139e-08, -50, 3, -33)
+
+[node name="e1m1" parent="." instance=ExtResource("3_oi3di")]
+
+[node name="Enemies" type="Node3D" parent="."]
+
+[node name="Enemy" parent="Enemies" instance=ExtResource("4_errvf")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 6, 0)
+
+[node name="Enemy2" parent="Enemies" instance=ExtResource("4_errvf")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, -23)
+
+[node name="Enemy3" parent="Enemies" instance=ExtResource("4_errvf")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8, 2, -24)
+
+[node name="Enemy4" parent="Enemies" instance=ExtResource("4_errvf")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -22, 4.5, -24)
+
+[node name="Enemy5" parent="Enemies" instance=ExtResource("4_errvf")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -38, 4.5, -19)
+
+[node name="GPUParticlesCollisionSDF3D" type="GPUParticlesCollisionSDF3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -26.5, 10, 11)
+size = Vector3(157, 50, 142)
+resolution = 4
+texture = ExtResource("5_myd3n")
diff --git a/3d/first_person_shooter/level_material.tres b/3d/first_person_shooter/level_material.tres
new file mode 100644
index 00000000000..1a9982dd8ce
--- /dev/null
+++ b/3d/first_person_shooter/level_material.tres
@@ -0,0 +1,35 @@
+[gd_resource type="StandardMaterial3D" load_steps=6 format=3 uid="uid://80yp8cdmypl6"]
+
+[sub_resource type="FastNoiseLite" id="FastNoiseLite_vemq1"]
+fractal_type = 2
+fractal_lacunarity = 16.782
+fractal_gain = 1.4
+
+[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_nepn7"]
+noise = SubResource("FastNoiseLite_vemq1")
+seamless = true
+
+[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_w2v74"]
+noise = SubResource("FastNoiseLite_vemq1")
+seamless = true
+as_normal_map = true
+bump_strength = 0.1
+
+[sub_resource type="Gradient" id="Gradient_soa80"]
+colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
+
+[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_rmhqn"]
+noise = SubResource("FastNoiseLite_vemq1")
+color_ramp = SubResource("Gradient_soa80")
+seamless = true
+
+[resource]
+albedo_texture = SubResource("NoiseTexture2D_nepn7")
+roughness = 0.5
+roughness_texture = SubResource("NoiseTexture2D_rmhqn")
+normal_enabled = true
+normal_texture = SubResource("NoiseTexture2D_w2v74")
+uv1_scale = Vector3(0.063, 0.063, 0.063)
+uv1_triplanar = true
+uv1_triplanar_sharpness = 15.455
+texture_filter = 4
diff --git a/3d/first_person_shooter/materials/+0_tscrn0_material.tres b/3d/first_person_shooter/materials/+0_tscrn0_material.tres
new file mode 100644
index 00000000000..eb3da38ad4d
--- /dev/null
+++ b/3d/first_person_shooter/materials/+0_tscrn0_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bqd47m1swyjr1"]
+
+[ext_resource type="Texture2D" path="res://textures/+0_tscrn0.png" id="1_x5cjf"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_x5cjf")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+0_tscrn1_material.tres b/3d/first_person_shooter/materials/+0_tscrn1_material.tres
new file mode 100644
index 00000000000..5fe4b7dc4c4
--- /dev/null
+++ b/3d/first_person_shooter/materials/+0_tscrn1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://btjvp0uialdwa"]
+
+[ext_resource type="Texture2D" path="res://textures/+0_tscrn1.png" id="1_1ubex"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_1ubex")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+0basebtn_material.tres b/3d/first_person_shooter/materials/+0basebtn_material.tres
new file mode 100644
index 00000000000..6efb7806a24
--- /dev/null
+++ b/3d/first_person_shooter/materials/+0basebtn_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://cwg76u84d0c3j"]
+
+[ext_resource type="Texture2D" path="res://textures/+0basebtn.png" id="1_ly3hw"]
+[ext_resource type="Texture2D" path="res://textures/+0basebtn_emission.png" id="2_svocj"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_ly3hw")
+emission_enabled = true
+emission_texture = ExtResource("2_svocj")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+0tek_jump1_material.tres b/3d/first_person_shooter/materials/+0tek_jump1_material.tres
new file mode 100644
index 00000000000..208ce3b4077
--- /dev/null
+++ b/3d/first_person_shooter/materials/+0tek_jump1_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://c51xukbgpcsf2"]
+
+[ext_resource type="Texture2D" path="res://textures/+0tek_jump1.png" id="1_s3n4k"]
+[ext_resource type="Texture2D" path="res://textures/+0tek_jump1_emission.png" id="2_0f1wq"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_s3n4k")
+emission_enabled = true
+emission_texture = ExtResource("2_0f1wq")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+0term128_material.tres b/3d/first_person_shooter/materials/+0term128_material.tres
new file mode 100644
index 00000000000..938ffaf6fc0
--- /dev/null
+++ b/3d/first_person_shooter/materials/+0term128_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bhrm41cvml05o"]
+
+[ext_resource type="Texture2D" path="res://textures/+0term128.png" id="1_ckrmb"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_ckrmb")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+0tlight3_material.tres b/3d/first_person_shooter/materials/+0tlight3_material.tres
new file mode 100644
index 00000000000..7bfc77c63ba
--- /dev/null
+++ b/3d/first_person_shooter/materials/+0tlight3_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bdab6cy0td7ca"]
+
+[ext_resource type="Texture2D" path="res://textures/+0tlight3.png" id="1_v7da0"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_v7da0")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+1basebtn_material.tres b/3d/first_person_shooter/materials/+1basebtn_material.tres
new file mode 100644
index 00000000000..16839c773ea
--- /dev/null
+++ b/3d/first_person_shooter/materials/+1basebtn_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://d6iyd5o8bw45"]
+
+[ext_resource type="Texture2D" path="res://textures/+1basebtn.png" id="1_2570h"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_2570h")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+1tek_jump1_material.tres b/3d/first_person_shooter/materials/+1tek_jump1_material.tres
new file mode 100644
index 00000000000..f2d1e06b6ef
--- /dev/null
+++ b/3d/first_person_shooter/materials/+1tek_jump1_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://b5562a2vehl8y"]
+
+[ext_resource type="Texture2D" path="res://textures/+1tek_jump1.png" id="1_rljuw"]
+[ext_resource type="Texture2D" path="res://textures/+1tek_jump1_emission.png" id="2_ebjhm"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_rljuw")
+emission_enabled = true
+emission_texture = ExtResource("2_ebjhm")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+1term128_material.tres b/3d/first_person_shooter/materials/+1term128_material.tres
new file mode 100644
index 00000000000..b5da6b06382
--- /dev/null
+++ b/3d/first_person_shooter/materials/+1term128_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://ca7pcpngo5085"]
+
+[ext_resource type="Texture2D" path="res://textures/+1term128.png" id="1_02isl"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_02isl")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+a_tscrn0_material.tres b/3d/first_person_shooter/materials/+a_tscrn0_material.tres
new file mode 100644
index 00000000000..3349391e48d
--- /dev/null
+++ b/3d/first_person_shooter/materials/+a_tscrn0_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://mbavdiyhp60d"]
+
+[ext_resource type="Texture2D" path="res://textures/+a_tscrn0.png" id="1_u1s7k"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_u1s7k")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+a_tscrn1_material.tres b/3d/first_person_shooter/materials/+a_tscrn1_material.tres
new file mode 100644
index 00000000000..81abc69d7c6
--- /dev/null
+++ b/3d/first_person_shooter/materials/+a_tscrn1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://x3nr0ljp68mr"]
+
+[ext_resource type="Texture2D" path="res://textures/+a_tscrn1.png" id="1_52a6a"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_52a6a")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+a_tscrn2_material.tres b/3d/first_person_shooter/materials/+a_tscrn2_material.tres
new file mode 100644
index 00000000000..cc0ff173227
--- /dev/null
+++ b/3d/first_person_shooter/materials/+a_tscrn2_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bbv03vlbc1gsh"]
+
+[ext_resource type="Texture2D" path="res://textures/+a_tscrn2.png" id="1_w4obx"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_w4obx")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+abasebtn_material.tres b/3d/first_person_shooter/materials/+abasebtn_material.tres
new file mode 100644
index 00000000000..9df4a960abe
--- /dev/null
+++ b/3d/first_person_shooter/materials/+abasebtn_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://i652121h7i1a"]
+
+[ext_resource type="Texture2D" path="res://textures/+abasebtn.png" id="1_jp528"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_jp528")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+atek_jump1_material.tres b/3d/first_person_shooter/materials/+atek_jump1_material.tres
new file mode 100644
index 00000000000..749b1a02764
--- /dev/null
+++ b/3d/first_person_shooter/materials/+atek_jump1_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://bldycnihjgk5s"]
+
+[ext_resource type="Texture2D" path="res://textures/+atek_jump1.png" id="1_wy8vl"]
+[ext_resource type="Texture2D" path="res://textures/+atek_jump1_emission.png" id="2_l5gko"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_wy8vl")
+emission_enabled = true
+emission_texture = ExtResource("2_l5gko")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/+atlight3_material.tres b/3d/first_person_shooter/materials/+atlight3_material.tres
new file mode 100644
index 00000000000..9d52675a51c
--- /dev/null
+++ b/3d/first_person_shooter/materials/+atlight3_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://6i1qd3rr4q26"]
+
+[ext_resource type="Texture2D" path="res://textures/+atlight3.png" id="1_n4526"]
+[ext_resource type="Texture2D" path="res://textures/+atlight3_emission.png" id="2_ny1ky"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_n4526")
+emission_enabled = true
+emission_texture = ExtResource("2_ny1ky")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/afloor1_4_material.tres b/3d/first_person_shooter/materials/afloor1_4_material.tres
new file mode 100644
index 00000000000..296af210d3e
--- /dev/null
+++ b/3d/first_person_shooter/materials/afloor1_4_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://iktc56mk6ljr"]
+
+[ext_resource type="Texture2D" path="res://textures/afloor1_4.png" id="1_3qtcn"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_3qtcn")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/altar1_1_material.tres b/3d/first_person_shooter/materials/altar1_1_material.tres
new file mode 100644
index 00000000000..c5d73b5bb87
--- /dev/null
+++ b/3d/first_person_shooter/materials/altar1_1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://dmb13016o4vx5"]
+
+[ext_resource type="Texture2D" path="res://textures/altar1_1.png" id="1_hknui"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_hknui")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/altar1_3_material.tres b/3d/first_person_shooter/materials/altar1_3_material.tres
new file mode 100644
index 00000000000..04e5731f8eb
--- /dev/null
+++ b/3d/first_person_shooter/materials/altar1_3_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b3p1tqxjmr5c6"]
+
+[ext_resource type="Texture2D" path="res://textures/altar1_3.png" id="1_5737j"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_5737j")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/aqf032_material.tres b/3d/first_person_shooter/materials/aqf032_material.tres
new file mode 100644
index 00000000000..ff87ee239a1
--- /dev/null
+++ b/3d/first_person_shooter/materials/aqf032_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bkd0geqfktioq"]
+
+[ext_resource type="Texture2D" path="res://textures/aqf032.png" id="1_d4fw7"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_d4fw7")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/aqmetl01_material.tres b/3d/first_person_shooter/materials/aqmetl01_material.tres
new file mode 100644
index 00000000000..e078dabe8b8
--- /dev/null
+++ b/3d/first_person_shooter/materials/aqmetl01_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://c048jjup8hhr7"]
+
+[ext_resource type="Texture2D" path="res://textures/aqmetl01.png" id="1_y50d8"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_y50d8")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/aqmetl07_material.tres b/3d/first_person_shooter/materials/aqmetl07_material.tres
new file mode 100644
index 00000000000..86e2e6fbe89
--- /dev/null
+++ b/3d/first_person_shooter/materials/aqmetl07_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://g67ktcfcwo6d"]
+
+[ext_resource type="Texture2D" path="res://textures/aqmetl07.png" id="1_qebwu"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_qebwu")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/aqmetl28_material.tres b/3d/first_person_shooter/materials/aqmetl28_material.tres
new file mode 100644
index 00000000000..1ee3436e71c
--- /dev/null
+++ b/3d/first_person_shooter/materials/aqmetl28_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cmuivvki2vawl"]
+
+[ext_resource type="Texture2D" path="res://textures/aqmetl28.png" id="1_18j5u"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_18j5u")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/aqrust04_material.tres b/3d/first_person_shooter/materials/aqrust04_material.tres
new file mode 100644
index 00000000000..ce12492a36c
--- /dev/null
+++ b/3d/first_person_shooter/materials/aqrust04_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://co05u8v8dq0pf"]
+
+[ext_resource type="Texture2D" path="res://textures/aqrust04.png" id="1_qs1fn"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_qs1fn")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/aqsupp01_material.tres b/3d/first_person_shooter/materials/aqsupp01_material.tres
new file mode 100644
index 00000000000..dca9c528665
--- /dev/null
+++ b/3d/first_person_shooter/materials/aqsupp01_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://1oob1cbrex4n"]
+
+[ext_resource type="Texture2D" path="res://textures/aqsupp01.png" id="1_h7ftd"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_h7ftd")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/aqsupp06_material.tres b/3d/first_person_shooter/materials/aqsupp06_material.tres
new file mode 100644
index 00000000000..8cacd6b5027
--- /dev/null
+++ b/3d/first_person_shooter/materials/aqsupp06_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bjevgxcimyuxf"]
+
+[ext_resource type="Texture2D" path="res://textures/aqsupp06.png" id="1_fnvu4"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_fnvu4")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/aqtrim02_material.tres b/3d/first_person_shooter/materials/aqtrim02_material.tres
new file mode 100644
index 00000000000..a1cde1fb09e
--- /dev/null
+++ b/3d/first_person_shooter/materials/aqtrim02_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b0e7wodu8yf54"]
+
+[ext_resource type="Texture2D" path="res://textures/aqtrim02.png" id="1_p2mpx"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_p2mpx")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/aqtrim08_material.tres b/3d/first_person_shooter/materials/aqtrim08_material.tres
new file mode 100644
index 00000000000..eb407f87d88
--- /dev/null
+++ b/3d/first_person_shooter/materials/aqtrim08_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://c4yfnlh1nec0x"]
+
+[ext_resource type="Texture2D" path="res://textures/aqtrim08.png" id="1_r2k38"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_r2k38")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/black_material.tres b/3d/first_person_shooter/materials/black_material.tres
new file mode 100644
index 00000000000..036d6aaf615
--- /dev/null
+++ b/3d/first_person_shooter/materials/black_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://clu1ohti5m0k1"]
+
+[ext_resource type="Texture2D" path="res://textures/black.png" id="1_eoffp"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_eoffp")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/butmet_material.tres b/3d/first_person_shooter/materials/butmet_material.tres
new file mode 100644
index 00000000000..74f2b0edcf4
--- /dev/null
+++ b/3d/first_person_shooter/materials/butmet_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b5puq4rq6m1i2"]
+
+[ext_resource type="Texture2D" path="res://textures/butmet.png" id="1_g13r7"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_g13r7")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/comp1_1_material.tres b/3d/first_person_shooter/materials/comp1_1_material.tres
new file mode 100644
index 00000000000..4b6d643a0d5
--- /dev/null
+++ b/3d/first_person_shooter/materials/comp1_1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b0i6g7y6s6epc"]
+
+[ext_resource type="Texture2D" path="res://textures/comp1_1.png" id="1_27fh0"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_27fh0")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/comp1_2_material.tres b/3d/first_person_shooter/materials/comp1_2_material.tres
new file mode 100644
index 00000000000..afc18d28906
--- /dev/null
+++ b/3d/first_person_shooter/materials/comp1_2_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://ctk8fsu563npo"]
+
+[ext_resource type="Texture2D" path="res://textures/comp1_2.png" id="1_63hc2"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_63hc2")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/comp1_3_material.tres b/3d/first_person_shooter/materials/comp1_3_material.tres
new file mode 100644
index 00000000000..cdb5c40e671
--- /dev/null
+++ b/3d/first_person_shooter/materials/comp1_3_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bi3r74r8o6xsn"]
+
+[ext_resource type="Texture2D" path="res://textures/comp1_3.png" id="1_qvkyl"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_qvkyl")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/comp1_6_material.tres b/3d/first_person_shooter/materials/comp1_6_material.tres
new file mode 100644
index 00000000000..576f740470e
--- /dev/null
+++ b/3d/first_person_shooter/materials/comp1_6_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://g1nroq8cplla"]
+
+[ext_resource type="Texture2D" path="res://textures/comp1_6.png" id="1_xacwv"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_xacwv")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/compbase_material.tres b/3d/first_person_shooter/materials/compbase_material.tres
new file mode 100644
index 00000000000..c662ba409d8
--- /dev/null
+++ b/3d/first_person_shooter/materials/compbase_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cbr1frs14p670"]
+
+[ext_resource type="Texture2D" path="res://textures/compbase.png" id="1_1yhyg"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_1yhyg")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/crate0_s_bottom_material.tres b/3d/first_person_shooter/materials/crate0_s_bottom_material.tres
new file mode 100644
index 00000000000..04f5dc0502b
--- /dev/null
+++ b/3d/first_person_shooter/materials/crate0_s_bottom_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://blrgfnlg4xwru"]
+
+[ext_resource type="Texture2D" path="res://textures/crate0_s_bottom.png" id="1_jqk20"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_jqk20")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/crate0_s_sside_material.tres b/3d/first_person_shooter/materials/crate0_s_sside_material.tres
new file mode 100644
index 00000000000..1431cd11ded
--- /dev/null
+++ b/3d/first_person_shooter/materials/crate0_s_sside_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://d02kl6wlk4w7i"]
+
+[ext_resource type="Texture2D" path="res://textures/crate0_s_sside.png" id="1_3ajwb"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_3ajwb")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/crate0_s_top_material.tres b/3d/first_person_shooter/materials/crate0_s_top_material.tres
new file mode 100644
index 00000000000..0818fdcbdf9
--- /dev/null
+++ b/3d/first_person_shooter/materials/crate0_s_top_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bo6d8caosv6xa"]
+
+[ext_resource type="Texture2D" path="res://textures/crate0_s_top.png" id="1_qixu8"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_qixu8")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/crate0_s_tside_material.tres b/3d/first_person_shooter/materials/crate0_s_tside_material.tres
new file mode 100644
index 00000000000..b8e9bc815ca
--- /dev/null
+++ b/3d/first_person_shooter/materials/crate0_s_tside_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://das6j7wbf8kcf"]
+
+[ext_resource type="Texture2D" path="res://textures/crate0_s_tside.png" id="1_dtjle"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_dtjle")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/crate0_side_material.tres b/3d/first_person_shooter/materials/crate0_side_material.tres
new file mode 100644
index 00000000000..d0786d9f4fa
--- /dev/null
+++ b/3d/first_person_shooter/materials/crate0_side_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b76qel482gych"]
+
+[ext_resource type="Texture2D" path="res://textures/crate0_side.png" id="1_r24dt"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_r24dt")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/crate0_top_material.tres b/3d/first_person_shooter/materials/crate0_top_material.tres
new file mode 100644
index 00000000000..81d2b5dfe2a
--- /dev/null
+++ b/3d/first_person_shooter/materials/crate0_top_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://dd6fgotpoi21e"]
+
+[ext_resource type="Texture2D" path="res://textures/crate0_top.png" id="1_x5yfm"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_x5yfm")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/crate1_side_material.tres b/3d/first_person_shooter/materials/crate1_side_material.tres
new file mode 100644
index 00000000000..25d0be85843
--- /dev/null
+++ b/3d/first_person_shooter/materials/crate1_side_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://desawoamqtkah"]
+
+[ext_resource type="Texture2D" path="res://textures/crate1_side.png" id="1_42fn7"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_42fn7")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/crate1_top_material.tres b/3d/first_person_shooter/materials/crate1_top_material.tres
new file mode 100644
index 00000000000..6c62467de0a
--- /dev/null
+++ b/3d/first_person_shooter/materials/crate1_top_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://dlol8h582nebc"]
+
+[ext_resource type="Texture2D" path="res://textures/crate1_top.png" id="1_qbo44"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_qbo44")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/dem4_4_material.tres b/3d/first_person_shooter/materials/dem4_4_material.tres
new file mode 100644
index 00000000000..374cc42607c
--- /dev/null
+++ b/3d/first_person_shooter/materials/dem4_4_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b617ta2i7jg7p"]
+
+[ext_resource type="Texture2D" path="res://textures/dem4_4.png" id="1_jkqqh"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_jkqqh")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/door02_1_material.tres b/3d/first_person_shooter/materials/door02_1_material.tres
new file mode 100644
index 00000000000..d7a1d86ada3
--- /dev/null
+++ b/3d/first_person_shooter/materials/door02_1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://blfjkouhma3mt"]
+
+[ext_resource type="Texture2D" path="res://textures/door02_1.png" id="1_36kxd"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_36kxd")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/doortrak1_material.tres b/3d/first_person_shooter/materials/doortrak1_material.tres
new file mode 100644
index 00000000000..7089465899b
--- /dev/null
+++ b/3d/first_person_shooter/materials/doortrak1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b4aei353iuh8j"]
+
+[ext_resource type="Texture2D" path="res://textures/doortrak1.png" id="1_o4jrs"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_o4jrs")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/doortrak2_material.tres b/3d/first_person_shooter/materials/doortrak2_material.tres
new file mode 100644
index 00000000000..b1f809b0243
--- /dev/null
+++ b/3d/first_person_shooter/materials/doortrak2_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bkrvq3viene3q"]
+
+[ext_resource type="Texture2D" path="res://textures/doortrak2.png" id="1_xv8fs"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_xv8fs")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/edoor01_1_material.tres b/3d/first_person_shooter/materials/edoor01_1_material.tres
new file mode 100644
index 00000000000..7b697c5aa35
--- /dev/null
+++ b/3d/first_person_shooter/materials/edoor01_1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cgkiu112qt217"]
+
+[ext_resource type="Texture2D" path="res://textures/edoor01_1.png" id="1_08fsm"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_08fsm")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/edoor02_material.tres b/3d/first_person_shooter/materials/edoor02_material.tres
new file mode 100644
index 00000000000..42293b66d72
--- /dev/null
+++ b/3d/first_person_shooter/materials/edoor02_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cb7w38j6wmkik"]
+
+[ext_resource type="Texture2D" path="res://textures/edoor02.png" id="1_hbttf"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_hbttf")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/flat4_material.tres b/3d/first_person_shooter/materials/flat4_material.tres
new file mode 100644
index 00000000000..316dae375ce
--- /dev/null
+++ b/3d/first_person_shooter/materials/flat4_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bj3hftvbcqdu6"]
+
+[ext_resource type="Texture2D" path="res://textures/flat4.png" id="1_3qwvp"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_3qwvp")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/gravel1_material.tres b/3d/first_person_shooter/materials/gravel1_material.tres
new file mode 100644
index 00000000000..074f4ca0d70
--- /dev/null
+++ b/3d/first_person_shooter/materials/gravel1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://de565y0gan5f2"]
+
+[ext_resource type="Texture2D" path="res://textures/gravel1.png" id="1_1h5sa"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_1h5sa")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/hint_material.tres b/3d/first_person_shooter/materials/hint_material.tres
new file mode 100644
index 00000000000..57669a5c07c
--- /dev/null
+++ b/3d/first_person_shooter/materials/hint_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://mvbpgm0nxsdy"]
+
+[ext_resource type="Texture2D" path="res://textures/hint.png" id="1_rwau8"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_rwau8")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/hintskip_material.tres b/3d/first_person_shooter/materials/hintskip_material.tres
new file mode 100644
index 00000000000..77f5b28e3c3
--- /dev/null
+++ b/3d/first_person_shooter/materials/hintskip_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://btkqyxecn6024"]
+
+[ext_resource type="Texture2D" path="res://textures/hintskip.png" id="1_jlo6i"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_jlo6i")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/lasergrid_material.tres b/3d/first_person_shooter/materials/lasergrid_material.tres
new file mode 100644
index 00000000000..231f23b275a
--- /dev/null
+++ b/3d/first_person_shooter/materials/lasergrid_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bq6ssamyyu2wc"]
+
+[ext_resource type="Texture2D" path="res://textures/lasergrid.png" id="1_f1gil"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_f1gil")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/light2_material.tres b/3d/first_person_shooter/materials/light2_material.tres
new file mode 100644
index 00000000000..52b93d25fed
--- /dev/null
+++ b/3d/first_person_shooter/materials/light2_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://q353cjj7jkre"]
+
+[ext_resource type="Texture2D" path="res://textures/light2.png" id="1_guasw"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_guasw")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/lit8sfb_material.tres b/3d/first_person_shooter/materials/lit8sfb_material.tres
new file mode 100644
index 00000000000..c08f1c2a0ee
--- /dev/null
+++ b/3d/first_person_shooter/materials/lit8sfb_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://dmrqo4mxbdm4"]
+
+[ext_resource type="Texture2D" path="res://textures/lit8sfb.png" id="1_73k7m"]
+[ext_resource type="Texture2D" path="res://textures/lit8sfb_emission.png" id="2_2jyr2"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_73k7m")
+emission_enabled = true
+emission_texture = ExtResource("2_2jyr2")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/med_cmet4_material.tres b/3d/first_person_shooter/materials/med_cmet4_material.tres
new file mode 100644
index 00000000000..53bf2c4752c
--- /dev/null
+++ b/3d/first_person_shooter/materials/med_cmet4_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bfgvkrbqo64gx"]
+
+[ext_resource type="Texture2D" path="res://textures/med_cmet4.png" id="1_4m7qw"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_4m7qw")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/med_csl_stp1_material.tres b/3d/first_person_shooter/materials/med_csl_stp1_material.tres
new file mode 100644
index 00000000000..4c14fddd0f5
--- /dev/null
+++ b/3d/first_person_shooter/materials/med_csl_stp1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://3d83lcxcc4f6"]
+
+[ext_resource type="Texture2D" path="res://textures/med_csl_stp1.png" id="1_nlalk"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_nlalk")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/med_dbrick6b_material.tres b/3d/first_person_shooter/materials/med_dbrick6b_material.tres
new file mode 100644
index 00000000000..9d4f7fa8739
--- /dev/null
+++ b/3d/first_person_shooter/materials/med_dbrick6b_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b3wbj0rs503b1"]
+
+[ext_resource type="Texture2D" path="res://textures/med_dbrick6b.png" id="1_e5eba"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_e5eba")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/met2_material.tres b/3d/first_person_shooter/materials/met2_material.tres
new file mode 100644
index 00000000000..3419f3ccedd
--- /dev/null
+++ b/3d/first_person_shooter/materials/met2_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://c6l7fo5iehibb"]
+
+[ext_resource type="Texture2D" path="res://textures/met2.png" id="1_hfqhu"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_hfqhu")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/plat_side1_material.tres b/3d/first_person_shooter/materials/plat_side1_material.tres
new file mode 100644
index 00000000000..554f9bbb13e
--- /dev/null
+++ b/3d/first_person_shooter/materials/plat_side1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://c8ik35stuuyjf"]
+
+[ext_resource type="Texture2D" path="res://textures/plat_side1.png" id="1_crye5"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_crye5")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/plat_stem_material.tres b/3d/first_person_shooter/materials/plat_stem_material.tres
new file mode 100644
index 00000000000..e0f7f2e7451
--- /dev/null
+++ b/3d/first_person_shooter/materials/plat_stem_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://c3rwn07x70vnn"]
+
+[ext_resource type="Texture2D" path="res://textures/plat_stem.png" id="1_5dxs3"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_5dxs3")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/plat_top1_material.tres b/3d/first_person_shooter/materials/plat_top1_material.tres
new file mode 100644
index 00000000000..d44fe9a968b
--- /dev/null
+++ b/3d/first_person_shooter/materials/plat_top1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bg7pq550mnlbj"]
+
+[ext_resource type="Texture2D" path="res://textures/plat_top1.png" id="1_ym123"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_ym123")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/plat_top2_material.tres b/3d/first_person_shooter/materials/plat_top2_material.tres
new file mode 100644
index 00000000000..f4cb1ab64e9
--- /dev/null
+++ b/3d/first_person_shooter/materials/plat_top2_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://d8o8min8pe8b"]
+
+[ext_resource type="Texture2D" path="res://textures/plat_top2.png" id="1_hx3vc"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_hx3vc")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/rocks07_material.tres b/3d/first_person_shooter/materials/rocks07_material.tres
new file mode 100644
index 00000000000..e541c77a319
--- /dev/null
+++ b/3d/first_person_shooter/materials/rocks07_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bk4iheclfxsvt"]
+
+[ext_resource type="Texture2D" path="res://textures/rocks07.png" id="1_2xxlr"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_2xxlr")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/rocks11d_material.tres b/3d/first_person_shooter/materials/rocks11d_material.tres
new file mode 100644
index 00000000000..91cb28475c1
--- /dev/null
+++ b/3d/first_person_shooter/materials/rocks11d_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://do4xg36q6p3xl"]
+
+[ext_resource type="Texture2D" path="res://textures/rocks11d.png" id="1_bp53v"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_bp53v")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/rocks11e_material.tres b/3d/first_person_shooter/materials/rocks11e_material.tres
new file mode 100644
index 00000000000..df506950070
--- /dev/null
+++ b/3d/first_person_shooter/materials/rocks11e_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cexv6ctfha4au"]
+
+[ext_resource type="Texture2D" path="res://textures/rocks11e.png" id="1_qeoil"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_qeoil")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/rw33_3_material.tres b/3d/first_person_shooter/materials/rw33_3_material.tres
new file mode 100644
index 00000000000..bcb48a73d33
--- /dev/null
+++ b/3d/first_person_shooter/materials/rw33_3_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://psmtxvb840l"]
+
+[ext_resource type="Texture2D" path="res://textures/rw33_3.png" id="1_sgehg"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_sgehg")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/rw33_flat_material.tres b/3d/first_person_shooter/materials/rw33_flat_material.tres
new file mode 100644
index 00000000000..0b6033fac85
--- /dev/null
+++ b/3d/first_person_shooter/materials/rw33_flat_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b6pycfa2g76de"]
+
+[ext_resource type="Texture2D" path="res://textures/rw33_flat.png" id="1_p5kvy"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_p5kvy")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/rw33_lit_material.tres b/3d/first_person_shooter/materials/rw33_lit_material.tres
new file mode 100644
index 00000000000..667a27ae6b1
--- /dev/null
+++ b/3d/first_person_shooter/materials/rw33_lit_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://ca5otsyelikaq"]
+
+[ext_resource type="Texture2D" path="res://textures/rw33_lit.png" id="1_bkl1d"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_bkl1d")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/rw33b_1_material.tres b/3d/first_person_shooter/materials/rw33b_1_material.tres
new file mode 100644
index 00000000000..e1259b281cb
--- /dev/null
+++ b/3d/first_person_shooter/materials/rw33b_1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bwjmmg67koya1"]
+
+[ext_resource type="Texture2D" path="res://textures/rw33b_1.png" id="1_s46vc"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_s46vc")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/rw33b_flat_material.tres b/3d/first_person_shooter/materials/rw33b_flat_material.tres
new file mode 100644
index 00000000000..2b1203da200
--- /dev/null
+++ b/3d/first_person_shooter/materials/rw33b_flat_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cd3abmpjhl41a"]
+
+[ext_resource type="Texture2D" path="res://textures/rw33b_flat.png" id="1_pqxsk"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_pqxsk")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/sky5_material.tres b/3d/first_person_shooter/materials/sky5_material.tres
new file mode 100644
index 00000000000..f07270db0a7
--- /dev/null
+++ b/3d/first_person_shooter/materials/sky5_material.tres
@@ -0,0 +1,15 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://dy1ukw5bhiiru"]
+
+[ext_resource type="Texture2D" uid="uid://1a2kkt6fdovh" path="res://textures/sky5.png" id="1_ssyd2"]
+[ext_resource type="Texture2D" uid="uid://cc45vw80lpmhc" path="res://textures/sky5_emission.png" id="2_0s4ot"]
+
+[resource]
+transparency = 2
+alpha_scissor_threshold = 0.5
+alpha_antialiasing_mode = 0
+cull_mode = 1
+specular_mode = 2
+albedo_color = Color(1, 1, 1, 0)
+albedo_texture = ExtResource("1_ssyd2")
+emission_texture = ExtResource("2_0s4ot")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/slime2_material.tres b/3d/first_person_shooter/materials/slime2_material.tres
new file mode 100644
index 00000000000..0952080c05a
--- /dev/null
+++ b/3d/first_person_shooter/materials/slime2_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b2j7kv3mk7cy6"]
+
+[ext_resource type="Texture2D" path="res://textures/slime2.png" id="1_mmsra"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_mmsra")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/spotlight_material.tres b/3d/first_person_shooter/materials/spotlight_material.tres
new file mode 100644
index 00000000000..d7442e80f67
--- /dev/null
+++ b/3d/first_person_shooter/materials/spotlight_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://byxs5acmsfxkx"]
+
+[ext_resource type="Texture2D" path="res://textures/spotlight.png" id="1_ykc3o"]
+[ext_resource type="Texture2D" path="res://textures/spotlight_emission.png" id="2_bum7j"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_ykc3o")
+emission_enabled = true
+emission_texture = ExtResource("2_bum7j")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_band1a_material.tres b/3d/first_person_shooter/materials/t_band1a_material.tres
new file mode 100644
index 00000000000..cf44d98116f
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_band1a_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://c56e0p2u267qg"]
+
+[ext_resource type="Texture2D" path="res://textures/t_band1a.png" id="1_vbaaa"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_vbaaa")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_band1b_material.tres b/3d/first_person_shooter/materials/t_band1b_material.tres
new file mode 100644
index 00000000000..961809fbefa
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_band1b_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b65il8uft0bx3"]
+
+[ext_resource type="Texture2D" path="res://textures/t_band1b.png" id="1_svfn0"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_svfn0")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_blok01a_material.tres b/3d/first_person_shooter/materials/t_blok01a_material.tres
new file mode 100644
index 00000000000..b7652318056
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_blok01a_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://ctpfspt2l2iev"]
+
+[ext_resource type="Texture2D" path="res://textures/t_blok01a.png" id="1_jfto1"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_jfto1")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_blok02_material.tres b/3d/first_person_shooter/materials/t_blok02_material.tres
new file mode 100644
index 00000000000..017fe293ffb
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_blok02_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://d4diotvbo6n8v"]
+
+[ext_resource type="Texture2D" path="res://textures/t_blok02.png" id="1_qtiey"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_qtiey")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_blok02a_material.tres b/3d/first_person_shooter/materials/t_blok02a_material.tres
new file mode 100644
index 00000000000..9bcb76fd361
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_blok02a_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://c8i8lxlt18ap1"]
+
+[ext_resource type="Texture2D" path="res://textures/t_blok02a.png" id="1_n4vst"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_n4vst")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_blok03a_material.tres b/3d/first_person_shooter/materials/t_blok03a_material.tres
new file mode 100644
index 00000000000..22a33678240
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_blok03a_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bcuv2rugdj7dn"]
+
+[ext_resource type="Texture2D" path="res://textures/t_blok03a.png" id="1_0mplr"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_0mplr")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_blok04_material.tres b/3d/first_person_shooter/materials/t_blok04_material.tres
new file mode 100644
index 00000000000..987c55ad5fa
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_blok04_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cvrakl6hb1fej"]
+
+[ext_resource type="Texture2D" path="res://textures/t_blok04.png" id="1_4kqqf"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_4kqqf")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_blok05_material.tres b/3d/first_person_shooter/materials/t_blok05_material.tres
new file mode 100644
index 00000000000..4977f63c346
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_blok05_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://c0dwsdy4trjvn"]
+
+[ext_resource type="Texture2D" path="res://textures/t_blok05.png" id="1_jetoe"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_jetoe")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_blok06_material.tres b/3d/first_person_shooter/materials/t_blok06_material.tres
new file mode 100644
index 00000000000..8a96f60e526
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_blok06_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://5hijvrwjjcj4"]
+
+[ext_resource type="Texture2D" path="res://textures/t_blok06.png" id="1_jylbt"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_jylbt")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_blok07_material.tres b/3d/first_person_shooter/materials/t_blok07_material.tres
new file mode 100644
index 00000000000..053b011db06
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_blok07_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://c7xp461ruvmto"]
+
+[ext_resource type="Texture2D" path="res://textures/t_blok07.png" id="1_fbnpn"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_fbnpn")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_blok08_material.tres b/3d/first_person_shooter/materials/t_blok08_material.tres
new file mode 100644
index 00000000000..3835352b480
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_blok08_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cj07i411up4ew"]
+
+[ext_resource type="Texture2D" path="res://textures/t_blok08.png" id="1_k13im"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_k13im")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_blok09_material.tres b/3d/first_person_shooter/materials/t_blok09_material.tres
new file mode 100644
index 00000000000..ec69048aca2
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_blok09_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cpghardsxv0tq"]
+
+[ext_resource type="Texture2D" path="res://textures/t_blok09.png" id="1_qvqup"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_qvqup")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_blok10_material.tres b/3d/first_person_shooter/materials/t_blok10_material.tres
new file mode 100644
index 00000000000..f08dc2f5431
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_blok10_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://d1673jc0q643h"]
+
+[ext_resource type="Texture2D" path="res://textures/t_blok10.png" id="1_ay15h"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_ay15h")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_blok11b_material.tres b/3d/first_person_shooter/materials/t_blok11b_material.tres
new file mode 100644
index 00000000000..1ec458c9e8f
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_blok11b_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://rh2jiprvaw6y"]
+
+[ext_resource type="Texture2D" path="res://textures/t_blok11b.png" id="1_po57o"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_po57o")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_flat01_material.tres b/3d/first_person_shooter/materials/t_flat01_material.tres
new file mode 100644
index 00000000000..1fca9b9b1ba
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_flat01_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bbsuba6aiq1ws"]
+
+[ext_resource type="Texture2D" path="res://textures/t_flat01.png" id="1_27md0"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_27md0")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_flat02_material.tres b/3d/first_person_shooter/materials/t_flat02_material.tres
new file mode 100644
index 00000000000..0d76d027a8a
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_flat02_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://lptkiu4omqgj"]
+
+[ext_resource type="Texture2D" path="res://textures/t_flat02.png" id="1_16wlq"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_16wlq")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_flor1a_material.tres b/3d/first_person_shooter/materials/t_flor1a_material.tres
new file mode 100644
index 00000000000..70ff0d217a7
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_flor1a_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://dw2bcsbmnv047"]
+
+[ext_resource type="Texture2D" path="res://textures/t_flor1a.png" id="1_uggxk"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_uggxk")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_flor1b_material.tres b/3d/first_person_shooter/materials/t_flor1b_material.tres
new file mode 100644
index 00000000000..21477b05cfc
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_flor1b_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://c1l5p6tdsp23d"]
+
+[ext_resource type="Texture2D" path="res://textures/t_flor1b.png" id="1_faf4u"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_faf4u")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_flor2a_material.tres b/3d/first_person_shooter/materials/t_flor2a_material.tres
new file mode 100644
index 00000000000..a0a5e32c9f7
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_flor2a_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://by4n6ub5lcc8y"]
+
+[ext_resource type="Texture2D" path="res://textures/t_flor2a.png" id="1_gduj0"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_gduj0")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_lit01_material.tres b/3d/first_person_shooter/materials/t_lit01_material.tres
new file mode 100644
index 00000000000..966fb107ece
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_lit01_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://cjbc0rwfow1ik"]
+
+[ext_resource type="Texture2D" path="res://textures/t_lit01.png" id="1_lr6bq"]
+[ext_resource type="Texture2D" path="res://textures/t_lit01_emission.png" id="2_ebhnr"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_lr6bq")
+emission_enabled = true
+emission_texture = ExtResource("2_ebhnr")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_lit07_material.tres b/3d/first_person_shooter/materials/t_lit07_material.tres
new file mode 100644
index 00000000000..a85ccf0136f
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_lit07_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://wydp6idj2r6u"]
+
+[ext_resource type="Texture2D" path="res://textures/t_lit07.png" id="1_ec1wp"]
+[ext_resource type="Texture2D" path="res://textures/t_lit07_emission.png" id="2_phupk"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_ec1wp")
+emission_enabled = true
+emission_texture = ExtResource("2_phupk")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_lit08_material.tres b/3d/first_person_shooter/materials/t_lit08_material.tres
new file mode 100644
index 00000000000..8cb1ebf4282
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_lit08_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://dka0qi3loynef"]
+
+[ext_resource type="Texture2D" path="res://textures/t_lit08.png" id="1_c767y"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_c767y")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_metalsheeta_material.tres b/3d/first_person_shooter/materials/t_metalsheeta_material.tres
new file mode 100644
index 00000000000..03c5373abb9
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_metalsheeta_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://beq1ln12qj825"]
+
+[ext_resource type="Texture2D" path="res://textures/t_metalsheeta.png" id="1_47w3x"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_47w3x")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_rivs01a_material.tres b/3d/first_person_shooter/materials/t_rivs01a_material.tres
new file mode 100644
index 00000000000..8e70a357873
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_rivs01a_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://ct0i6c4k8y841"]
+
+[ext_resource type="Texture2D" path="res://textures/t_rivs01a.png" id="1_rgwjj"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_rgwjj")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_tech01_material.tres b/3d/first_person_shooter/materials/t_tech01_material.tres
new file mode 100644
index 00000000000..eb65aeee494
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_tech01_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bcii5u8vlch4r"]
+
+[ext_resource type="Texture2D" path="res://textures/t_tech01.png" id="1_i1hry"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_i1hry")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_tech02_material.tres b/3d/first_person_shooter/materials/t_tech02_material.tres
new file mode 100644
index 00000000000..f3c5e6fb91a
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_tech02_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b70x16b612b42"]
+
+[ext_resource type="Texture2D" path="res://textures/t_tech02.png" id="1_7cok5"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_7cok5")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_trim1aa_material.tres b/3d/first_person_shooter/materials/t_trim1aa_material.tres
new file mode 100644
index 00000000000..e4bf71bf819
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_trim1aa_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://csa4ea6p60rfy"]
+
+[ext_resource type="Texture2D" path="res://textures/t_trim1aa.png" id="1_fpbc6"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_fpbc6")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_trim1ba_material.tres b/3d/first_person_shooter/materials/t_trim1ba_material.tres
new file mode 100644
index 00000000000..1fb2fa2ec01
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_trim1ba_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bm0u61bqaodh2"]
+
+[ext_resource type="Texture2D" path="res://textures/t_trim1ba.png" id="1_s5e5f"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_s5e5f")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_trim1c_material.tres b/3d/first_person_shooter/materials/t_trim1c_material.tres
new file mode 100644
index 00000000000..2f06379e5b1
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_trim1c_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://c8fdw1mjssy72"]
+
+[ext_resource type="Texture2D" path="res://textures/t_trim1c.png" id="1_yrttd"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_yrttd")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_trim1ca_material.tres b/3d/first_person_shooter/materials/t_trim1ca_material.tres
new file mode 100644
index 00000000000..86cecb9ff4e
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_trim1ca_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://da1ag8aevu1ek"]
+
+[ext_resource type="Texture2D" path="res://textures/t_trim1ca.png" id="1_nm7vj"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_nm7vj")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_trim1d_material.tres b/3d/first_person_shooter/materials/t_trim1d_material.tres
new file mode 100644
index 00000000000..bcd14c4a014
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_trim1d_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://coakdk5rfp3u6"]
+
+[ext_resource type="Texture2D" path="res://textures/t_trim1d.png" id="1_eyhiu"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_eyhiu")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_trim1e_material.tres b/3d/first_person_shooter/materials/t_trim1e_material.tres
new file mode 100644
index 00000000000..312bc49d7a7
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_trim1e_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://ndnuton2rm7k"]
+
+[ext_resource type="Texture2D" path="res://textures/t_trim1e.png" id="1_wivj2"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_wivj2")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_trim2aa_material.tres b/3d/first_person_shooter/materials/t_trim2aa_material.tres
new file mode 100644
index 00000000000..463472b28a2
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_trim2aa_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bsegekxw5k2em"]
+
+[ext_resource type="Texture2D" path="res://textures/t_trim2aa.png" id="1_m8pf0"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_m8pf0")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_trim2ba_material.tres b/3d/first_person_shooter/materials/t_trim2ba_material.tres
new file mode 100644
index 00000000000..4b48c26e854
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_trim2ba_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://itblnfuh1twf"]
+
+[ext_resource type="Texture2D" path="res://textures/t_trim2ba.png" id="1_gjbgw"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_gjbgw")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_trim2ca_material.tres b/3d/first_person_shooter/materials/t_trim2ca_material.tres
new file mode 100644
index 00000000000..a630068db52
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_trim2ca_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://l3k3nqwx5lu8"]
+
+[ext_resource type="Texture2D" path="res://textures/t_trim2ca.png" id="1_5w0wc"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_5w0wc")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_trim2d_material.tres b/3d/first_person_shooter/materials/t_trim2d_material.tres
new file mode 100644
index 00000000000..e1b1bd943a2
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_trim2d_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://28kpvu01hpou"]
+
+[ext_resource type="Texture2D" path="res://textures/t_trim2d.png" id="1_5b6et"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_5b6et")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_trim2e_material.tres b/3d/first_person_shooter/materials/t_trim2e_material.tres
new file mode 100644
index 00000000000..fb492d30693
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_trim2e_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://c1nmvxt3nss57"]
+
+[ext_resource type="Texture2D" path="res://textures/t_trim2e.png" id="1_ut4nc"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_ut4nc")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_tris02_material.tres b/3d/first_person_shooter/materials/t_tris02_material.tres
new file mode 100644
index 00000000000..c2b552413c9
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_tris02_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cmxul787b3f5"]
+
+[ext_resource type="Texture2D" path="res://textures/t_tris02.png" id="1_1w57o"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_1w57o")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_wall05_material.tres b/3d/first_person_shooter/materials/t_wall05_material.tres
new file mode 100644
index 00000000000..b291518b057
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_wall05_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://q0broom3f8qt"]
+
+[ext_resource type="Texture2D" path="res://textures/t_wall05.png" id="1_62wk0"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_62wk0")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_wall1a_material.tres b/3d/first_person_shooter/materials/t_wall1a_material.tres
new file mode 100644
index 00000000000..68e9b0f4e1c
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_wall1a_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bwfule7d725pw"]
+
+[ext_resource type="Texture2D" path="res://textures/t_wall1a.png" id="1_nshps"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_nshps")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_wall1aa_material.tres b/3d/first_person_shooter/materials/t_wall1aa_material.tres
new file mode 100644
index 00000000000..83572025aba
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_wall1aa_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bogwexpicc4mq"]
+
+[ext_resource type="Texture2D" path="res://textures/t_wall1aa.png" id="1_274am"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_274am")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_wall1b_material.tres b/3d/first_person_shooter/materials/t_wall1b_material.tres
new file mode 100644
index 00000000000..0bea10d94a1
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_wall1b_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://djt8tbwpt57os"]
+
+[ext_resource type="Texture2D" path="res://textures/t_wall1b.png" id="1_c68q0"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_c68q0")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_wall1ba_material.tres b/3d/first_person_shooter/materials/t_wall1ba_material.tres
new file mode 100644
index 00000000000..c793a95ef85
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_wall1ba_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://x5irsg820sfm"]
+
+[ext_resource type="Texture2D" path="res://textures/t_wall1ba.png" id="1_vjnry"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_vjnry")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_wall2a_material.tres b/3d/first_person_shooter/materials/t_wall2a_material.tres
new file mode 100644
index 00000000000..5c46c5b1500
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_wall2a_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bhrew2oxyjftf"]
+
+[ext_resource type="Texture2D" path="res://textures/t_wall2a.png" id="1_bo5jy"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_bo5jy")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_wall2aa_material.tres b/3d/first_person_shooter/materials/t_wall2aa_material.tres
new file mode 100644
index 00000000000..c8d06b41715
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_wall2aa_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cmd02lt7kt4ky"]
+
+[ext_resource type="Texture2D" path="res://textures/t_wall2aa.png" id="1_mxyig"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_mxyig")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_wall2ab_material.tres b/3d/first_person_shooter/materials/t_wall2ab_material.tres
new file mode 100644
index 00000000000..49ea39d60fd
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_wall2ab_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://ovlnm2viphyf"]
+
+[ext_resource type="Texture2D" path="res://textures/t_wall2ab.png" id="1_lkynw"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_lkynw")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_wall2b_material.tres b/3d/first_person_shooter/materials/t_wall2b_material.tres
new file mode 100644
index 00000000000..fc9a5e09c99
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_wall2b_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://4ls2tavqjo66"]
+
+[ext_resource type="Texture2D" path="res://textures/t_wall2b.png" id="1_66u6y"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_66u6y")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_wall2ba_material.tres b/3d/first_person_shooter/materials/t_wall2ba_material.tres
new file mode 100644
index 00000000000..eebbbee4e15
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_wall2ba_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://dqb1apxpq6nqd"]
+
+[ext_resource type="Texture2D" path="res://textures/t_wall2ba.png" id="1_oyy80"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_oyy80")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_wall3aa_material.tres b/3d/first_person_shooter/materials/t_wall3aa_material.tres
new file mode 100644
index 00000000000..91fef5062eb
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_wall3aa_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://catpkvd8j7vwx"]
+
+[ext_resource type="Texture2D" path="res://textures/t_wall3aa.png" id="1_q38fr"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_q38fr")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_wall3b_material.tres b/3d/first_person_shooter/materials/t_wall3b_material.tres
new file mode 100644
index 00000000000..1edf7426348
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_wall3b_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cd7acoo82xkdg"]
+
+[ext_resource type="Texture2D" path="res://textures/t_wall3b.png" id="1_r7voi"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_r7voi")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/t_wall3ba_material.tres b/3d/first_person_shooter/materials/t_wall3ba_material.tres
new file mode 100644
index 00000000000..58990ab8823
--- /dev/null
+++ b/3d/first_person_shooter/materials/t_wall3ba_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://ekp8wjkwb5ig"]
+
+[ext_resource type="Texture2D" path="res://textures/t_wall3ba.png" id="1_71glr"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_71glr")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/tek_door1_material.tres b/3d/first_person_shooter/materials/tek_door1_material.tres
new file mode 100644
index 00000000000..ac3c0a4247c
--- /dev/null
+++ b/3d/first_person_shooter/materials/tek_door1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://dwqwxmf1sxk6e"]
+
+[ext_resource type="Texture2D" path="res://textures/tek_door1.png" id="1_ndcuc"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_ndcuc")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/tek_flr3_material.tres b/3d/first_person_shooter/materials/tek_flr3_material.tres
new file mode 100644
index 00000000000..edb054fd13a
--- /dev/null
+++ b/3d/first_person_shooter/materials/tek_flr3_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bo1hbqq2hcte1"]
+
+[ext_resource type="Texture2D" path="res://textures/tek_flr3.png" id="1_2s317"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_2s317")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/tek_grate_material.tres b/3d/first_person_shooter/materials/tek_grate_material.tres
new file mode 100644
index 00000000000..824c424a0f5
--- /dev/null
+++ b/3d/first_person_shooter/materials/tek_grate_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b5fn4ewmyey6m"]
+
+[ext_resource type="Texture2D" path="res://textures/tek_grate.png" id="1_etcji"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_etcji")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/tek_lit3_material.tres b/3d/first_person_shooter/materials/tek_lit3_material.tres
new file mode 100644
index 00000000000..bf91fb2a8d7
--- /dev/null
+++ b/3d/first_person_shooter/materials/tek_lit3_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://bkkeiknlvio1a"]
+
+[ext_resource type="Texture2D" path="res://textures/tek_lit3.png" id="1_d4rjj"]
+[ext_resource type="Texture2D" path="res://textures/tek_lit3_emission.png" id="2_dlrmu"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_d4rjj")
+emission_enabled = true
+emission_texture = ExtResource("2_dlrmu")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/tek_lit4_material.tres b/3d/first_person_shooter/materials/tek_lit4_material.tres
new file mode 100644
index 00000000000..3bdc5746499
--- /dev/null
+++ b/3d/first_person_shooter/materials/tek_lit4_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://cvfa0sd0sgseh"]
+
+[ext_resource type="Texture2D" path="res://textures/tek_lit4.png" id="1_er5xt"]
+[ext_resource type="Texture2D" path="res://textures/tek_lit4_emission.png" id="2_2l5b8"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_er5xt")
+emission_enabled = true
+emission_texture = ExtResource("2_2l5b8")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/tek_pipe2_material.tres b/3d/first_person_shooter/materials/tek_pipe2_material.tres
new file mode 100644
index 00000000000..e601c270cf8
--- /dev/null
+++ b/3d/first_person_shooter/materials/tek_pipe2_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://ca5os8kxfhmdy"]
+
+[ext_resource type="Texture2D" path="res://textures/tek_pipe2.png" id="1_6udb6"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_6udb6")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/tele3_material.tres b/3d/first_person_shooter/materials/tele3_material.tres
new file mode 100644
index 00000000000..d2441aba8df
--- /dev/null
+++ b/3d/first_person_shooter/materials/tele3_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://8swovpo3a1rt"]
+
+[ext_resource type="Texture2D" path="res://textures/tele3.png" id="1_tbj7g"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_tbj7g")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/tele_frame1_material.tres b/3d/first_person_shooter/materials/tele_frame1_material.tres
new file mode 100644
index 00000000000..28fc92bdcfc
--- /dev/null
+++ b/3d/first_person_shooter/materials/tele_frame1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://m08c184ihhsg"]
+
+[ext_resource type="Texture2D" path="res://textures/tele_frame1.png" id="1_ulh36"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_ulh36")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/tele_frame3_material.tres b/3d/first_person_shooter/materials/tele_frame3_material.tres
new file mode 100644
index 00000000000..4fb9eef6a1f
--- /dev/null
+++ b/3d/first_person_shooter/materials/tele_frame3_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://b7x6ky2asxl3f"]
+
+[ext_resource type="Texture2D" path="res://textures/tele_frame3.png" id="1_v1cy5"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_v1cy5")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/telepad1_material.tres b/3d/first_person_shooter/materials/telepad1_material.tres
new file mode 100644
index 00000000000..26b18ccb46c
--- /dev/null
+++ b/3d/first_person_shooter/materials/telepad1_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://ulgkbex0rr3v"]
+
+[ext_resource type="Texture2D" path="res://textures/telepad1.png" id="1_n6kty"]
+[ext_resource type="Texture2D" path="res://textures/telepad1_emission.png" id="2_lxxfq"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_n6kty")
+emission_enabled = true
+emission_texture = ExtResource("2_lxxfq")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/tlight11_material.tres b/3d/first_person_shooter/materials/tlight11_material.tres
new file mode 100644
index 00000000000..63cf7232a74
--- /dev/null
+++ b/3d/first_person_shooter/materials/tlight11_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://ddt83jo1l5122"]
+
+[ext_resource type="Texture2D" path="res://textures/tlight11.png" id="1_dlebb"]
+[ext_resource type="Texture2D" path="res://textures/tlight11_emission.png" id="2_6ofie"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_dlebb")
+emission_enabled = true
+emission_texture = ExtResource("2_6ofie")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/tlight13_material.tres b/3d/first_person_shooter/materials/tlight13_material.tres
new file mode 100644
index 00000000000..ee1da651da6
--- /dev/null
+++ b/3d/first_person_shooter/materials/tlight13_material.tres
@@ -0,0 +1,11 @@
+[gd_resource type="StandardMaterial3D" load_steps=3 format=3 uid="uid://vsg4deohoq8h"]
+
+[ext_resource type="Texture2D" path="res://textures/tlight13.png" id="1_f8ygc"]
+[ext_resource type="Texture2D" path="res://textures/tlight13_emission.png" id="2_1t1f4"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_f8ygc")
+emission_enabled = true
+emission_texture = ExtResource("2_1t1f4")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/treadplatemetal_material.tres b/3d/first_person_shooter/materials/treadplatemetal_material.tres
new file mode 100644
index 00000000000..07c61127e14
--- /dev/null
+++ b/3d/first_person_shooter/materials/treadplatemetal_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cyx6ffcggeo70"]
+
+[ext_resource type="Texture2D" path="res://textures/treadplatemetal.png" id="1_m01bk"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_m01bk")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/uwall1_2_material.tres b/3d/first_person_shooter/materials/uwall1_2_material.tres
new file mode 100644
index 00000000000..2e08b700821
--- /dev/null
+++ b/3d/first_person_shooter/materials/uwall1_2_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://dgu5jtpnpo75s"]
+
+[ext_resource type="Texture2D" path="res://textures/uwall1_2.png" id="1_38dgy"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_38dgy")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/w17_1_material.tres b/3d/first_person_shooter/materials/w17_1_material.tres
new file mode 100644
index 00000000000..1224c871571
--- /dev/null
+++ b/3d/first_person_shooter/materials/w17_1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://bgflobywn4e7o"]
+
+[ext_resource type="Texture2D" path="res://textures/w17_1.png" id="1_4nmxp"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_4nmxp")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/water0_material.tres b/3d/first_person_shooter/materials/water0_material.tres
new file mode 100644
index 00000000000..c0b49adff08
--- /dev/null
+++ b/3d/first_person_shooter/materials/water0_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://d1xqjdsva0tvu"]
+
+[ext_resource type="Texture2D" path="res://textures/water0.png" id="1_vb1ou"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_vb1ou")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/water4_material.tres b/3d/first_person_shooter/materials/water4_material.tres
new file mode 100644
index 00000000000..38e1e82553a
--- /dev/null
+++ b/3d/first_person_shooter/materials/water4_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://cyuu4hpckctsc"]
+
+[ext_resource type="Texture2D" path="res://textures/water4.png" id="1_e33e1"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_e33e1")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/wbrick1_5_material.tres b/3d/first_person_shooter/materials/wbrick1_5_material.tres
new file mode 100644
index 00000000000..9f238626008
--- /dev/null
+++ b/3d/first_person_shooter/materials/wbrick1_5_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://2qhg3nfsfglp"]
+
+[ext_resource type="Texture2D" path="res://textures/wbrick1_5.png" id="1_4g8dj"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_4g8dj")
+texture_filter = 0
diff --git a/3d/first_person_shooter/materials/wswamp2_1_material.tres b/3d/first_person_shooter/materials/wswamp2_1_material.tres
new file mode 100644
index 00000000000..48bc7bd1496
--- /dev/null
+++ b/3d/first_person_shooter/materials/wswamp2_1_material.tres
@@ -0,0 +1,8 @@
+[gd_resource type="StandardMaterial3D" load_steps=2 format=3 uid="uid://doaikdcwnwhq3"]
+
+[ext_resource type="Texture2D" path="res://textures/wswamp2_1.png" id="1_fvksk"]
+
+[resource]
+specular_mode = 2
+albedo_texture = ExtResource("1_fvksk")
+texture_filter = 0
diff --git a/3d/first_person_shooter/platform.gd b/3d/first_person_shooter/platform.gd
new file mode 100644
index 00000000000..f69028fa68f
--- /dev/null
+++ b/3d/first_person_shooter/platform.gd
@@ -0,0 +1,52 @@
+extends StaticBody3D
+
+## Distance to travel upwards in units.
+@export var distance := 20.0
+
+## Speed in units per second.
+@export var speed := 9.0
+
+# The current platform's speed.
+# Positive: going upwards, negative: going downwards, zero: stopped.
+var velocity := 0.0
+
+# If `true`, a player is currently on the platform.
+var player_on_platform := false
+
+@onready var initial_height := position.y
+
+func _physics_process(delta: float) -> void:
+ position.y = clamp(position.y + velocity * delta, initial_height, initial_height + distance)
+
+ if is_equal_approx(position.y, initial_height):
+ # Reached the bottom.
+ velocity = 0.0
+
+ if is_equal_approx(position.y, initial_height + distance):
+ # Reached the top.
+ velocity = 0.0
+ if $Timer.is_stopped():
+ # Start timer that will make the platform go back down when timing out.
+ $Timer.start()
+
+
+func _on_move_trigger_body_entered(body: Node3D) -> void:
+ if body is Player:
+ player_on_platform = true
+ if velocity >= 0.0:
+ velocity = speed
+
+
+func _on_move_trigger_body_exited(_body: Node3D) -> void:
+ player_on_platform = false
+ if is_zero_approx(velocity) and is_zero_approx($Timer.get_time_left()):
+ # If the timer already expired, start going downwards immediately.
+ velocity = -speed
+
+
+func _on_timer_timeout() -> void:
+ # Only move downwards if the player is not currently on the platform.
+ # This allows the player to stay indefinitely on a fully raised platform,
+ # as long as they don't leave it.
+ if not player_on_platform:
+ velocity = -speed
diff --git a/3d/first_person_shooter/platform.gd.uid b/3d/first_person_shooter/platform.gd.uid
new file mode 100644
index 00000000000..b75cb37b1f0
--- /dev/null
+++ b/3d/first_person_shooter/platform.gd.uid
@@ -0,0 +1 @@
+uid://b6ug4qlgmpmrc
diff --git a/3d/first_person_shooter/platform.tscn b/3d/first_person_shooter/platform.tscn
new file mode 100644
index 00000000000..67c6588e78a
--- /dev/null
+++ b/3d/first_person_shooter/platform.tscn
@@ -0,0 +1,76 @@
+[gd_scene load_steps=11 format=3 uid="uid://c8n2cdrjonibs"]
+
+[ext_resource type="Script" uid="uid://b6ug4qlgmpmrc" path="res://platform.gd" id="1_g3ryg"]
+
+[sub_resource type="BoxShape3D" id="BoxShape3D_6hjjg"]
+size = Vector3(6, 0.5, 4)
+
+[sub_resource type="BoxMesh" id="BoxMesh_tg3xl"]
+size = Vector3(6, 0.5, 4)
+
+[sub_resource type="FastNoiseLite" id="FastNoiseLite_vemq1"]
+fractal_type = 2
+fractal_lacunarity = 16.782
+fractal_gain = 1.4
+
+[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_nepn7"]
+seamless = true
+noise = SubResource("FastNoiseLite_vemq1")
+
+[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_w2v74"]
+seamless = true
+as_normal_map = true
+bump_strength = 0.1
+noise = SubResource("FastNoiseLite_vemq1")
+
+[sub_resource type="Gradient" id="Gradient_soa80"]
+colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
+
+[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_rmhqn"]
+seamless = true
+color_ramp = SubResource("Gradient_soa80")
+noise = SubResource("FastNoiseLite_vemq1")
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_y10mx"]
+albedo_color = Color(0.65, 1, 0.743333, 1)
+albedo_texture = SubResource("NoiseTexture2D_nepn7")
+roughness = 0.5
+roughness_texture = SubResource("NoiseTexture2D_rmhqn")
+normal_enabled = true
+normal_texture = SubResource("NoiseTexture2D_w2v74")
+uv1_scale = Vector3(1.125, 0.5, 1)
+uv1_triplanar_sharpness = 15.455
+texture_filter = 4
+
+[sub_resource type="BoxShape3D" id="BoxShape3D_ekrg2"]
+size = Vector3(4, 2, 2)
+
+[node name="Platform" type="StaticBody3D"]
+script = ExtResource("1_g3ryg")
+
+[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
+shape = SubResource("BoxShape3D_6hjjg")
+
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
+layers = 2
+mesh = SubResource("BoxMesh_tg3xl")
+surface_material_override/0 = SubResource("StandardMaterial3D_y10mx")
+
+[node name="GPUParticlesCollisionBox3D" type="GPUParticlesCollisionBox3D" parent="."]
+size = Vector3(6, 0.5, 4)
+
+[node name="MoveTrigger" type="Area3D" parent="."]
+collision_layer = 2
+collision_mask = 2
+
+[node name="CollisionShape3D" type="CollisionShape3D" parent="MoveTrigger"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.25, 0)
+shape = SubResource("BoxShape3D_ekrg2")
+
+[node name="Timer" type="Timer" parent="."]
+wait_time = 2.5
+one_shot = true
+
+[connection signal="body_entered" from="MoveTrigger" to="." method="_on_move_trigger_body_entered"]
+[connection signal="body_exited" from="MoveTrigger" to="." method="_on_move_trigger_body_exited"]
+[connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"]
diff --git a/3d/first_person_shooter/player.gd b/3d/first_person_shooter/player.gd
new file mode 100644
index 00000000000..e8f15c6353a
--- /dev/null
+++ b/3d/first_person_shooter/player.gd
@@ -0,0 +1,316 @@
+class_name Player
+extends CharacterBody3D
+
+## Keyboard/gamepad look sensitivity.
+const LOOK_SENSITIVITY = 4.0
+
+## Mouse sensitivity.
+const MOUSE_SENSITIVITY = 0.0005
+
+## Minimum view pitch.
+const MIN_VIEW_PITCH = -TAU * 0.249
+
+## Maximum view pitch.
+const MAX_VIEW_PITCH = TAU * 0.249
+
+## Base speed multiplier.
+const SPEED = 1.0
+
+## Jump speed (affects how high you jump).
+const JUMP_VELOCITY = 10.0
+
+## How fast you accelerate while airborne. This influences maximum movement speed too.
+const AIR_ACCELERATION_FACTOR = 0.27
+
+## How fast you accelerate while in water. This influences maximum movement speed too.
+const WATER_ACCELERATION_FACTOR = 0.55
+
+## How strong gravity is underwater, compared to the default gravity (1.0 is full gravity).
+const WATER_GRAVITY_FACTOR = 0.1
+
+## Maximum upwards vertical speed allowed while in water.
+const WATER_DAMPING_FLOAT = 5.0
+
+## Maximum downwards vertical speed allowed while in water.
+const WATER_DAMPING_SINK = 2.5
+
+## How fast you swim upwards while pressing the Jump key underwater.
+const WATER_JUMP_SPEED = 25.0
+
+## How fast the camera recovers from falling (bobbing effect). Higher values result in faster recovery.
+const BOB_FALL_RECOVER_SPEED = 9.0
+
+## Number of bullets fired by the weapon.
+const SHOTGUN_BULLET_COUNT = 16
+
+## How far away the player is moved when firing their weapon.
+const WEAPON_KICKBACK_FORCE = 5.0
+
+const GRADIENT := preload("res://player/crosshair_health_gradient.tres")
+
+## The number of health points the player currently has.
+var health: int = 100:
+ set(value):
+ if value < health:
+ # Player was hurt.
+ # Increase opacity of damage overlay and tilt camera according to damage received.
+ $DamageEffect.modulate.a = clampf($DamageEffect.modulate.a + (health - value) * 0.05, 0.0, 1.0)
+ damage_roll += 0.005 * (health - value)
+
+ health = value
+ $HUD/Health.text = "Health: %d" % health
+ # Set crosshair color according to health, which is defined using a Gradient resource.
+ # This allows adjusting color along a predefined gradient without manually performing the math.
+ var crosshair_color := GRADIENT.sample(remap(health, 0, 100, 0.0, 1.0))
+ # Don't override alpha channel as this is done based on current weapon state in `_process()`.
+ $Crosshair.modulate.r = crosshair_color.r
+ $Crosshair.modulate.g = crosshair_color.g
+ $Crosshair.modulate.b = crosshair_color.b
+
+ if health <= 0:
+ die()
+
+# Time counter for view bobbing (doesn't increment while airborne).
+var bob_cycle_counter := 0.0
+# Fall impact accumulator for camera landing effect.
+var bob_fall_counter := 0.0
+# Fall impact accumulator for camera landing effect.
+var bob_fall_increment := 0.0
+
+# Additional camera roll to apply (damage effect, reduced over time).
+var damage_roll := 0.0
+
+# `true` if the player is currently touching a ground (not a steep slope or wall), `false` otherwise.
+var touching_ground := false
+
+# `true` if the player is currently in water, `false` otherwise.
+var in_water := false:
+ set(value):
+ if value != in_water:
+ # Water state has changed, play sound accordingly.
+ if value:
+ $WaterInSound.play()
+ else:
+ $WaterOutSound.play()
+
+ in_water = value
+
+# The height of the water plane the player is currently in (in global Y coordinates).
+# This is used to check whether the camera is underwater to apply effects.
+# When not in water, this is set to negative infinity to ensure checks against it are always `false`.
+var water_plane_y := -INF
+
+var base_height: int = ProjectSettings.get_setting("display/window/size/viewport_height")
+
+# Get the gravity from the project settings to be synced with RigidBody nodes.
+var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
+
+@onready var initial_camera_position: Vector3 = $Camera3D.position
+@onready var initial_weapon_sprite_position: Vector3 = $Camera3D/WeaponSprite.position
+@onready var initial_underwater_color: Color = $UnderwaterEffect.color
+
+
+func _ready() -> void:
+ Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
+
+ # V-Sync is disabled to reduce input lag. To avoid excessive power consumption,
+ # FPS is capped to (roughly) the refresh rate of the fastest monitor on the system.
+ var highest_refresh_rate := 60.0
+ for screen in DisplayServer.get_screen_count():
+ highest_refresh_rate = max(highest_refresh_rate, DisplayServer.screen_get_refresh_rate(screen))
+ Engine.max_fps = int(highest_refresh_rate) + 2
+
+ # Prevent underwater and damage effect "out" transitions from playing on scene load.
+ $UnderwaterEffect.color = Color.TRANSPARENT
+ $DamageEffect.modulate.a = 0.0
+
+
+func _physics_process(delta: float) -> void:
+ touching_ground = $ShapeCast3D.is_colliding() and $ShapeCast3D.get_collision_normal(0).dot(Vector3.UP) > 0.6
+
+ # Camera effects (view bobbing).
+
+ if false:
+ # FIXME: Find a way to detect vertical player speed.
+ # We've just landed, apply landing increase.
+ print("fall")
+ bob_fall_increment += 0.1
+
+ # Increase landing offset over time, but decrease both the landing increment and the offset.
+ # This leads to a parabola-like appearance of the landing effect: the effect increases progressively,
+ # then decreases progressively.
+ bob_fall_counter += bob_fall_increment
+ bob_fall_increment = lerpf(bob_fall_increment, 0.0, BOB_FALL_RECOVER_SPEED * delta)
+
+ if touching_ground or in_water:
+ # Don't bob camera and weapon sprite while airborne.
+ bob_cycle_counter += delta
+
+ # Perform view bobbing based on horizontal movement speed, and also apply the fall bobbing offset.
+ # We can't use `v_offset` as it would depend on view pitch.
+ if health >= 1:
+ $Camera3D.position.y = initial_camera_position.y + sin(bob_cycle_counter * 10) * 0.01 * Vector3(velocity.x, 0, velocity.z).length() - bob_fall_counter
+ else:
+ # Put camera near the floor level while dead.
+ $Camera3D.position.y = -0.65
+
+ # Perform weapon sprite bobbing (horizontal and vertical), and also apply the fall bobbing offset on the weapon sprite.
+ $Camera3D/WeaponSprite.position.x = initial_weapon_sprite_position.x + cos(bob_cycle_counter * 10) * 0.002 * Vector3(velocity.x, 0, velocity.z).length()
+ $Camera3D/WeaponSprite.position.y = initial_weapon_sprite_position.y - cos(sin(bob_cycle_counter * 10)) * 0.005 * Vector3(velocity.x, 0, velocity.z).length() - bob_fall_counter * 15
+
+ # Reduce fall bobbing offset over time.
+ bob_fall_counter = lerpf(bob_fall_counter, 0.0, BOB_FALL_RECOVER_SPEED * delta)
+
+ # Roll the camera based on sideways movement speed.
+ var roll := velocity.dot($Camera3D.global_transform.basis.x)
+ if health >= 1:
+ $Camera3D.rotation.z = -roll * 0.003 + damage_roll
+ else:
+ # Roll camera permanently and hide the weapon sprite when dead.
+ $Camera3D.rotation.z = deg_to_rad(-75)
+ $Camera3D/WeaponSprite.visible = false
+
+ # Character controller.
+
+ # We don't use `is_on_floor()` and rely on the ShapeCast3D's results to determine
+ # whether the player is on the floor. This is because we need to use the same check
+ # for stair climbing (to avoid discrepancies between both functions).
+
+ # Add the gravity (and perform damping if in water).
+ if not touching_ground:
+ if in_water:
+ # Lower gravity while in water.
+ velocity.y -= WATER_GRAVITY_FACTOR * gravity * delta
+ # Perform damping for vertical speed while in water.
+ velocity.y = clampf(velocity.y, -WATER_DAMPING_SINK, WATER_DAMPING_FLOAT)
+ else:
+ velocity.y -= gravity * delta
+
+
+ if health >= 1 and Input.is_action_pressed("jump") and (in_water or touching_ground):
+ # Only allow jumping while alive.
+ if in_water:
+ # Allow jumping while in water to swim upwards, but more slowly.
+ # Here, jumping is performed every frame if underwater, so multiply it by `delta`.
+ velocity.y += WATER_JUMP_SPEED * delta
+ else:
+ velocity.y = JUMP_VELOCITY
+
+ # Get the input direction and handle the movement/deceleration.
+ var input_dir := Vector2()
+ if health >= 1:
+ input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_backward")
+ else:
+ # Don't allow player movement while dead, but still process gravity and water damping.
+ input_dir = Vector2()
+
+ var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
+ var motion := Vector3()
+ if direction:
+ motion.x = direction.x * SPEED
+ motion.z = direction.z * SPEED
+
+ motion = motion.rotated(Vector3.UP, $Camera3D.rotation.y)
+
+ if Input.is_action_pressed(&"walk"):
+ # Slow down player movement.
+ motion *= 0.5
+
+ if in_water:
+ motion *= WATER_ACCELERATION_FACTOR
+
+ if not touching_ground:
+ # Slow down player movement (to take reduced friction into account,
+ # and give the impression of reduced air control).
+ motion *= AIR_ACCELERATION_FACTOR
+
+ velocity += motion
+
+ if not Input.is_action_pressed("jump") and touching_ground:
+ # Stair climbing.
+ global_position.y = 1.25 + $ShapeCast3D.get_collision_point(0).y
+ # Apply downwards velocity to stick to slopes and small steps.
+ velocity.y = -5.0
+
+ move_and_slide()
+
+ # Apply friction.
+ var friction := 0.94 if touching_ground else 0.985
+ velocity.x *= friction
+ velocity.z *= friction
+
+ # Check if camera is underwater to apply effects.
+ if $Camera3D.global_position.y < water_plane_y:
+ # Smoothly transition underwater TextureRect overlay.
+ $UnderwaterEffect.color = lerp($UnderwaterEffect.color, initial_underwater_color, 12 * delta)
+ # Enable low-pass effect on the Master bus.
+ AudioServer.set_bus_effect_enabled(0, 0, true)
+ else:
+ $UnderwaterEffect.color = lerp($UnderwaterEffect.color, Color.TRANSPARENT, 12 * delta)
+ # Disable low-pass effect on the Master bus.
+ AudioServer.set_bus_effect_enabled(0, 0, false)
+
+
+func _process(delta: float) -> void:
+ # Looking around with keyboard/gamepad.
+ var look := Input.get_vector("look_down", "look_up", "look_left", "look_right")
+ $Camera3D.rotation.x = clampf($Camera3D.rotation.x + look.x * LOOK_SENSITIVITY * delta, MIN_VIEW_PITCH, MAX_VIEW_PITCH)
+ $Camera3D.rotation.y -= look.y * LOOK_SENSITIVITY * delta
+
+ # Shooting (or respawning if currently dead).
+ if Input.is_action_pressed("attack") and is_zero_approx($ShootTimer.time_left):
+ if health <= 0:
+ get_tree().reload_current_scene()
+ return
+
+ for i in SHOTGUN_BULLET_COUNT:
+ var bullet = preload("res://bullet.tscn").instantiate()
+ # Bullets are not child of the player to prevent moving along the player.
+ get_parent().add_child(bullet)
+ bullet.global_transform = $Camera3D.global_transform
+ # Apply random spread (twice as much spread horizontally than vertically).
+ bullet.rotation.y += -0.1 + randf() * 0.2
+ bullet.rotation.x += -0.05 + randf() * 0.1
+
+ $ShootTimer.start()
+ $WeaponSounds.play()
+ $AnimationPlayer.play("fire")
+ # Apply weapon kickback (player is pushed away from their firing direction).
+ velocity += $Camera3D.global_transform.basis.z * WEAPON_KICKBACK_FORCE
+
+ if $AnimationPlayer.current_animation == &"fire":
+ # Fade out crosshair while the weapon is reloading.
+ $Crosshair.modulate.a = 0.5
+ else:
+ $Crosshair.modulate.a = 1.0
+
+ # Hide crosshair if dead.
+ $Crosshair.visible = health >= 1
+
+ # Fade out damage effect over time.
+ $DamageEffect.modulate.a = lerpf($DamageEffect.modulate.a, 0.0, 3 * delta)
+ damage_roll = lerpf(damage_roll, 0.0, 4 * delta)
+
+
+func _input(event: InputEvent) -> void:
+ # Looking around with mouse.
+ if event is InputEventMouseMotion:
+ # Compensate motion speed to be resolution-independent (based on the window height).
+ var relative_motion: Vector2 = event.relative * DisplayServer.window_get_size().y / base_height
+ # Don't allow looking *exactly* straight up/down to avoid issues with sprite rotation.
+ $Camera3D.rotation.x = clampf($Camera3D.rotation.x - relative_motion.y * MOUSE_SENSITIVITY, MIN_VIEW_PITCH, MAX_VIEW_PITCH)
+ $Camera3D.rotation.y -= relative_motion.x * MOUSE_SENSITIVITY
+
+ if event.is_action_pressed(&"toggle_flashlight"):
+ $Camera3D/Flashlight.visible = not $Camera3D/Flashlight.visible
+ # Use lower audio pitch when toggling off.
+ $FlashlightSounds.pitch_scale = 1.0 if $Camera3D/Flashlight.visible else 0.7
+ $FlashlightSounds.play()
+
+ if event.is_action_pressed(&"quit"):
+ get_tree().quit()
+
+
+# Called when the player dies.
+func die() -> void:
+ $HUD/Health.text = "You died! Click to retry."
diff --git a/3d/first_person_shooter/player.gd.uid b/3d/first_person_shooter/player.gd.uid
new file mode 100644
index 00000000000..1fae45f5988
--- /dev/null
+++ b/3d/first_person_shooter/player.gd.uid
@@ -0,0 +1 @@
+uid://bnmrtcv7egtlj
diff --git a/3d/first_person_shooter/player.tscn b/3d/first_person_shooter/player.tscn
new file mode 100644
index 00000000000..56263300e2c
--- /dev/null
+++ b/3d/first_person_shooter/player.tscn
@@ -0,0 +1,400 @@
+[gd_scene load_steps=39 format=3 uid="uid://dfyswwfb8j6iv"]
+
+[ext_resource type="Script" uid="uid://bnmrtcv7egtlj" path="res://player.gd" id="1_3afs5"]
+[ext_resource type="PackedScene" uid="uid://b4g77r67peq11" path="res://blob_shadow.tscn" id="2_att33"]
+[ext_resource type="Texture2D" uid="uid://df46fn25wxblu" path="res://player/shotgun/spritesheet.png" id="2_ntkbj"]
+[ext_resource type="Texture2D" uid="uid://d0h6we75g3l0h" path="res://crosshair.png" id="2_xdhj0"]
+[ext_resource type="AudioStream" uid="uid://jfxdoxq7t3t2" path="res://player/water_splash_out.ogg" id="3_ovny0"]
+[ext_resource type="AudioStream" uid="uid://lqgi4erf48wg" path="res://player/shotgun/fire.wav" id="3_w6ksn"]
+[ext_resource type="AudioStream" uid="uid://c2n47qjisa0wl" path="res://player/water_splash_in.ogg" id="3_yf4c3"]
+[ext_resource type="Shader" uid="uid://c50kid6qcbeog" path="res://player/weapon_sprite.gdshader" id="4_i5vum"]
+[ext_resource type="AudioStream" uid="uid://do4fwt667onp2" path="res://player/rain.ogg" id="6_cmbiq"]
+[ext_resource type="AudioStream" uid="uid://cy2lhrs5we1a7" path="res://player/shotgun/open.wav" id="6_tknt2"]
+[ext_resource type="AudioStream" uid="uid://dam35f8u5f2d5" path="res://player/shotgun/load.wav" id="7_dom6o"]
+[ext_resource type="AudioStream" uid="uid://cykqcvgf3tyv3" path="res://player/shotgun/close.wav" id="8_uckjf"]
+[ext_resource type="FontFile" uid="uid://blm3851cjtjji" path="res://fonts/vga-rom-font.png" id="9_yojfu"]
+
+[sub_resource type="BoxShape3D" id="BoxShape3D_n7pit"]
+size = Vector3(1, 1.5, 1)
+
+[sub_resource type="BoxShape3D" id="BoxShape3D_nlrfb"]
+size = Vector3(0.9, 0.75, 0.9)
+
+[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_lu535"]
+random_pitch = 1.02
+streams_count = 1
+stream_0/stream = ExtResource("7_dom6o")
+
+[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_46hgo"]
+random_pitch = 1.02
+streams_count = 1
+stream_0/stream = ExtResource("3_yf4c3")
+
+[sub_resource type="AudioStreamRandomizer" id="AudioStreamRandomizer_vhi2c"]
+random_pitch = 1.02
+streams_count = 1
+stream_0/stream = ExtResource("3_ovny0")
+
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_lr0u3"]
+emission_shape = 6
+emission_ring_axis = Vector3(0, 1, 0)
+emission_ring_height = 0.0
+emission_ring_radius = 50.0
+emission_ring_inner_radius = 0.0
+emission_ring_cone_angle = 90.0
+direction = Vector3(0, -1, 0)
+spread = 3.0
+initial_velocity_min = 60.0
+initial_velocity_max = 60.0
+collision_mode = 2
+sub_emitter_mode = 3
+sub_emitter_amount_at_collision = 1
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_sfjl0"]
+transparency = 1
+cull_mode = 2
+shading_mode = 0
+albedo_color = Color(0.662745, 0.788235, 1, 0.12549)
+billboard_mode = 2
+
+[sub_resource type="QuadMesh" id="QuadMesh_f2lko"]
+material = SubResource("StandardMaterial3D_sfjl0")
+size = Vector2(0.025, 0.5)
+
+[sub_resource type="Gradient" id="Gradient_iq4t4"]
+colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
+
+[sub_resource type="GradientTexture1D" id="GradientTexture1D_aql0l"]
+gradient = SubResource("Gradient_iq4t4")
+
+[sub_resource type="Curve" id="Curve_3xpn1"]
+_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
+point_count = 2
+
+[sub_resource type="CurveTexture" id="CurveTexture_fyu6e"]
+curve = SubResource("Curve_3xpn1")
+
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_2q22j"]
+gravity = Vector3(0, -3, 0)
+scale_curve = SubResource("CurveTexture_fyu6e")
+color = Color(0.745098, 0.882353, 1, 0.25098)
+color_ramp = SubResource("GradientTexture1D_aql0l")
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_m681u"]
+transparency = 1
+shading_mode = 0
+vertex_color_use_as_albedo = true
+billboard_mode = 1
+billboard_keep_scale = true
+
+[sub_resource type="QuadMesh" id="QuadMesh_rmfmt"]
+material = SubResource("StandardMaterial3D_m681u")
+size = Vector2(0.05, 0.05)
+
+[sub_resource type="QuadMesh" id="QuadMesh_m5j6l"]
+size = Vector2(1.655, 1)
+
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_fb2wo"]
+render_priority = 0
+shader = ExtResource("4_i5vum")
+shader_parameter/views = ExtResource("2_ntkbj")
+shader_parameter/frame_count = 10
+shader_parameter/frame = 0
+
+[sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_t4cq8"]
+blend_mode = 3
+
+[sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_502b5"]
+blend_mode = 1
+
+[sub_resource type="Gradient" id="Gradient_xdggq"]
+offsets = PackedFloat32Array(0.00198807, 1)
+colors = PackedColorArray(0, 0, 0, 0, 1, 0, 0, 1)
+
+[sub_resource type="GradientTexture2D" id="GradientTexture2D_pusfi"]
+gradient = SubResource("Gradient_xdggq")
+fill = 1
+fill_from = Vector2(0.5, 0.5)
+
+[sub_resource type="Animation" id="Animation_y888d"]
+length = 0.001
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Camera3D/WeaponSprite:surface_material_override/0:shader_parameter/frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [0]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Camera3D/WeaponLight:visible")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [true]
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("Camera3D/WeaponLight:light_energy")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [0.0]
+}
+
+[sub_resource type="Animation" id="Animation_nrowk"]
+resource_name = "fire"
+length = 1.15
+step = 0.05
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Camera3D/WeaponSprite:surface_material_override/0:shader_parameter/frame")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 0.25, 0.45, 1.05, 1.15),
+"transitions": PackedFloat32Array(1, 1, 1, 0, 1),
+"update": 0,
+"values": [0, 3, 3, 9, 0]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("Camera3D/WeaponLight:visible")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0, 0.3),
+"transitions": PackedFloat32Array(1, 1),
+"update": 1,
+"values": [true, false]
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("Camera3D/WeaponLight:light_energy")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0, 0.05, 0.3),
+"transitions": PackedFloat32Array(-2, -2, -2),
+"update": 0,
+"values": [0.0, 2.0, 0.0]
+}
+tracks/3/type = "audio"
+tracks/3/imported = false
+tracks/3/enabled = true
+tracks/3/path = NodePath("WeaponSounds")
+tracks/3/interp = 1
+tracks/3/loop_wrap = true
+tracks/3/keys = {
+"clips": [{
+"end_offset": 0.00360187,
+"start_offset": 0.0,
+"stream": ExtResource("3_w6ksn")
+}, {
+"end_offset": 0.0,
+"start_offset": 0.0276511,
+"stream": ExtResource("6_tknt2")
+}, {
+"end_offset": 0.0,
+"start_offset": 0.0,
+"stream": ExtResource("7_dom6o")
+}, {
+"end_offset": 0.0,
+"start_offset": 0.0,
+"stream": ExtResource("8_uckjf")
+}],
+"times": PackedFloat32Array(0, 0.535896, 0.844826, 1)
+}
+tracks/3/use_blend = true
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_glvp6"]
+_data = {
+&"RESET": SubResource("Animation_y888d"),
+&"fire": SubResource("Animation_nrowk")
+}
+
+[sub_resource type="Theme" id="Theme_6xrdg"]
+default_font = ExtResource("9_yojfu")
+
+[node name="Player" type="CharacterBody3D" groups=["player"]]
+collision_layer = 2
+collision_mask = 7
+script = ExtResource("1_3afs5")
+
+[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, 0)
+shape = SubResource("BoxShape3D_n7pit")
+
+[node name="ShapeCast3D" type="ShapeCast3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.125, 0)
+shape = SubResource("BoxShape3D_nlrfb")
+max_results = 1
+
+[node name="WeaponSounds" type="AudioStreamPlayer" parent="."]
+volume_db = -12.0
+max_polyphony = 2
+
+[node name="FlashlightSounds" type="AudioStreamPlayer" parent="."]
+stream = SubResource("AudioStreamRandomizer_lu535")
+volume_db = -12.0
+max_polyphony = 2
+
+[node name="WaterInSound" type="AudioStreamPlayer" parent="."]
+stream = SubResource("AudioStreamRandomizer_46hgo")
+volume_db = -6.0
+max_polyphony = 2
+
+[node name="WaterOutSound" type="AudioStreamPlayer" parent="."]
+stream = SubResource("AudioStreamRandomizer_vhi2c")
+volume_db = -6.0
+max_polyphony = 2
+
+[node name="Rain" type="GPUParticles3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 30.5, 0)
+amount = 4000
+sub_emitter = NodePath("RainImpactSubemitter")
+lifetime = 2.0
+preprocess = 2.0
+fixed_fps = 0
+interpolate = false
+collision_base_size = 0.25
+visibility_aabb = AABB(-49.847, -490.159, -49.8395, 99.8953, 490.659, 99.2455)
+process_material = SubResource("ParticleProcessMaterial_lr0u3")
+draw_pass_1 = SubResource("QuadMesh_f2lko")
+
+[node name="RainImpactSubemitter" type="GPUParticles3D" parent="Rain"]
+emitting = false
+amount = 3000
+fixed_fps = 0
+interpolate = false
+visibility_aabb = AABB(-49.847, -490.159, -49.8395, 99.8953, 490.659, 99.2455)
+process_material = SubResource("ParticleProcessMaterial_2q22j")
+draw_pass_1 = SubResource("QuadMesh_rmfmt")
+
+[node name="RainSound" type="AudioStreamPlayer" parent="Rain"]
+stream = ExtResource("6_cmbiq")
+volume_db = -6.0
+autoplay = true
+
+[node name="Camera3D" type="Camera3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
+fov = 74.0
+
+[node name="Flashlight" type="SpotLight3D" parent="Camera3D"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.4, -0.4, 0)
+visible = false
+light_color = Color(1, 0.973333, 0.92, 1)
+light_energy = 5.0
+light_specular = 0.25
+shadow_enabled = true
+shadow_bias = 0.01
+shadow_blur = 2.5
+spot_range = 50.0
+spot_attenuation = 2.0
+spot_angle = 35.0
+spot_angle_attenuation = 2.0
+
+[node name="WeaponSprite" type="MeshInstance3D" parent="Camera3D"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.37, -0.67, -1.5)
+layers = 2
+sorting_offset = 100.0
+cast_shadow = 0
+mesh = SubResource("QuadMesh_m5j6l")
+surface_material_override/0 = SubResource("ShaderMaterial_fb2wo")
+
+[node name="WeaponLight" type="OmniLight3D" parent="Camera3D"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.5, 0)
+light_color = Color(1, 0.764706, 0.235294, 1)
+light_energy = 0.0
+light_specular = 0.1
+shadow_enabled = true
+shadow_bias = 0.12
+shadow_blur = 2.5
+omni_range = 10.0
+
+[node name="Decal" parent="." instance=ExtResource("2_att33")]
+
+[node name="ShootTimer" type="Timer" parent="."]
+wait_time = 1.2
+one_shot = true
+
+[node name="UnderwaterEffect" type="ColorRect" parent="."]
+material = SubResource("CanvasItemMaterial_t4cq8")
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+color = Color(0.54902, 0.647059, 0.901961, 1)
+
+[node name="DamageEffect" type="TextureRect" parent="."]
+texture_filter = 2
+material = SubResource("CanvasItemMaterial_502b5")
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+texture = SubResource("GradientTexture2D_pusfi")
+
+[node name="Crosshair" type="TextureRect" parent="."]
+texture_filter = 2
+anchors_preset = 8
+anchor_left = 0.5
+anchor_top = 0.5
+anchor_right = 0.5
+anchor_bottom = 0.5
+offset_left = -8.0
+offset_top = -8.0
+offset_right = 8.0
+offset_bottom = 8.0
+grow_horizontal = 2
+grow_vertical = 2
+texture = ExtResource("2_xdhj0")
+expand_mode = 1
+
+[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
+libraries = {
+&"": SubResource("AnimationLibrary_glvp6")
+}
+
+[node name="HUD" type="Control" parent="."]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+theme = SubResource("Theme_6xrdg")
+
+[node name="Health" type="Label" parent="HUD"]
+layout_mode = 1
+anchors_preset = 2
+anchor_top = 1.0
+anchor_bottom = 1.0
+offset_left = 48.0
+offset_top = -75.0
+offset_right = 240.0
+offset_bottom = -40.0
+grow_vertical = 0
+theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
+theme_override_constants/shadow_offset_x = 2
+theme_override_constants/shadow_offset_y = 2
+text = "Health: 100"
+vertical_alignment = 2
diff --git a/3d/first_person_shooter/player/crosshair_health_gradient.tres b/3d/first_person_shooter/player/crosshair_health_gradient.tres
new file mode 100644
index 00000000000..6754195a45a
--- /dev/null
+++ b/3d/first_person_shooter/player/crosshair_health_gradient.tres
@@ -0,0 +1,5 @@
+[gd_resource type="Gradient" format=3 uid="uid://cu4od503o35ja"]
+
+[resource]
+offsets = PackedFloat32Array(0.2, 0.6, 1)
+colors = PackedColorArray(1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1)
diff --git a/3d/first_person_shooter/player/rain.ogg b/3d/first_person_shooter/player/rain.ogg
new file mode 100644
index 00000000000..5ed194a9611
Binary files /dev/null and b/3d/first_person_shooter/player/rain.ogg differ
diff --git a/3d/first_person_shooter/player/rain.ogg.import b/3d/first_person_shooter/player/rain.ogg.import
new file mode 100644
index 00000000000..890694fc9cc
--- /dev/null
+++ b/3d/first_person_shooter/player/rain.ogg.import
@@ -0,0 +1,19 @@
+[remap]
+
+importer="oggvorbisstr"
+type="AudioStreamOggVorbis"
+uid="uid://do4fwt667onp2"
+path="res://.godot/imported/rain.ogg-2ca7ffef65e09d85c183b78463d4fc7e.oggvorbisstr"
+
+[deps]
+
+source_file="res://player/rain.ogg"
+dest_files=["res://.godot/imported/rain.ogg-2ca7ffef65e09d85c183b78463d4fc7e.oggvorbisstr"]
+
+[params]
+
+loop=true
+loop_offset=0
+bpm=0
+beat_count=0
+bar_beats=4
diff --git a/3d/first_person_shooter/player/shotgun/close.wav b/3d/first_person_shooter/player/shotgun/close.wav
new file mode 100644
index 00000000000..f600ad688b9
Binary files /dev/null and b/3d/first_person_shooter/player/shotgun/close.wav differ
diff --git a/3d/first_person_shooter/player/shotgun/close.wav.import b/3d/first_person_shooter/player/shotgun/close.wav.import
new file mode 100644
index 00000000000..a9c52cbfa9a
--- /dev/null
+++ b/3d/first_person_shooter/player/shotgun/close.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://cykqcvgf3tyv3"
+path="res://.godot/imported/close.wav-c10b62d5f9755ef8f63478a27a6f97c9.sample"
+
+[deps]
+
+source_file="res://player/shotgun/close.wav"
+dest_files=["res://.godot/imported/close.wav-c10b62d5f9755ef8f63478a27a6f97c9.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/3d/first_person_shooter/player/shotgun/fire.wav b/3d/first_person_shooter/player/shotgun/fire.wav
new file mode 100644
index 00000000000..ffa9dc86417
Binary files /dev/null and b/3d/first_person_shooter/player/shotgun/fire.wav differ
diff --git a/3d/first_person_shooter/player/shotgun/fire.wav.import b/3d/first_person_shooter/player/shotgun/fire.wav.import
new file mode 100644
index 00000000000..33a22040e30
--- /dev/null
+++ b/3d/first_person_shooter/player/shotgun/fire.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://lqgi4erf48wg"
+path="res://.godot/imported/fire.wav-e424f8860f2e9c036badf186d57d0db8.sample"
+
+[deps]
+
+source_file="res://player/shotgun/fire.wav"
+dest_files=["res://.godot/imported/fire.wav-e424f8860f2e9c036badf186d57d0db8.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/3d/first_person_shooter/player/shotgun/load.wav b/3d/first_person_shooter/player/shotgun/load.wav
new file mode 100644
index 00000000000..28d357f4548
Binary files /dev/null and b/3d/first_person_shooter/player/shotgun/load.wav differ
diff --git a/3d/first_person_shooter/player/shotgun/load.wav.import b/3d/first_person_shooter/player/shotgun/load.wav.import
new file mode 100644
index 00000000000..450238c2a51
--- /dev/null
+++ b/3d/first_person_shooter/player/shotgun/load.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://dam35f8u5f2d5"
+path="res://.godot/imported/load.wav-96d4070bf57894416dfa8f72018220b3.sample"
+
+[deps]
+
+source_file="res://player/shotgun/load.wav"
+dest_files=["res://.godot/imported/load.wav-96d4070bf57894416dfa8f72018220b3.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/3d/first_person_shooter/player/shotgun/open.wav b/3d/first_person_shooter/player/shotgun/open.wav
new file mode 100644
index 00000000000..ce9b47603ad
Binary files /dev/null and b/3d/first_person_shooter/player/shotgun/open.wav differ
diff --git a/3d/first_person_shooter/player/shotgun/open.wav.import b/3d/first_person_shooter/player/shotgun/open.wav.import
new file mode 100644
index 00000000000..2943c66b5aa
--- /dev/null
+++ b/3d/first_person_shooter/player/shotgun/open.wav.import
@@ -0,0 +1,24 @@
+[remap]
+
+importer="wav"
+type="AudioStreamWAV"
+uid="uid://cy2lhrs5we1a7"
+path="res://.godot/imported/open.wav-7c31b99055ac1d59a8af97a8bce02370.sample"
+
+[deps]
+
+source_file="res://player/shotgun/open.wav"
+dest_files=["res://.godot/imported/open.wav-7c31b99055ac1d59a8af97a8bce02370.sample"]
+
+[params]
+
+force/8_bit=false
+force/mono=false
+force/max_rate=false
+force/max_rate_hz=44100
+edit/trim=false
+edit/normalize=false
+edit/loop_mode=0
+edit/loop_begin=0
+edit/loop_end=-1
+compress/mode=0
diff --git a/3d/first_person_shooter/player/shotgun/spritesheet.png b/3d/first_person_shooter/player/shotgun/spritesheet.png
new file mode 100644
index 00000000000..db0f1f18361
Binary files /dev/null and b/3d/first_person_shooter/player/shotgun/spritesheet.png differ
diff --git a/3d/first_person_shooter/player/shotgun/spritesheet.png.import b/3d/first_person_shooter/player/shotgun/spritesheet.png.import
new file mode 100644
index 00000000000..7f6823b66c2
--- /dev/null
+++ b/3d/first_person_shooter/player/shotgun/spritesheet.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://df46fn25wxblu"
+path="res://.godot/imported/spritesheet.png-6dc933fb56592748e1df563eb6433903.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://player/shotgun/spritesheet.png"
+dest_files=["res://.godot/imported/spritesheet.png-6dc933fb56592748e1df563eb6433903.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/player/water_splash_in.ogg b/3d/first_person_shooter/player/water_splash_in.ogg
new file mode 100644
index 00000000000..75c1d4a5f61
Binary files /dev/null and b/3d/first_person_shooter/player/water_splash_in.ogg differ
diff --git a/3d/first_person_shooter/player/water_splash_in.ogg.import b/3d/first_person_shooter/player/water_splash_in.ogg.import
new file mode 100644
index 00000000000..a9e19f1d843
--- /dev/null
+++ b/3d/first_person_shooter/player/water_splash_in.ogg.import
@@ -0,0 +1,19 @@
+[remap]
+
+importer="oggvorbisstr"
+type="AudioStreamOggVorbis"
+uid="uid://c2n47qjisa0wl"
+path="res://.godot/imported/water_splash_in.ogg-f77bbc682bf38a165260625734d95ae0.oggvorbisstr"
+
+[deps]
+
+source_file="res://player/water_splash_in.ogg"
+dest_files=["res://.godot/imported/water_splash_in.ogg-f77bbc682bf38a165260625734d95ae0.oggvorbisstr"]
+
+[params]
+
+loop=false
+loop_offset=0
+bpm=0
+beat_count=0
+bar_beats=4
diff --git a/3d/first_person_shooter/player/water_splash_out.ogg b/3d/first_person_shooter/player/water_splash_out.ogg
new file mode 100644
index 00000000000..482b1d06da8
Binary files /dev/null and b/3d/first_person_shooter/player/water_splash_out.ogg differ
diff --git a/3d/first_person_shooter/player/water_splash_out.ogg.import b/3d/first_person_shooter/player/water_splash_out.ogg.import
new file mode 100644
index 00000000000..b016cb4183c
--- /dev/null
+++ b/3d/first_person_shooter/player/water_splash_out.ogg.import
@@ -0,0 +1,19 @@
+[remap]
+
+importer="oggvorbisstr"
+type="AudioStreamOggVorbis"
+uid="uid://jfxdoxq7t3t2"
+path="res://.godot/imported/water_splash_out.ogg-48198d6b4f2c68b34654eea272313a53.oggvorbisstr"
+
+[deps]
+
+source_file="res://player/water_splash_out.ogg"
+dest_files=["res://.godot/imported/water_splash_out.ogg-48198d6b4f2c68b34654eea272313a53.oggvorbisstr"]
+
+[params]
+
+loop=false
+loop_offset=0
+bpm=0
+beat_count=0
+bar_beats=4
diff --git a/3d/first_person_shooter/player/weapon_sprite.gdshader b/3d/first_person_shooter/player/weapon_sprite.gdshader
new file mode 100644
index 00000000000..67b2288e354
--- /dev/null
+++ b/3d/first_person_shooter/player/weapon_sprite.gdshader
@@ -0,0 +1,33 @@
+shader_type spatial;
+render_mode specular_disabled, depth_test_disabled;
+
+// Texture spritesheet.
+uniform sampler2D views : filter_nearest, source_color;
+
+// Number of frames in the animation (vertical axis on the image).
+uniform int frame_count : hint_range(1, 1000) = 7;
+// Current frame in the animation.
+uniform int frame : hint_range(0, 999) = 0;
+
+const float MIN_BRIGHTNESS = 0.4;
+const float ALBEDO_ENERGY = 4.0;
+
+void vertex() {
+ // Billboard.
+ MODELVIEW_MATRIX = VIEW_MATRIX * mat4(INV_VIEW_MATRIX[0], INV_VIEW_MATRIX[1], INV_VIEW_MATRIX[2], MODEL_MATRIX[3]);
+}
+
+void fragment() {
+ float y = float(frame) / float(frame_count); // UV vertical start for the view in the atlas.
+ float view_height = 1.0 / float(frame_count); // UV height of the animation in the atlas.
+
+ // Add a slight vertical offset to UV sampling to fix stray pixel edges appearing at the top of the sprite.
+ vec4 tex = texture(views, vec2(UV.x, y + view_height * UV.y + 0.001));
+
+ // Ensure the weapon sprite in the darkness is always visible to an extent,
+ // but allow it to be lit by light sources.
+ EMISSION.rgb = tex.rgb * MIN_BRIGHTNESS;
+ ALBEDO = tex.rgb * ALBEDO_ENERGY;
+ ALPHA = tex.a;
+ ALPHA_SCISSOR_THRESHOLD = 0.5;
+}
diff --git a/3d/first_person_shooter/player/weapon_sprite.gdshader.uid b/3d/first_person_shooter/player/weapon_sprite.gdshader.uid
new file mode 100644
index 00000000000..a8f703ae6fb
--- /dev/null
+++ b/3d/first_person_shooter/player/weapon_sprite.gdshader.uid
@@ -0,0 +1 @@
+uid://c50kid6qcbeog
diff --git a/3d/first_person_shooter/project.godot b/3d/first_person_shooter/project.godot
new file mode 100644
index 00000000000..dd1ba52aa20
--- /dev/null
+++ b/3d/first_person_shooter/project.godot
@@ -0,0 +1,140 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="First-Person Shooter"
+run/main_scene="res://level.tscn"
+config/features=PackedStringArray("4.5")
+
+[debug]
+
+settings/physics_interpolation/enable_warnings=false
+
+[display]
+
+window/stretch/mode="canvas_items"
+window/stretch/aspect="expand"
+window/vsync/vsync_mode=0
+
+[editor_plugins]
+
+enabled=PackedStringArray("res://addons/bsp_importer/plugin.cfg")
+
+[input]
+
+move_forward={
+"deadzone": 0.2,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
+]
+}
+move_backward={
+"deadzone": 0.2,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null)
+]
+}
+move_left={
+"deadzone": 0.2,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
+]
+}
+move_right={
+"deadzone": 0.2,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
+]
+}
+jump={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":true,"script":null)
+, Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":2,"canceled":false,"pressed":false,"double_click":false,"script":null)
+]
+}
+toggle_flashlight={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":70,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+, Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":8,"canceled":false,"pressed":false,"double_click":false,"script":null)
+, Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":9,"canceled":false,"pressed":false,"double_click":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":1,"pressure":0.0,"pressed":true,"script":null)
+]
+}
+walk={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194326,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":9,"pressure":0.0,"pressed":true,"script":null)
+]
+}
+attack={
+"deadzone": 0.5,
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":5,"axis_value":1.0,"script":null)
+]
+}
+quit={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":11,"pressure":0.0,"pressed":true,"script":null)
+]
+}
+look_up={
+"deadzone": 0.2,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194320,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":3,"axis_value":-1.0,"script":null)
+]
+}
+look_down={
+"deadzone": 0.2,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194322,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":3,"axis_value":1.0,"script":null)
+]
+}
+look_left={
+"deadzone": 0.2,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194319,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":2,"axis_value":-1.0,"script":null)
+]
+}
+look_right={
+"deadzone": 0.2,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194321,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":2,"axis_value":1.0,"script":null)
+]
+}
+
+[layer_names]
+
+3d_physics/layer_1="Level"
+3d_physics/layer_2="Player"
+3d_physics/layer_3="Enemies"
+
+[physics]
+
+common/physics_ticks_per_second=120
+3d/physics_engine="Jolt Physics"
+3d/default_gravity=30.0
+common/physics_interpolation=true
+
+[rendering]
+
+textures/canvas_textures/default_texture_filter=0
+textures/default_filters/anisotropic_filtering_level=4
+anti_aliasing/quality/msaa_3d=2
+textures/decals/filter=4
+textures/light_projectors/filter=4
+anti_aliasing/quality/screen_space_aa=2
+anti_aliasing/quality/use_debanding=true
+lights_and_shadows/positional_shadow/atlas_size=2048
+lights_and_shadows/positional_shadow/atlas_size.mobile=1024
+lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv=2
+lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv=2
diff --git a/3d/first_person_shooter/screenshots/.gdignore b/3d/first_person_shooter/screenshots/.gdignore
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/3d/first_person_shooter/screenshots/first_person_shooter.webp b/3d/first_person_shooter/screenshots/first_person_shooter.webp
new file mode 100644
index 00000000000..61d5c5c8b6e
Binary files /dev/null and b/3d/first_person_shooter/screenshots/first_person_shooter.webp differ
diff --git a/3d/first_person_shooter/sky.png b/3d/first_person_shooter/sky.png
new file mode 100644
index 00000000000..c318228a2f5
Binary files /dev/null and b/3d/first_person_shooter/sky.png differ
diff --git a/3d/first_person_shooter/sky.png.import b/3d/first_person_shooter/sky.png.import
new file mode 100644
index 00000000000..fef924b8f60
--- /dev/null
+++ b/3d/first_person_shooter/sky.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bc3n2sen32mqx"
+path.s3tc="res://.godot/imported/sky.png-26d2f2385da36d2602e95bc19d12fcc5.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://sky.png"
+dest_files=["res://.godot/imported/sky.png-26d2f2385da36d2602e95bc19d12fcc5.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+0_tscrn0.png b/3d/first_person_shooter/textures/+0_tscrn0.png
new file mode 100644
index 00000000000..1bfdce73131
Binary files /dev/null and b/3d/first_person_shooter/textures/+0_tscrn0.png differ
diff --git a/3d/first_person_shooter/textures/+0_tscrn0.png.import b/3d/first_person_shooter/textures/+0_tscrn0.png.import
new file mode 100644
index 00000000000..07f52a54f11
--- /dev/null
+++ b/3d/first_person_shooter/textures/+0_tscrn0.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bdnk44peuh5c1"
+path.s3tc="res://.godot/imported/+0_tscrn0.png-e84e72ed23dcd640d3a3443b58d7479d.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+0_tscrn0.png"
+dest_files=["res://.godot/imported/+0_tscrn0.png-e84e72ed23dcd640d3a3443b58d7479d.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+0_tscrn1.png b/3d/first_person_shooter/textures/+0_tscrn1.png
new file mode 100644
index 00000000000..a7c4c3af5e7
Binary files /dev/null and b/3d/first_person_shooter/textures/+0_tscrn1.png differ
diff --git a/3d/first_person_shooter/textures/+0_tscrn1.png.import b/3d/first_person_shooter/textures/+0_tscrn1.png.import
new file mode 100644
index 00000000000..b0f97dbb0f3
--- /dev/null
+++ b/3d/first_person_shooter/textures/+0_tscrn1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://capqyr63c2571"
+path.s3tc="res://.godot/imported/+0_tscrn1.png-55f1fb4f82d7b39b83c50695fdc302da.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+0_tscrn1.png"
+dest_files=["res://.godot/imported/+0_tscrn1.png-55f1fb4f82d7b39b83c50695fdc302da.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+0basebtn.png b/3d/first_person_shooter/textures/+0basebtn.png
new file mode 100644
index 00000000000..80f67f96ae4
Binary files /dev/null and b/3d/first_person_shooter/textures/+0basebtn.png differ
diff --git a/3d/first_person_shooter/textures/+0basebtn.png.import b/3d/first_person_shooter/textures/+0basebtn.png.import
new file mode 100644
index 00000000000..42db0c0c6cf
--- /dev/null
+++ b/3d/first_person_shooter/textures/+0basebtn.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dchte5668e374"
+path.s3tc="res://.godot/imported/+0basebtn.png-337113ceeab01b8e78615ee52ef4099f.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+0basebtn.png"
+dest_files=["res://.godot/imported/+0basebtn.png-337113ceeab01b8e78615ee52ef4099f.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+0basebtn_emission.png b/3d/first_person_shooter/textures/+0basebtn_emission.png
new file mode 100644
index 00000000000..15c174e52b4
Binary files /dev/null and b/3d/first_person_shooter/textures/+0basebtn_emission.png differ
diff --git a/3d/first_person_shooter/textures/+0basebtn_emission.png.import b/3d/first_person_shooter/textures/+0basebtn_emission.png.import
new file mode 100644
index 00000000000..e28eff3ff06
--- /dev/null
+++ b/3d/first_person_shooter/textures/+0basebtn_emission.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://7d1cc0lq6x2k"
+path.s3tc="res://.godot/imported/+0basebtn_emission.png-e2914516ec3aa2070645ef47f4452506.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+0basebtn_emission.png"
+dest_files=["res://.godot/imported/+0basebtn_emission.png-e2914516ec3aa2070645ef47f4452506.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+0tek_jump1.png b/3d/first_person_shooter/textures/+0tek_jump1.png
new file mode 100644
index 00000000000..f7b4cf7533d
Binary files /dev/null and b/3d/first_person_shooter/textures/+0tek_jump1.png differ
diff --git a/3d/first_person_shooter/textures/+0tek_jump1.png.import b/3d/first_person_shooter/textures/+0tek_jump1.png.import
new file mode 100644
index 00000000000..8aae8e4039b
--- /dev/null
+++ b/3d/first_person_shooter/textures/+0tek_jump1.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://jtpwwtrxii2c"
+path="res://.godot/imported/+0tek_jump1.png-ed91c01f6b0fcd98ea73d82236d9eb67.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://textures/+0tek_jump1.png"
+dest_files=["res://.godot/imported/+0tek_jump1.png-ed91c01f6b0fcd98ea73d82236d9eb67.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/3d/first_person_shooter/textures/+0tek_jump1_emission.png b/3d/first_person_shooter/textures/+0tek_jump1_emission.png
new file mode 100644
index 00000000000..6df9b8758e0
Binary files /dev/null and b/3d/first_person_shooter/textures/+0tek_jump1_emission.png differ
diff --git a/3d/first_person_shooter/textures/+0tek_jump1_emission.png.import b/3d/first_person_shooter/textures/+0tek_jump1_emission.png.import
new file mode 100644
index 00000000000..ae25ebb26e9
--- /dev/null
+++ b/3d/first_person_shooter/textures/+0tek_jump1_emission.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bp2hixbldp7q2"
+path="res://.godot/imported/+0tek_jump1_emission.png-cbae4a354d17fab929da82e7abadfb96.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://textures/+0tek_jump1_emission.png"
+dest_files=["res://.godot/imported/+0tek_jump1_emission.png-cbae4a354d17fab929da82e7abadfb96.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/3d/first_person_shooter/textures/+0term128.png b/3d/first_person_shooter/textures/+0term128.png
new file mode 100644
index 00000000000..172806e3688
Binary files /dev/null and b/3d/first_person_shooter/textures/+0term128.png differ
diff --git a/3d/first_person_shooter/textures/+0term128.png.import b/3d/first_person_shooter/textures/+0term128.png.import
new file mode 100644
index 00000000000..d5d9b050844
--- /dev/null
+++ b/3d/first_person_shooter/textures/+0term128.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://14l2nrrgfsyn"
+path.s3tc="res://.godot/imported/+0term128.png-b8217f9500b26f0151f7fb67fae2d7f7.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+0term128.png"
+dest_files=["res://.godot/imported/+0term128.png-b8217f9500b26f0151f7fb67fae2d7f7.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+0tlight3.png b/3d/first_person_shooter/textures/+0tlight3.png
new file mode 100644
index 00000000000..ff55f1f7e36
Binary files /dev/null and b/3d/first_person_shooter/textures/+0tlight3.png differ
diff --git a/3d/first_person_shooter/textures/+0tlight3.png.import b/3d/first_person_shooter/textures/+0tlight3.png.import
new file mode 100644
index 00000000000..950e523ea78
--- /dev/null
+++ b/3d/first_person_shooter/textures/+0tlight3.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cahkfrtxenf5u"
+path.s3tc="res://.godot/imported/+0tlight3.png-2a6f67baf82019a94841a31e0280ed6b.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+0tlight3.png"
+dest_files=["res://.godot/imported/+0tlight3.png-2a6f67baf82019a94841a31e0280ed6b.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+1basebtn.png b/3d/first_person_shooter/textures/+1basebtn.png
new file mode 100644
index 00000000000..eacd1a7857d
Binary files /dev/null and b/3d/first_person_shooter/textures/+1basebtn.png differ
diff --git a/3d/first_person_shooter/textures/+1basebtn.png.import b/3d/first_person_shooter/textures/+1basebtn.png.import
new file mode 100644
index 00000000000..719669e7258
--- /dev/null
+++ b/3d/first_person_shooter/textures/+1basebtn.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cwnc7dmy368mi"
+path.s3tc="res://.godot/imported/+1basebtn.png-07fb115f5161699c79ac1bff95f15124.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+1basebtn.png"
+dest_files=["res://.godot/imported/+1basebtn.png-07fb115f5161699c79ac1bff95f15124.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+1tek_jump1.png b/3d/first_person_shooter/textures/+1tek_jump1.png
new file mode 100644
index 00000000000..f7b4cf7533d
Binary files /dev/null and b/3d/first_person_shooter/textures/+1tek_jump1.png differ
diff --git a/3d/first_person_shooter/textures/+1tek_jump1.png.import b/3d/first_person_shooter/textures/+1tek_jump1.png.import
new file mode 100644
index 00000000000..f671f4f5ab1
--- /dev/null
+++ b/3d/first_person_shooter/textures/+1tek_jump1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bi8o3yald3n7"
+path.s3tc="res://.godot/imported/+1tek_jump1.png-86af3e6b3a3f9d725ef5932ac0147f86.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+1tek_jump1.png"
+dest_files=["res://.godot/imported/+1tek_jump1.png-86af3e6b3a3f9d725ef5932ac0147f86.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+1tek_jump1_emission.png b/3d/first_person_shooter/textures/+1tek_jump1_emission.png
new file mode 100644
index 00000000000..6df9b8758e0
Binary files /dev/null and b/3d/first_person_shooter/textures/+1tek_jump1_emission.png differ
diff --git a/3d/first_person_shooter/textures/+1tek_jump1_emission.png.import b/3d/first_person_shooter/textures/+1tek_jump1_emission.png.import
new file mode 100644
index 00000000000..68c340ae377
--- /dev/null
+++ b/3d/first_person_shooter/textures/+1tek_jump1_emission.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c34gbcqcc7m14"
+path.s3tc="res://.godot/imported/+1tek_jump1_emission.png-7bae74238eea0da46cd5d2155984727f.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+1tek_jump1_emission.png"
+dest_files=["res://.godot/imported/+1tek_jump1_emission.png-7bae74238eea0da46cd5d2155984727f.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+1term128.png b/3d/first_person_shooter/textures/+1term128.png
new file mode 100644
index 00000000000..0e44903716f
Binary files /dev/null and b/3d/first_person_shooter/textures/+1term128.png differ
diff --git a/3d/first_person_shooter/textures/+1term128.png.import b/3d/first_person_shooter/textures/+1term128.png.import
new file mode 100644
index 00000000000..f079fa29a88
--- /dev/null
+++ b/3d/first_person_shooter/textures/+1term128.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bd0a4cs6x6paq"
+path="res://.godot/imported/+1term128.png-187699b66af5a9bb6a253bea0e039726.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://textures/+1term128.png"
+dest_files=["res://.godot/imported/+1term128.png-187699b66af5a9bb6a253bea0e039726.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/3d/first_person_shooter/textures/+a_tscrn0.png b/3d/first_person_shooter/textures/+a_tscrn0.png
new file mode 100644
index 00000000000..7a0ace3044f
Binary files /dev/null and b/3d/first_person_shooter/textures/+a_tscrn0.png differ
diff --git a/3d/first_person_shooter/textures/+a_tscrn0.png.import b/3d/first_person_shooter/textures/+a_tscrn0.png.import
new file mode 100644
index 00000000000..9c506ac3698
--- /dev/null
+++ b/3d/first_person_shooter/textures/+a_tscrn0.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bt0snhtaoiqjx"
+path.s3tc="res://.godot/imported/+a_tscrn0.png-ef02e208c0a139bd2d673ea955df74fa.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+a_tscrn0.png"
+dest_files=["res://.godot/imported/+a_tscrn0.png-ef02e208c0a139bd2d673ea955df74fa.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+a_tscrn1.png b/3d/first_person_shooter/textures/+a_tscrn1.png
new file mode 100644
index 00000000000..22609cb712a
Binary files /dev/null and b/3d/first_person_shooter/textures/+a_tscrn1.png differ
diff --git a/3d/first_person_shooter/textures/+a_tscrn1.png.import b/3d/first_person_shooter/textures/+a_tscrn1.png.import
new file mode 100644
index 00000000000..a8a5ab585ee
--- /dev/null
+++ b/3d/first_person_shooter/textures/+a_tscrn1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ifw67i42pv3b"
+path.s3tc="res://.godot/imported/+a_tscrn1.png-d7aef5600e824a1d4c23f8ecfc5b30bc.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+a_tscrn1.png"
+dest_files=["res://.godot/imported/+a_tscrn1.png-d7aef5600e824a1d4c23f8ecfc5b30bc.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+a_tscrn2.png b/3d/first_person_shooter/textures/+a_tscrn2.png
new file mode 100644
index 00000000000..7b51a0b5ecf
Binary files /dev/null and b/3d/first_person_shooter/textures/+a_tscrn2.png differ
diff --git a/3d/first_person_shooter/textures/+a_tscrn2.png.import b/3d/first_person_shooter/textures/+a_tscrn2.png.import
new file mode 100644
index 00000000000..7cab4ba1e86
--- /dev/null
+++ b/3d/first_person_shooter/textures/+a_tscrn2.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dvsqjt37n6jv4"
+path.s3tc="res://.godot/imported/+a_tscrn2.png-bbf9c8fdbea4fcf2030f2b2e8bb0508c.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+a_tscrn2.png"
+dest_files=["res://.godot/imported/+a_tscrn2.png-bbf9c8fdbea4fcf2030f2b2e8bb0508c.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+abasebtn.png b/3d/first_person_shooter/textures/+abasebtn.png
new file mode 100644
index 00000000000..159bdfe2366
Binary files /dev/null and b/3d/first_person_shooter/textures/+abasebtn.png differ
diff --git a/3d/first_person_shooter/textures/+abasebtn.png.import b/3d/first_person_shooter/textures/+abasebtn.png.import
new file mode 100644
index 00000000000..25e627208c4
--- /dev/null
+++ b/3d/first_person_shooter/textures/+abasebtn.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cld3je11kldd5"
+path.s3tc="res://.godot/imported/+abasebtn.png-aabf7d3c003d8b24e9e1eef5506112c7.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+abasebtn.png"
+dest_files=["res://.godot/imported/+abasebtn.png-aabf7d3c003d8b24e9e1eef5506112c7.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+atek_jump1.png b/3d/first_person_shooter/textures/+atek_jump1.png
new file mode 100644
index 00000000000..f7b4cf7533d
Binary files /dev/null and b/3d/first_person_shooter/textures/+atek_jump1.png differ
diff --git a/3d/first_person_shooter/textures/+atek_jump1.png.import b/3d/first_person_shooter/textures/+atek_jump1.png.import
new file mode 100644
index 00000000000..74187e2ae41
--- /dev/null
+++ b/3d/first_person_shooter/textures/+atek_jump1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ctelrhbqknsr0"
+path.s3tc="res://.godot/imported/+atek_jump1.png-591efaa80426dde04afa484ece96e2de.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+atek_jump1.png"
+dest_files=["res://.godot/imported/+atek_jump1.png-591efaa80426dde04afa484ece96e2de.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+atek_jump1_emission.png b/3d/first_person_shooter/textures/+atek_jump1_emission.png
new file mode 100644
index 00000000000..4af55e69ec5
Binary files /dev/null and b/3d/first_person_shooter/textures/+atek_jump1_emission.png differ
diff --git a/3d/first_person_shooter/textures/+atek_jump1_emission.png.import b/3d/first_person_shooter/textures/+atek_jump1_emission.png.import
new file mode 100644
index 00000000000..95204874faf
--- /dev/null
+++ b/3d/first_person_shooter/textures/+atek_jump1_emission.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://crx2hsxrq630e"
+path.s3tc="res://.godot/imported/+atek_jump1_emission.png-2379b746da1aa988709d8685e93ec728.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+atek_jump1_emission.png"
+dest_files=["res://.godot/imported/+atek_jump1_emission.png-2379b746da1aa988709d8685e93ec728.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+atlight3.png b/3d/first_person_shooter/textures/+atlight3.png
new file mode 100644
index 00000000000..db27a282ca1
Binary files /dev/null and b/3d/first_person_shooter/textures/+atlight3.png differ
diff --git a/3d/first_person_shooter/textures/+atlight3.png.import b/3d/first_person_shooter/textures/+atlight3.png.import
new file mode 100644
index 00000000000..216bfc4b008
--- /dev/null
+++ b/3d/first_person_shooter/textures/+atlight3.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://h4rgayywl3r6"
+path.s3tc="res://.godot/imported/+atlight3.png-6ade2a16e76544f11e5e7acc903730fd.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+atlight3.png"
+dest_files=["res://.godot/imported/+atlight3.png-6ade2a16e76544f11e5e7acc903730fd.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/+atlight3_emission.png b/3d/first_person_shooter/textures/+atlight3_emission.png
new file mode 100644
index 00000000000..58fd75e67bb
Binary files /dev/null and b/3d/first_person_shooter/textures/+atlight3_emission.png differ
diff --git a/3d/first_person_shooter/textures/+atlight3_emission.png.import b/3d/first_person_shooter/textures/+atlight3_emission.png.import
new file mode 100644
index 00000000000..82d524517c0
--- /dev/null
+++ b/3d/first_person_shooter/textures/+atlight3_emission.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dts1e0bs2l0jk"
+path.s3tc="res://.godot/imported/+atlight3_emission.png-49f166bff7ef636dcb020718371c2382.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/+atlight3_emission.png"
+dest_files=["res://.godot/imported/+atlight3_emission.png-49f166bff7ef636dcb020718371c2382.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/afloor1_4.png b/3d/first_person_shooter/textures/afloor1_4.png
new file mode 100644
index 00000000000..de490d9ace6
Binary files /dev/null and b/3d/first_person_shooter/textures/afloor1_4.png differ
diff --git a/3d/first_person_shooter/textures/afloor1_4.png.import b/3d/first_person_shooter/textures/afloor1_4.png.import
new file mode 100644
index 00000000000..a148b89dde9
--- /dev/null
+++ b/3d/first_person_shooter/textures/afloor1_4.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c0ldlb8o6d1ps"
+path.s3tc="res://.godot/imported/afloor1_4.png-aeff474fa4e06ab78b86fb71ef3e2581.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/afloor1_4.png"
+dest_files=["res://.godot/imported/afloor1_4.png-aeff474fa4e06ab78b86fb71ef3e2581.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/altar1_1.png b/3d/first_person_shooter/textures/altar1_1.png
new file mode 100644
index 00000000000..9cad34c04f3
Binary files /dev/null and b/3d/first_person_shooter/textures/altar1_1.png differ
diff --git a/3d/first_person_shooter/textures/altar1_1.png.import b/3d/first_person_shooter/textures/altar1_1.png.import
new file mode 100644
index 00000000000..063cfc0706f
--- /dev/null
+++ b/3d/first_person_shooter/textures/altar1_1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://n2g2xa72kbi1"
+path.s3tc="res://.godot/imported/altar1_1.png-87d5960dbb6741d333b6f925567e4e07.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/altar1_1.png"
+dest_files=["res://.godot/imported/altar1_1.png-87d5960dbb6741d333b6f925567e4e07.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/altar1_3.png b/3d/first_person_shooter/textures/altar1_3.png
new file mode 100644
index 00000000000..7d08f92b6ed
Binary files /dev/null and b/3d/first_person_shooter/textures/altar1_3.png differ
diff --git a/3d/first_person_shooter/textures/altar1_3.png.import b/3d/first_person_shooter/textures/altar1_3.png.import
new file mode 100644
index 00000000000..b2709864d8f
--- /dev/null
+++ b/3d/first_person_shooter/textures/altar1_3.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://vswbp3felufl"
+path.s3tc="res://.godot/imported/altar1_3.png-065221a6306e40d38c9ff46e2782c65b.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/altar1_3.png"
+dest_files=["res://.godot/imported/altar1_3.png-065221a6306e40d38c9ff46e2782c65b.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/aqf032.png b/3d/first_person_shooter/textures/aqf032.png
new file mode 100644
index 00000000000..4e2d43441f4
Binary files /dev/null and b/3d/first_person_shooter/textures/aqf032.png differ
diff --git a/3d/first_person_shooter/textures/aqf032.png.import b/3d/first_person_shooter/textures/aqf032.png.import
new file mode 100644
index 00000000000..5f2f839aef9
--- /dev/null
+++ b/3d/first_person_shooter/textures/aqf032.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b4ta3k8bw8nb0"
+path.s3tc="res://.godot/imported/aqf032.png-016fbdf3f08dafd09a235b46809544d2.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/aqf032.png"
+dest_files=["res://.godot/imported/aqf032.png-016fbdf3f08dafd09a235b46809544d2.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/aqmetl01.png b/3d/first_person_shooter/textures/aqmetl01.png
new file mode 100644
index 00000000000..266dd192e4e
Binary files /dev/null and b/3d/first_person_shooter/textures/aqmetl01.png differ
diff --git a/3d/first_person_shooter/textures/aqmetl01.png.import b/3d/first_person_shooter/textures/aqmetl01.png.import
new file mode 100644
index 00000000000..596e1163755
--- /dev/null
+++ b/3d/first_person_shooter/textures/aqmetl01.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cowj7p1d7sd8d"
+path.s3tc="res://.godot/imported/aqmetl01.png-00ac639f30e36ba1e5c1f3319a8bb74f.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/aqmetl01.png"
+dest_files=["res://.godot/imported/aqmetl01.png-00ac639f30e36ba1e5c1f3319a8bb74f.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/aqmetl07.png b/3d/first_person_shooter/textures/aqmetl07.png
new file mode 100644
index 00000000000..221c7222ed1
Binary files /dev/null and b/3d/first_person_shooter/textures/aqmetl07.png differ
diff --git a/3d/first_person_shooter/textures/aqmetl07.png.import b/3d/first_person_shooter/textures/aqmetl07.png.import
new file mode 100644
index 00000000000..e51da834825
--- /dev/null
+++ b/3d/first_person_shooter/textures/aqmetl07.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cvsc1lxltvysp"
+path.s3tc="res://.godot/imported/aqmetl07.png-381525f47981da9d2f647b1263750a0e.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/aqmetl07.png"
+dest_files=["res://.godot/imported/aqmetl07.png-381525f47981da9d2f647b1263750a0e.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/aqmetl28.png b/3d/first_person_shooter/textures/aqmetl28.png
new file mode 100644
index 00000000000..3186e9b57f5
Binary files /dev/null and b/3d/first_person_shooter/textures/aqmetl28.png differ
diff --git a/3d/first_person_shooter/textures/aqmetl28.png.import b/3d/first_person_shooter/textures/aqmetl28.png.import
new file mode 100644
index 00000000000..7b46dbf9fba
--- /dev/null
+++ b/3d/first_person_shooter/textures/aqmetl28.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cbuuuhtyjsnxa"
+path.s3tc="res://.godot/imported/aqmetl28.png-c89a3cc0f3071d5320f0cc1c4c12a938.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/aqmetl28.png"
+dest_files=["res://.godot/imported/aqmetl28.png-c89a3cc0f3071d5320f0cc1c4c12a938.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/aqrust04.png b/3d/first_person_shooter/textures/aqrust04.png
new file mode 100644
index 00000000000..63cd6ac7800
Binary files /dev/null and b/3d/first_person_shooter/textures/aqrust04.png differ
diff --git a/3d/first_person_shooter/textures/aqrust04.png.import b/3d/first_person_shooter/textures/aqrust04.png.import
new file mode 100644
index 00000000000..ee3d8b6531d
--- /dev/null
+++ b/3d/first_person_shooter/textures/aqrust04.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://r27ien8x0g5q"
+path.s3tc="res://.godot/imported/aqrust04.png-90b447e33fa8c90603e177e9a0dd682d.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/aqrust04.png"
+dest_files=["res://.godot/imported/aqrust04.png-90b447e33fa8c90603e177e9a0dd682d.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/aqsupp01.png b/3d/first_person_shooter/textures/aqsupp01.png
new file mode 100644
index 00000000000..e980662f97f
Binary files /dev/null and b/3d/first_person_shooter/textures/aqsupp01.png differ
diff --git a/3d/first_person_shooter/textures/aqsupp01.png.import b/3d/first_person_shooter/textures/aqsupp01.png.import
new file mode 100644
index 00000000000..dcc4565c330
--- /dev/null
+++ b/3d/first_person_shooter/textures/aqsupp01.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cdp3jw6h2ffx3"
+path.s3tc="res://.godot/imported/aqsupp01.png-453f3cc1e7c41b0cb0d32dbad651bb24.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/aqsupp01.png"
+dest_files=["res://.godot/imported/aqsupp01.png-453f3cc1e7c41b0cb0d32dbad651bb24.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/aqsupp06.png b/3d/first_person_shooter/textures/aqsupp06.png
new file mode 100644
index 00000000000..7e661abbe21
Binary files /dev/null and b/3d/first_person_shooter/textures/aqsupp06.png differ
diff --git a/3d/first_person_shooter/textures/aqsupp06.png.import b/3d/first_person_shooter/textures/aqsupp06.png.import
new file mode 100644
index 00000000000..476dc3f0d1c
--- /dev/null
+++ b/3d/first_person_shooter/textures/aqsupp06.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dp7vymgwbukx1"
+path.s3tc="res://.godot/imported/aqsupp06.png-38e6fe26302c3188b5de562bdcf9e510.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/aqsupp06.png"
+dest_files=["res://.godot/imported/aqsupp06.png-38e6fe26302c3188b5de562bdcf9e510.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/aqtrim02.png b/3d/first_person_shooter/textures/aqtrim02.png
new file mode 100644
index 00000000000..8e4ffdb0dfe
Binary files /dev/null and b/3d/first_person_shooter/textures/aqtrim02.png differ
diff --git a/3d/first_person_shooter/textures/aqtrim02.png.import b/3d/first_person_shooter/textures/aqtrim02.png.import
new file mode 100644
index 00000000000..621a39f1bc3
--- /dev/null
+++ b/3d/first_person_shooter/textures/aqtrim02.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dcm017vt7pv4j"
+path.s3tc="res://.godot/imported/aqtrim02.png-708e4086337bc9959afc86fd8411699c.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/aqtrim02.png"
+dest_files=["res://.godot/imported/aqtrim02.png-708e4086337bc9959afc86fd8411699c.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/aqtrim08.png b/3d/first_person_shooter/textures/aqtrim08.png
new file mode 100644
index 00000000000..d70ce60ced5
Binary files /dev/null and b/3d/first_person_shooter/textures/aqtrim08.png differ
diff --git a/3d/first_person_shooter/textures/aqtrim08.png.import b/3d/first_person_shooter/textures/aqtrim08.png.import
new file mode 100644
index 00000000000..9067a24bc38
--- /dev/null
+++ b/3d/first_person_shooter/textures/aqtrim08.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dj6pfgggao4m4"
+path.s3tc="res://.godot/imported/aqtrim08.png-a8b60b6300ca1d8993cb368cd9bcfeb9.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/aqtrim08.png"
+dest_files=["res://.godot/imported/aqtrim08.png-a8b60b6300ca1d8993cb368cd9bcfeb9.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/black.png b/3d/first_person_shooter/textures/black.png
new file mode 100644
index 00000000000..eb48deb0f14
Binary files /dev/null and b/3d/first_person_shooter/textures/black.png differ
diff --git a/3d/first_person_shooter/textures/black.png.import b/3d/first_person_shooter/textures/black.png.import
new file mode 100644
index 00000000000..f62bb613a3e
--- /dev/null
+++ b/3d/first_person_shooter/textures/black.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bqmp8q8idwet5"
+path.s3tc="res://.godot/imported/black.png-0262b92e70cb3a77f5677abea62f4776.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/black.png"
+dest_files=["res://.godot/imported/black.png-0262b92e70cb3a77f5677abea62f4776.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/butmet.png b/3d/first_person_shooter/textures/butmet.png
new file mode 100644
index 00000000000..98977186c65
Binary files /dev/null and b/3d/first_person_shooter/textures/butmet.png differ
diff --git a/3d/first_person_shooter/textures/butmet.png.import b/3d/first_person_shooter/textures/butmet.png.import
new file mode 100644
index 00000000000..e586686eb83
--- /dev/null
+++ b/3d/first_person_shooter/textures/butmet.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bipv0taspqrvd"
+path.s3tc="res://.godot/imported/butmet.png-6956f58778e7559cd2789eb4d832e6bc.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/butmet.png"
+dest_files=["res://.godot/imported/butmet.png-6956f58778e7559cd2789eb4d832e6bc.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/comp1_1.png b/3d/first_person_shooter/textures/comp1_1.png
new file mode 100644
index 00000000000..50db542badd
Binary files /dev/null and b/3d/first_person_shooter/textures/comp1_1.png differ
diff --git a/3d/first_person_shooter/textures/comp1_1.png.import b/3d/first_person_shooter/textures/comp1_1.png.import
new file mode 100644
index 00000000000..fb986428767
--- /dev/null
+++ b/3d/first_person_shooter/textures/comp1_1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bkphnk1rn4hnc"
+path.s3tc="res://.godot/imported/comp1_1.png-a6c74a8d64bf6b10c99d8d88091a1062.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/comp1_1.png"
+dest_files=["res://.godot/imported/comp1_1.png-a6c74a8d64bf6b10c99d8d88091a1062.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/comp1_2.png b/3d/first_person_shooter/textures/comp1_2.png
new file mode 100644
index 00000000000..5f5527767af
Binary files /dev/null and b/3d/first_person_shooter/textures/comp1_2.png differ
diff --git a/3d/first_person_shooter/textures/comp1_2.png.import b/3d/first_person_shooter/textures/comp1_2.png.import
new file mode 100644
index 00000000000..99d4f3623d4
--- /dev/null
+++ b/3d/first_person_shooter/textures/comp1_2.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://k3blb3hittel"
+path.s3tc="res://.godot/imported/comp1_2.png-cd6ffdc527a81abab248a2272c5111e0.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/comp1_2.png"
+dest_files=["res://.godot/imported/comp1_2.png-cd6ffdc527a81abab248a2272c5111e0.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/comp1_3.png b/3d/first_person_shooter/textures/comp1_3.png
new file mode 100644
index 00000000000..d9f66679ec7
Binary files /dev/null and b/3d/first_person_shooter/textures/comp1_3.png differ
diff --git a/3d/first_person_shooter/textures/comp1_3.png.import b/3d/first_person_shooter/textures/comp1_3.png.import
new file mode 100644
index 00000000000..f61965faf67
--- /dev/null
+++ b/3d/first_person_shooter/textures/comp1_3.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://2e0klct56l3l"
+path.s3tc="res://.godot/imported/comp1_3.png-02b770496226036e1ccc1cf4d6876de9.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/comp1_3.png"
+dest_files=["res://.godot/imported/comp1_3.png-02b770496226036e1ccc1cf4d6876de9.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/comp1_6.png b/3d/first_person_shooter/textures/comp1_6.png
new file mode 100644
index 00000000000..a6032d715b2
Binary files /dev/null and b/3d/first_person_shooter/textures/comp1_6.png differ
diff --git a/3d/first_person_shooter/textures/comp1_6.png.import b/3d/first_person_shooter/textures/comp1_6.png.import
new file mode 100644
index 00000000000..af46443907b
--- /dev/null
+++ b/3d/first_person_shooter/textures/comp1_6.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ck3fo3dkpbcec"
+path.s3tc="res://.godot/imported/comp1_6.png-5d28f3e2d50af6f7a3e1f44b158334b3.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/comp1_6.png"
+dest_files=["res://.godot/imported/comp1_6.png-5d28f3e2d50af6f7a3e1f44b158334b3.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/compbase.png b/3d/first_person_shooter/textures/compbase.png
new file mode 100644
index 00000000000..2f594a9b8a5
Binary files /dev/null and b/3d/first_person_shooter/textures/compbase.png differ
diff --git a/3d/first_person_shooter/textures/compbase.png.import b/3d/first_person_shooter/textures/compbase.png.import
new file mode 100644
index 00000000000..549320bcc48
--- /dev/null
+++ b/3d/first_person_shooter/textures/compbase.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bww87j7x55rg2"
+path.s3tc="res://.godot/imported/compbase.png-d562d98b860aa06ca30404728673cf32.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/compbase.png"
+dest_files=["res://.godot/imported/compbase.png-d562d98b860aa06ca30404728673cf32.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/crate0_s_bottom.png b/3d/first_person_shooter/textures/crate0_s_bottom.png
new file mode 100644
index 00000000000..deb028040f7
Binary files /dev/null and b/3d/first_person_shooter/textures/crate0_s_bottom.png differ
diff --git a/3d/first_person_shooter/textures/crate0_s_bottom.png.import b/3d/first_person_shooter/textures/crate0_s_bottom.png.import
new file mode 100644
index 00000000000..86ed696e241
--- /dev/null
+++ b/3d/first_person_shooter/textures/crate0_s_bottom.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b2h4ef4vq2ro1"
+path.s3tc="res://.godot/imported/crate0_s_bottom.png-e9c5f8140a2704506543a0cc75ef1e27.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/crate0_s_bottom.png"
+dest_files=["res://.godot/imported/crate0_s_bottom.png-e9c5f8140a2704506543a0cc75ef1e27.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/crate0_s_sside.png b/3d/first_person_shooter/textures/crate0_s_sside.png
new file mode 100644
index 00000000000..aac0fed507f
Binary files /dev/null and b/3d/first_person_shooter/textures/crate0_s_sside.png differ
diff --git a/3d/first_person_shooter/textures/crate0_s_sside.png.import b/3d/first_person_shooter/textures/crate0_s_sside.png.import
new file mode 100644
index 00000000000..726ccc6dc46
--- /dev/null
+++ b/3d/first_person_shooter/textures/crate0_s_sside.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://qylwy4h65iiu"
+path.s3tc="res://.godot/imported/crate0_s_sside.png-0eb5119b0a9dc6369caeffcd87f4afa8.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/crate0_s_sside.png"
+dest_files=["res://.godot/imported/crate0_s_sside.png-0eb5119b0a9dc6369caeffcd87f4afa8.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/crate0_s_top.png b/3d/first_person_shooter/textures/crate0_s_top.png
new file mode 100644
index 00000000000..686ba14908f
Binary files /dev/null and b/3d/first_person_shooter/textures/crate0_s_top.png differ
diff --git a/3d/first_person_shooter/textures/crate0_s_top.png.import b/3d/first_person_shooter/textures/crate0_s_top.png.import
new file mode 100644
index 00000000000..be0bd28d397
--- /dev/null
+++ b/3d/first_person_shooter/textures/crate0_s_top.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dc20qp44t5icu"
+path.s3tc="res://.godot/imported/crate0_s_top.png-0bb2c28b6c1edae6db1d137973b995f0.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/crate0_s_top.png"
+dest_files=["res://.godot/imported/crate0_s_top.png-0bb2c28b6c1edae6db1d137973b995f0.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/crate0_s_tside.png b/3d/first_person_shooter/textures/crate0_s_tside.png
new file mode 100644
index 00000000000..5322894ea70
Binary files /dev/null and b/3d/first_person_shooter/textures/crate0_s_tside.png differ
diff --git a/3d/first_person_shooter/textures/crate0_s_tside.png.import b/3d/first_person_shooter/textures/crate0_s_tside.png.import
new file mode 100644
index 00000000000..72da20fd448
--- /dev/null
+++ b/3d/first_person_shooter/textures/crate0_s_tside.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bnxii4inwexsk"
+path.s3tc="res://.godot/imported/crate0_s_tside.png-065584174e046fc9146adc5334e53aa7.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/crate0_s_tside.png"
+dest_files=["res://.godot/imported/crate0_s_tside.png-065584174e046fc9146adc5334e53aa7.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/crate0_side.png b/3d/first_person_shooter/textures/crate0_side.png
new file mode 100644
index 00000000000..c3174a58110
Binary files /dev/null and b/3d/first_person_shooter/textures/crate0_side.png differ
diff --git a/3d/first_person_shooter/textures/crate0_side.png.import b/3d/first_person_shooter/textures/crate0_side.png.import
new file mode 100644
index 00000000000..a1529185b57
--- /dev/null
+++ b/3d/first_person_shooter/textures/crate0_side.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://nuw3mvxmuija"
+path.s3tc="res://.godot/imported/crate0_side.png-304b0f0296986ae35b902e1b586cec3f.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/crate0_side.png"
+dest_files=["res://.godot/imported/crate0_side.png-304b0f0296986ae35b902e1b586cec3f.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/crate0_top.png b/3d/first_person_shooter/textures/crate0_top.png
new file mode 100644
index 00000000000..bf8e8ad3556
Binary files /dev/null and b/3d/first_person_shooter/textures/crate0_top.png differ
diff --git a/3d/first_person_shooter/textures/crate0_top.png.import b/3d/first_person_shooter/textures/crate0_top.png.import
new file mode 100644
index 00000000000..ac6c8385769
--- /dev/null
+++ b/3d/first_person_shooter/textures/crate0_top.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dom3fh6ynj3op"
+path.s3tc="res://.godot/imported/crate0_top.png-df108ff80d1c765e664d528a239a0e65.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/crate0_top.png"
+dest_files=["res://.godot/imported/crate0_top.png-df108ff80d1c765e664d528a239a0e65.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/crate1_side.png b/3d/first_person_shooter/textures/crate1_side.png
new file mode 100644
index 00000000000..4026c9a1765
Binary files /dev/null and b/3d/first_person_shooter/textures/crate1_side.png differ
diff --git a/3d/first_person_shooter/textures/crate1_side.png.import b/3d/first_person_shooter/textures/crate1_side.png.import
new file mode 100644
index 00000000000..eea5b091882
--- /dev/null
+++ b/3d/first_person_shooter/textures/crate1_side.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://thugqmgnuhva"
+path.s3tc="res://.godot/imported/crate1_side.png-a6d7b45107f06135245ee1732e4ea453.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/crate1_side.png"
+dest_files=["res://.godot/imported/crate1_side.png-a6d7b45107f06135245ee1732e4ea453.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/crate1_top.png b/3d/first_person_shooter/textures/crate1_top.png
new file mode 100644
index 00000000000..17340f120bc
Binary files /dev/null and b/3d/first_person_shooter/textures/crate1_top.png differ
diff --git a/3d/first_person_shooter/textures/crate1_top.png.import b/3d/first_person_shooter/textures/crate1_top.png.import
new file mode 100644
index 00000000000..402cd1758ea
--- /dev/null
+++ b/3d/first_person_shooter/textures/crate1_top.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://eilgujop8gmb"
+path.s3tc="res://.godot/imported/crate1_top.png-031ce277d346ae7e63130e2495094433.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/crate1_top.png"
+dest_files=["res://.godot/imported/crate1_top.png-031ce277d346ae7e63130e2495094433.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/dem4_4.png b/3d/first_person_shooter/textures/dem4_4.png
new file mode 100644
index 00000000000..e534cd9124a
Binary files /dev/null and b/3d/first_person_shooter/textures/dem4_4.png differ
diff --git a/3d/first_person_shooter/textures/dem4_4.png.import b/3d/first_person_shooter/textures/dem4_4.png.import
new file mode 100644
index 00000000000..9e8b96dd81d
--- /dev/null
+++ b/3d/first_person_shooter/textures/dem4_4.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://djbcp2k24twrn"
+path.s3tc="res://.godot/imported/dem4_4.png-c8ac72e69fdf9cf37add4b1d452972d3.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/dem4_4.png"
+dest_files=["res://.godot/imported/dem4_4.png-c8ac72e69fdf9cf37add4b1d452972d3.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/door02_1.png b/3d/first_person_shooter/textures/door02_1.png
new file mode 100644
index 00000000000..afa8e3c88c8
Binary files /dev/null and b/3d/first_person_shooter/textures/door02_1.png differ
diff --git a/3d/first_person_shooter/textures/door02_1.png.import b/3d/first_person_shooter/textures/door02_1.png.import
new file mode 100644
index 00000000000..895ca00008c
--- /dev/null
+++ b/3d/first_person_shooter/textures/door02_1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://l4o3d0rmkplk"
+path.s3tc="res://.godot/imported/door02_1.png-870bd8f1f7628fb46e2a2f6c7dfc58f5.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/door02_1.png"
+dest_files=["res://.godot/imported/door02_1.png-870bd8f1f7628fb46e2a2f6c7dfc58f5.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/doortrak1.png b/3d/first_person_shooter/textures/doortrak1.png
new file mode 100644
index 00000000000..3f11692f2ab
Binary files /dev/null and b/3d/first_person_shooter/textures/doortrak1.png differ
diff --git a/3d/first_person_shooter/textures/doortrak1.png.import b/3d/first_person_shooter/textures/doortrak1.png.import
new file mode 100644
index 00000000000..9050b7a17f1
--- /dev/null
+++ b/3d/first_person_shooter/textures/doortrak1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bapaafhiy6t8p"
+path.s3tc="res://.godot/imported/doortrak1.png-4b2a50ace24515f5184b994b7d627c07.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/doortrak1.png"
+dest_files=["res://.godot/imported/doortrak1.png-4b2a50ace24515f5184b994b7d627c07.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/doortrak2.png b/3d/first_person_shooter/textures/doortrak2.png
new file mode 100644
index 00000000000..7842621964d
Binary files /dev/null and b/3d/first_person_shooter/textures/doortrak2.png differ
diff --git a/3d/first_person_shooter/textures/doortrak2.png.import b/3d/first_person_shooter/textures/doortrak2.png.import
new file mode 100644
index 00000000000..9cb425de5f1
--- /dev/null
+++ b/3d/first_person_shooter/textures/doortrak2.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://be8fh5cbnms5w"
+path.s3tc="res://.godot/imported/doortrak2.png-d583610291045a55d97456eee3f2b616.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/doortrak2.png"
+dest_files=["res://.godot/imported/doortrak2.png-d583610291045a55d97456eee3f2b616.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/edoor01_1.png b/3d/first_person_shooter/textures/edoor01_1.png
new file mode 100644
index 00000000000..52f6f3bfa32
Binary files /dev/null and b/3d/first_person_shooter/textures/edoor01_1.png differ
diff --git a/3d/first_person_shooter/textures/edoor01_1.png.import b/3d/first_person_shooter/textures/edoor01_1.png.import
new file mode 100644
index 00000000000..cfd59dd4779
--- /dev/null
+++ b/3d/first_person_shooter/textures/edoor01_1.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cyikcijcuq7ka"
+path="res://.godot/imported/edoor01_1.png-e7f65eb666f9ebc605f6ed88847fca79.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://textures/edoor01_1.png"
+dest_files=["res://.godot/imported/edoor01_1.png-e7f65eb666f9ebc605f6ed88847fca79.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/3d/first_person_shooter/textures/edoor02.png b/3d/first_person_shooter/textures/edoor02.png
new file mode 100644
index 00000000000..145678d304e
Binary files /dev/null and b/3d/first_person_shooter/textures/edoor02.png differ
diff --git a/3d/first_person_shooter/textures/edoor02.png.import b/3d/first_person_shooter/textures/edoor02.png.import
new file mode 100644
index 00000000000..de757ccccf8
--- /dev/null
+++ b/3d/first_person_shooter/textures/edoor02.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dd726h0lwtw4t"
+path="res://.godot/imported/edoor02.png-a73fc5303f8d5c77bbe35dd97f701ee4.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://textures/edoor02.png"
+dest_files=["res://.godot/imported/edoor02.png-a73fc5303f8d5c77bbe35dd97f701ee4.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/3d/first_person_shooter/textures/flat4.png b/3d/first_person_shooter/textures/flat4.png
new file mode 100644
index 00000000000..d0978c4e5fa
Binary files /dev/null and b/3d/first_person_shooter/textures/flat4.png differ
diff --git a/3d/first_person_shooter/textures/flat4.png.import b/3d/first_person_shooter/textures/flat4.png.import
new file mode 100644
index 00000000000..5e1898c52d8
--- /dev/null
+++ b/3d/first_person_shooter/textures/flat4.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ntsny1xyvlto"
+path.s3tc="res://.godot/imported/flat4.png-ff30fedf6673e95d15ecaf20597e9d7d.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/flat4.png"
+dest_files=["res://.godot/imported/flat4.png-ff30fedf6673e95d15ecaf20597e9d7d.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/gravel1.png b/3d/first_person_shooter/textures/gravel1.png
new file mode 100644
index 00000000000..e7ef5c58876
Binary files /dev/null and b/3d/first_person_shooter/textures/gravel1.png differ
diff --git a/3d/first_person_shooter/textures/gravel1.png.import b/3d/first_person_shooter/textures/gravel1.png.import
new file mode 100644
index 00000000000..e376ea27fa1
--- /dev/null
+++ b/3d/first_person_shooter/textures/gravel1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://chue0ny2ti6es"
+path.s3tc="res://.godot/imported/gravel1.png-3b1d4fe7901136015b87d4343db42123.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/gravel1.png"
+dest_files=["res://.godot/imported/gravel1.png-3b1d4fe7901136015b87d4343db42123.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/hint.png b/3d/first_person_shooter/textures/hint.png
new file mode 100644
index 00000000000..b65dfddb2cc
Binary files /dev/null and b/3d/first_person_shooter/textures/hint.png differ
diff --git a/3d/first_person_shooter/textures/hint.png.import b/3d/first_person_shooter/textures/hint.png.import
new file mode 100644
index 00000000000..aa600f72ef2
--- /dev/null
+++ b/3d/first_person_shooter/textures/hint.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b64n0jgu68t0a"
+path="res://.godot/imported/hint.png-1d27e9f6c38f4a6ed7b9e9a31c104a11.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://textures/hint.png"
+dest_files=["res://.godot/imported/hint.png-1d27e9f6c38f4a6ed7b9e9a31c104a11.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/3d/first_person_shooter/textures/hintskip.png b/3d/first_person_shooter/textures/hintskip.png
new file mode 100644
index 00000000000..bbc03fb8169
Binary files /dev/null and b/3d/first_person_shooter/textures/hintskip.png differ
diff --git a/3d/first_person_shooter/textures/hintskip.png.import b/3d/first_person_shooter/textures/hintskip.png.import
new file mode 100644
index 00000000000..dbe98b20fa2
--- /dev/null
+++ b/3d/first_person_shooter/textures/hintskip.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://drseq0qlguywt"
+path.s3tc="res://.godot/imported/hintskip.png-a4294831e9c4ad6acaf3851405784dcf.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/hintskip.png"
+dest_files=["res://.godot/imported/hintskip.png-a4294831e9c4ad6acaf3851405784dcf.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/lasergrid.png b/3d/first_person_shooter/textures/lasergrid.png
new file mode 100644
index 00000000000..f27ed313cee
Binary files /dev/null and b/3d/first_person_shooter/textures/lasergrid.png differ
diff --git a/3d/first_person_shooter/textures/lasergrid.png.import b/3d/first_person_shooter/textures/lasergrid.png.import
new file mode 100644
index 00000000000..eff0476f1fc
--- /dev/null
+++ b/3d/first_person_shooter/textures/lasergrid.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bgfi5cu5ywvgs"
+path="res://.godot/imported/lasergrid.png-976210eafea1124b2f2d4aa41607e9ce.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://textures/lasergrid.png"
+dest_files=["res://.godot/imported/lasergrid.png-976210eafea1124b2f2d4aa41607e9ce.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/3d/first_person_shooter/textures/light2.png b/3d/first_person_shooter/textures/light2.png
new file mode 100644
index 00000000000..eb157394978
Binary files /dev/null and b/3d/first_person_shooter/textures/light2.png differ
diff --git a/3d/first_person_shooter/textures/light2.png.import b/3d/first_person_shooter/textures/light2.png.import
new file mode 100644
index 00000000000..7811fb5de0e
--- /dev/null
+++ b/3d/first_person_shooter/textures/light2.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cnfr04jc5udof"
+path.s3tc="res://.godot/imported/light2.png-1f6eccf3ba9f01a5ebdae55c8a48f87c.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/light2.png"
+dest_files=["res://.godot/imported/light2.png-1f6eccf3ba9f01a5ebdae55c8a48f87c.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/lit8sfb.png b/3d/first_person_shooter/textures/lit8sfb.png
new file mode 100644
index 00000000000..fd3a7e0007b
Binary files /dev/null and b/3d/first_person_shooter/textures/lit8sfb.png differ
diff --git a/3d/first_person_shooter/textures/lit8sfb.png.import b/3d/first_person_shooter/textures/lit8sfb.png.import
new file mode 100644
index 00000000000..92dc59e8eba
--- /dev/null
+++ b/3d/first_person_shooter/textures/lit8sfb.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cuvhj445fwx1o"
+path.s3tc="res://.godot/imported/lit8sfb.png-2e38af1325d8c8efef1d7057fbc30857.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/lit8sfb.png"
+dest_files=["res://.godot/imported/lit8sfb.png-2e38af1325d8c8efef1d7057fbc30857.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/lit8sfb_emission.png b/3d/first_person_shooter/textures/lit8sfb_emission.png
new file mode 100644
index 00000000000..0ef4a18a05e
Binary files /dev/null and b/3d/first_person_shooter/textures/lit8sfb_emission.png differ
diff --git a/3d/first_person_shooter/textures/lit8sfb_emission.png.import b/3d/first_person_shooter/textures/lit8sfb_emission.png.import
new file mode 100644
index 00000000000..6a7056360f2
--- /dev/null
+++ b/3d/first_person_shooter/textures/lit8sfb_emission.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b17d8o60u8tri"
+path.s3tc="res://.godot/imported/lit8sfb_emission.png-544507236a67ef24aa61fc624e4460d5.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/lit8sfb_emission.png"
+dest_files=["res://.godot/imported/lit8sfb_emission.png-544507236a67ef24aa61fc624e4460d5.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/med_cmet4.png b/3d/first_person_shooter/textures/med_cmet4.png
new file mode 100644
index 00000000000..0da953384ab
Binary files /dev/null and b/3d/first_person_shooter/textures/med_cmet4.png differ
diff --git a/3d/first_person_shooter/textures/med_cmet4.png.import b/3d/first_person_shooter/textures/med_cmet4.png.import
new file mode 100644
index 00000000000..8eb99bd4d8f
--- /dev/null
+++ b/3d/first_person_shooter/textures/med_cmet4.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://tv56cnriiayi"
+path.s3tc="res://.godot/imported/med_cmet4.png-c3b23b3e74588df0cc08069d759c43a4.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/med_cmet4.png"
+dest_files=["res://.godot/imported/med_cmet4.png-c3b23b3e74588df0cc08069d759c43a4.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/med_csl_stp1.png b/3d/first_person_shooter/textures/med_csl_stp1.png
new file mode 100644
index 00000000000..6e8d7649d02
Binary files /dev/null and b/3d/first_person_shooter/textures/med_csl_stp1.png differ
diff --git a/3d/first_person_shooter/textures/med_csl_stp1.png.import b/3d/first_person_shooter/textures/med_csl_stp1.png.import
new file mode 100644
index 00000000000..46cd6b3733f
--- /dev/null
+++ b/3d/first_person_shooter/textures/med_csl_stp1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bkuppe4e7yrw7"
+path.s3tc="res://.godot/imported/med_csl_stp1.png-5d6c512f82e04d059b5c3e326f6ba0db.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/med_csl_stp1.png"
+dest_files=["res://.godot/imported/med_csl_stp1.png-5d6c512f82e04d059b5c3e326f6ba0db.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/med_dbrick6b.png b/3d/first_person_shooter/textures/med_dbrick6b.png
new file mode 100644
index 00000000000..319e0533238
Binary files /dev/null and b/3d/first_person_shooter/textures/med_dbrick6b.png differ
diff --git a/3d/first_person_shooter/textures/med_dbrick6b.png.import b/3d/first_person_shooter/textures/med_dbrick6b.png.import
new file mode 100644
index 00000000000..7df9580ab1b
--- /dev/null
+++ b/3d/first_person_shooter/textures/med_dbrick6b.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c2oplyx2ix0bh"
+path.s3tc="res://.godot/imported/med_dbrick6b.png-b720b4e0d3244b87a62b9cfebbf30af5.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/med_dbrick6b.png"
+dest_files=["res://.godot/imported/med_dbrick6b.png-b720b4e0d3244b87a62b9cfebbf30af5.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/met2.png b/3d/first_person_shooter/textures/met2.png
new file mode 100644
index 00000000000..f0bf1d238fb
Binary files /dev/null and b/3d/first_person_shooter/textures/met2.png differ
diff --git a/3d/first_person_shooter/textures/met2.png.import b/3d/first_person_shooter/textures/met2.png.import
new file mode 100644
index 00000000000..021fd2e63ae
--- /dev/null
+++ b/3d/first_person_shooter/textures/met2.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://craapn6m4wju7"
+path.s3tc="res://.godot/imported/met2.png-aeda0f3ba08b6e23e3a0814e91088341.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/met2.png"
+dest_files=["res://.godot/imported/met2.png-aeda0f3ba08b6e23e3a0814e91088341.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/plat_side1.png b/3d/first_person_shooter/textures/plat_side1.png
new file mode 100644
index 00000000000..b89f252ad7a
Binary files /dev/null and b/3d/first_person_shooter/textures/plat_side1.png differ
diff --git a/3d/first_person_shooter/textures/plat_side1.png.import b/3d/first_person_shooter/textures/plat_side1.png.import
new file mode 100644
index 00000000000..7cc1572c195
--- /dev/null
+++ b/3d/first_person_shooter/textures/plat_side1.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cchkdwswwwm7a"
+path="res://.godot/imported/plat_side1.png-be624b2507e36ecbb9701e29f5971424.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://textures/plat_side1.png"
+dest_files=["res://.godot/imported/plat_side1.png-be624b2507e36ecbb9701e29f5971424.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/3d/first_person_shooter/textures/plat_stem.png b/3d/first_person_shooter/textures/plat_stem.png
new file mode 100644
index 00000000000..5d725f0c49a
Binary files /dev/null and b/3d/first_person_shooter/textures/plat_stem.png differ
diff --git a/3d/first_person_shooter/textures/plat_stem.png.import b/3d/first_person_shooter/textures/plat_stem.png.import
new file mode 100644
index 00000000000..c284e0bee6d
--- /dev/null
+++ b/3d/first_person_shooter/textures/plat_stem.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ct3v2bxxmmsbq"
+path.s3tc="res://.godot/imported/plat_stem.png-240848717e29c4d10be39449baa76318.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/plat_stem.png"
+dest_files=["res://.godot/imported/plat_stem.png-240848717e29c4d10be39449baa76318.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/plat_top1.png b/3d/first_person_shooter/textures/plat_top1.png
new file mode 100644
index 00000000000..79be86fceae
Binary files /dev/null and b/3d/first_person_shooter/textures/plat_top1.png differ
diff --git a/3d/first_person_shooter/textures/plat_top1.png.import b/3d/first_person_shooter/textures/plat_top1.png.import
new file mode 100644
index 00000000000..c4fe7ea9404
--- /dev/null
+++ b/3d/first_person_shooter/textures/plat_top1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://v27uatdpmgih"
+path.s3tc="res://.godot/imported/plat_top1.png-b1fd66e5027971669be1974142901422.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/plat_top1.png"
+dest_files=["res://.godot/imported/plat_top1.png-b1fd66e5027971669be1974142901422.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/plat_top2.png b/3d/first_person_shooter/textures/plat_top2.png
new file mode 100644
index 00000000000..bf44abbedf2
Binary files /dev/null and b/3d/first_person_shooter/textures/plat_top2.png differ
diff --git a/3d/first_person_shooter/textures/plat_top2.png.import b/3d/first_person_shooter/textures/plat_top2.png.import
new file mode 100644
index 00000000000..34f7cf62bb2
--- /dev/null
+++ b/3d/first_person_shooter/textures/plat_top2.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://btekr8knr7vb6"
+path.s3tc="res://.godot/imported/plat_top2.png-8dbbc7b2fec1f4130435732534e71d0f.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/plat_top2.png"
+dest_files=["res://.godot/imported/plat_top2.png-8dbbc7b2fec1f4130435732534e71d0f.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/rocks07.png b/3d/first_person_shooter/textures/rocks07.png
new file mode 100644
index 00000000000..5f21156dbe0
Binary files /dev/null and b/3d/first_person_shooter/textures/rocks07.png differ
diff --git a/3d/first_person_shooter/textures/rocks07.png.import b/3d/first_person_shooter/textures/rocks07.png.import
new file mode 100644
index 00000000000..7786118ad5c
--- /dev/null
+++ b/3d/first_person_shooter/textures/rocks07.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://xcrhm1mwn63c"
+path.s3tc="res://.godot/imported/rocks07.png-b33660f07250e092f381a8432e90c9f8.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/rocks07.png"
+dest_files=["res://.godot/imported/rocks07.png-b33660f07250e092f381a8432e90c9f8.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/rocks11d.png b/3d/first_person_shooter/textures/rocks11d.png
new file mode 100644
index 00000000000..bfae45f71e1
Binary files /dev/null and b/3d/first_person_shooter/textures/rocks11d.png differ
diff --git a/3d/first_person_shooter/textures/rocks11d.png.import b/3d/first_person_shooter/textures/rocks11d.png.import
new file mode 100644
index 00000000000..b91ce6ea86e
--- /dev/null
+++ b/3d/first_person_shooter/textures/rocks11d.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://beaa3jy7p4gcq"
+path.s3tc="res://.godot/imported/rocks11d.png-680048ec095abd8ea117e6330156a403.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/rocks11d.png"
+dest_files=["res://.godot/imported/rocks11d.png-680048ec095abd8ea117e6330156a403.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/rocks11e.png b/3d/first_person_shooter/textures/rocks11e.png
new file mode 100644
index 00000000000..b50ccecb5d3
Binary files /dev/null and b/3d/first_person_shooter/textures/rocks11e.png differ
diff --git a/3d/first_person_shooter/textures/rocks11e.png.import b/3d/first_person_shooter/textures/rocks11e.png.import
new file mode 100644
index 00000000000..bc13880a189
--- /dev/null
+++ b/3d/first_person_shooter/textures/rocks11e.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://3nuod7o6qx4w"
+path.s3tc="res://.godot/imported/rocks11e.png-961833f8de35a55b9308785049bb73b3.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/rocks11e.png"
+dest_files=["res://.godot/imported/rocks11e.png-961833f8de35a55b9308785049bb73b3.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/rw33_3.png b/3d/first_person_shooter/textures/rw33_3.png
new file mode 100644
index 00000000000..ea7e90d0dc6
Binary files /dev/null and b/3d/first_person_shooter/textures/rw33_3.png differ
diff --git a/3d/first_person_shooter/textures/rw33_3.png.import b/3d/first_person_shooter/textures/rw33_3.png.import
new file mode 100644
index 00000000000..adeb5d3ec3b
--- /dev/null
+++ b/3d/first_person_shooter/textures/rw33_3.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d4fgps7a3fi8k"
+path.s3tc="res://.godot/imported/rw33_3.png-5a1762195affee8362168eef399b2d4e.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/rw33_3.png"
+dest_files=["res://.godot/imported/rw33_3.png-5a1762195affee8362168eef399b2d4e.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/rw33_flat.png b/3d/first_person_shooter/textures/rw33_flat.png
new file mode 100644
index 00000000000..254e7e61925
Binary files /dev/null and b/3d/first_person_shooter/textures/rw33_flat.png differ
diff --git a/3d/first_person_shooter/textures/rw33_flat.png.import b/3d/first_person_shooter/textures/rw33_flat.png.import
new file mode 100644
index 00000000000..9d3776cd7d9
--- /dev/null
+++ b/3d/first_person_shooter/textures/rw33_flat.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://culjk4b7cpyy6"
+path.s3tc="res://.godot/imported/rw33_flat.png-88236cf98c28219bed03f411a04cf41c.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/rw33_flat.png"
+dest_files=["res://.godot/imported/rw33_flat.png-88236cf98c28219bed03f411a04cf41c.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/rw33_lit.png b/3d/first_person_shooter/textures/rw33_lit.png
new file mode 100644
index 00000000000..6c518d11411
Binary files /dev/null and b/3d/first_person_shooter/textures/rw33_lit.png differ
diff --git a/3d/first_person_shooter/textures/rw33_lit.png.import b/3d/first_person_shooter/textures/rw33_lit.png.import
new file mode 100644
index 00000000000..f83e2a8eee1
--- /dev/null
+++ b/3d/first_person_shooter/textures/rw33_lit.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dg6gef57yx0ls"
+path.s3tc="res://.godot/imported/rw33_lit.png-1bc1ca0242c8f639fea71721761b5497.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/rw33_lit.png"
+dest_files=["res://.godot/imported/rw33_lit.png-1bc1ca0242c8f639fea71721761b5497.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/rw33b_1.png b/3d/first_person_shooter/textures/rw33b_1.png
new file mode 100644
index 00000000000..0ef60c59974
Binary files /dev/null and b/3d/first_person_shooter/textures/rw33b_1.png differ
diff --git a/3d/first_person_shooter/textures/rw33b_1.png.import b/3d/first_person_shooter/textures/rw33b_1.png.import
new file mode 100644
index 00000000000..155abe21a68
--- /dev/null
+++ b/3d/first_person_shooter/textures/rw33b_1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d6wy1n4yuwvo"
+path.s3tc="res://.godot/imported/rw33b_1.png-d152b07c301a526fae0995e1d14f3931.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/rw33b_1.png"
+dest_files=["res://.godot/imported/rw33b_1.png-d152b07c301a526fae0995e1d14f3931.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/rw33b_flat.png b/3d/first_person_shooter/textures/rw33b_flat.png
new file mode 100644
index 00000000000..2f843a46880
Binary files /dev/null and b/3d/first_person_shooter/textures/rw33b_flat.png differ
diff --git a/3d/first_person_shooter/textures/rw33b_flat.png.import b/3d/first_person_shooter/textures/rw33b_flat.png.import
new file mode 100644
index 00000000000..2d2cca430f2
--- /dev/null
+++ b/3d/first_person_shooter/textures/rw33b_flat.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://vyor2ffwp137"
+path.s3tc="res://.godot/imported/rw33b_flat.png-424293b261b5c63da928f07be1248f03.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/rw33b_flat.png"
+dest_files=["res://.godot/imported/rw33b_flat.png-424293b261b5c63da928f07be1248f03.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/sky5.png b/3d/first_person_shooter/textures/sky5.png
new file mode 100644
index 00000000000..04327c49c66
Binary files /dev/null and b/3d/first_person_shooter/textures/sky5.png differ
diff --git a/3d/first_person_shooter/textures/sky5.png.import b/3d/first_person_shooter/textures/sky5.png.import
new file mode 100644
index 00000000000..6cd352a31ae
--- /dev/null
+++ b/3d/first_person_shooter/textures/sky5.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://1a2kkt6fdovh"
+path.s3tc="res://.godot/imported/sky5.png-b7a12354be950e80b30484a9e62fb671.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/sky5.png"
+dest_files=["res://.godot/imported/sky5.png-b7a12354be950e80b30484a9e62fb671.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/sky5_emission.png b/3d/first_person_shooter/textures/sky5_emission.png
new file mode 100644
index 00000000000..3dcad686ac0
Binary files /dev/null and b/3d/first_person_shooter/textures/sky5_emission.png differ
diff --git a/3d/first_person_shooter/textures/sky5_emission.png.import b/3d/first_person_shooter/textures/sky5_emission.png.import
new file mode 100644
index 00000000000..dd4607b4027
--- /dev/null
+++ b/3d/first_person_shooter/textures/sky5_emission.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cc45vw80lpmhc"
+path="res://.godot/imported/sky5_emission.png-e3579efa1f750169f670b50079486f31.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://textures/sky5_emission.png"
+dest_files=["res://.godot/imported/sky5_emission.png-e3579efa1f750169f670b50079486f31.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/3d/first_person_shooter/textures/slime2.png b/3d/first_person_shooter/textures/slime2.png
new file mode 100644
index 00000000000..fc591c25275
Binary files /dev/null and b/3d/first_person_shooter/textures/slime2.png differ
diff --git a/3d/first_person_shooter/textures/slime2.png.import b/3d/first_person_shooter/textures/slime2.png.import
new file mode 100644
index 00000000000..79cc87b003d
--- /dev/null
+++ b/3d/first_person_shooter/textures/slime2.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c81nhf4ab8k5f"
+path.s3tc="res://.godot/imported/slime2.png-e5812afae9d77bd6a07ef70216392b76.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/slime2.png"
+dest_files=["res://.godot/imported/slime2.png-e5812afae9d77bd6a07ef70216392b76.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/spotlight.png b/3d/first_person_shooter/textures/spotlight.png
new file mode 100644
index 00000000000..8dc1acfd85c
Binary files /dev/null and b/3d/first_person_shooter/textures/spotlight.png differ
diff --git a/3d/first_person_shooter/textures/spotlight.png.import b/3d/first_person_shooter/textures/spotlight.png.import
new file mode 100644
index 00000000000..43dbc6128fc
--- /dev/null
+++ b/3d/first_person_shooter/textures/spotlight.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c7xrpxi8a6eqc"
+path.s3tc="res://.godot/imported/spotlight.png-c0bdf494fd950f664f16ea49e765523f.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/spotlight.png"
+dest_files=["res://.godot/imported/spotlight.png-c0bdf494fd950f664f16ea49e765523f.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/spotlight_emission.png b/3d/first_person_shooter/textures/spotlight_emission.png
new file mode 100644
index 00000000000..48a5a861bd7
Binary files /dev/null and b/3d/first_person_shooter/textures/spotlight_emission.png differ
diff --git a/3d/first_person_shooter/textures/spotlight_emission.png.import b/3d/first_person_shooter/textures/spotlight_emission.png.import
new file mode 100644
index 00000000000..c58440e62ae
--- /dev/null
+++ b/3d/first_person_shooter/textures/spotlight_emission.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://be7ld8w2f84h"
+path.s3tc="res://.godot/imported/spotlight_emission.png-067a05eeab910250509ca601c58f9637.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/spotlight_emission.png"
+dest_files=["res://.godot/imported/spotlight_emission.png-067a05eeab910250509ca601c58f9637.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_band1a.png b/3d/first_person_shooter/textures/t_band1a.png
new file mode 100644
index 00000000000..dfd236caf01
Binary files /dev/null and b/3d/first_person_shooter/textures/t_band1a.png differ
diff --git a/3d/first_person_shooter/textures/t_band1a.png.import b/3d/first_person_shooter/textures/t_band1a.png.import
new file mode 100644
index 00000000000..da256e3c0c7
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_band1a.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://coco2kqdub40r"
+path.s3tc="res://.godot/imported/t_band1a.png-db1cd379aa12eba1c8530ecee04440e9.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_band1a.png"
+dest_files=["res://.godot/imported/t_band1a.png-db1cd379aa12eba1c8530ecee04440e9.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_band1b.png b/3d/first_person_shooter/textures/t_band1b.png
new file mode 100644
index 00000000000..cdffe2cda2f
Binary files /dev/null and b/3d/first_person_shooter/textures/t_band1b.png differ
diff --git a/3d/first_person_shooter/textures/t_band1b.png.import b/3d/first_person_shooter/textures/t_band1b.png.import
new file mode 100644
index 00000000000..e1d893b25a8
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_band1b.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c5wibuv3jj30"
+path.s3tc="res://.godot/imported/t_band1b.png-98ba7a5a41cf83749c234e7779d6ac99.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_band1b.png"
+dest_files=["res://.godot/imported/t_band1b.png-98ba7a5a41cf83749c234e7779d6ac99.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_blok01a.png b/3d/first_person_shooter/textures/t_blok01a.png
new file mode 100644
index 00000000000..152ebdc3dfb
Binary files /dev/null and b/3d/first_person_shooter/textures/t_blok01a.png differ
diff --git a/3d/first_person_shooter/textures/t_blok01a.png.import b/3d/first_person_shooter/textures/t_blok01a.png.import
new file mode 100644
index 00000000000..ed95bf25fca
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_blok01a.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bawpoh70locs5"
+path.s3tc="res://.godot/imported/t_blok01a.png-811d4ec3ca18d42f2975b9ddf03a8329.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_blok01a.png"
+dest_files=["res://.godot/imported/t_blok01a.png-811d4ec3ca18d42f2975b9ddf03a8329.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_blok02.png b/3d/first_person_shooter/textures/t_blok02.png
new file mode 100644
index 00000000000..1f44ce63aa2
Binary files /dev/null and b/3d/first_person_shooter/textures/t_blok02.png differ
diff --git a/3d/first_person_shooter/textures/t_blok02.png.import b/3d/first_person_shooter/textures/t_blok02.png.import
new file mode 100644
index 00000000000..b523a18e055
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_blok02.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ch1jfkov6o4g5"
+path.s3tc="res://.godot/imported/t_blok02.png-eb9d6aa9d89223de48f3760bbcbdf9fd.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_blok02.png"
+dest_files=["res://.godot/imported/t_blok02.png-eb9d6aa9d89223de48f3760bbcbdf9fd.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_blok02a.png b/3d/first_person_shooter/textures/t_blok02a.png
new file mode 100644
index 00000000000..64e95d148bc
Binary files /dev/null and b/3d/first_person_shooter/textures/t_blok02a.png differ
diff --git a/3d/first_person_shooter/textures/t_blok02a.png.import b/3d/first_person_shooter/textures/t_blok02a.png.import
new file mode 100644
index 00000000000..154acafeb13
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_blok02a.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ct3vmxaibb5v5"
+path.s3tc="res://.godot/imported/t_blok02a.png-48c96297e2da1368b3c79e8f342bf8bd.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_blok02a.png"
+dest_files=["res://.godot/imported/t_blok02a.png-48c96297e2da1368b3c79e8f342bf8bd.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_blok03a.png b/3d/first_person_shooter/textures/t_blok03a.png
new file mode 100644
index 00000000000..6d792f11228
Binary files /dev/null and b/3d/first_person_shooter/textures/t_blok03a.png differ
diff --git a/3d/first_person_shooter/textures/t_blok03a.png.import b/3d/first_person_shooter/textures/t_blok03a.png.import
new file mode 100644
index 00000000000..659abc2e9e1
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_blok03a.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://1fj0540x7o0f"
+path.s3tc="res://.godot/imported/t_blok03a.png-68af2076599d685cc9fa615b0cd92dc5.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_blok03a.png"
+dest_files=["res://.godot/imported/t_blok03a.png-68af2076599d685cc9fa615b0cd92dc5.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_blok04.png b/3d/first_person_shooter/textures/t_blok04.png
new file mode 100644
index 00000000000..13ef925dbe0
Binary files /dev/null and b/3d/first_person_shooter/textures/t_blok04.png differ
diff --git a/3d/first_person_shooter/textures/t_blok04.png.import b/3d/first_person_shooter/textures/t_blok04.png.import
new file mode 100644
index 00000000000..1d9928b219f
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_blok04.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b7k36x4uxaf6c"
+path.s3tc="res://.godot/imported/t_blok04.png-d356f424e310168c06cf5a59ab93c159.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_blok04.png"
+dest_files=["res://.godot/imported/t_blok04.png-d356f424e310168c06cf5a59ab93c159.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_blok05.png b/3d/first_person_shooter/textures/t_blok05.png
new file mode 100644
index 00000000000..75362d373e9
Binary files /dev/null and b/3d/first_person_shooter/textures/t_blok05.png differ
diff --git a/3d/first_person_shooter/textures/t_blok05.png.import b/3d/first_person_shooter/textures/t_blok05.png.import
new file mode 100644
index 00000000000..d7f44000782
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_blok05.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c3b7hjkqcgocs"
+path.s3tc="res://.godot/imported/t_blok05.png-2fa409e4098677eb4d4d4f84479c3e93.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_blok05.png"
+dest_files=["res://.godot/imported/t_blok05.png-2fa409e4098677eb4d4d4f84479c3e93.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_blok06.png b/3d/first_person_shooter/textures/t_blok06.png
new file mode 100644
index 00000000000..95fe6841e59
Binary files /dev/null and b/3d/first_person_shooter/textures/t_blok06.png differ
diff --git a/3d/first_person_shooter/textures/t_blok06.png.import b/3d/first_person_shooter/textures/t_blok06.png.import
new file mode 100644
index 00000000000..c7b067bcd79
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_blok06.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://brabrcm0ecm3i"
+path.s3tc="res://.godot/imported/t_blok06.png-c3e4af649e7195d24ef74f7837b0cc67.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_blok06.png"
+dest_files=["res://.godot/imported/t_blok06.png-c3e4af649e7195d24ef74f7837b0cc67.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_blok07.png b/3d/first_person_shooter/textures/t_blok07.png
new file mode 100644
index 00000000000..f08e2b1d0a1
Binary files /dev/null and b/3d/first_person_shooter/textures/t_blok07.png differ
diff --git a/3d/first_person_shooter/textures/t_blok07.png.import b/3d/first_person_shooter/textures/t_blok07.png.import
new file mode 100644
index 00000000000..87b51585d83
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_blok07.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bdx4s8ugusd5h"
+path.s3tc="res://.godot/imported/t_blok07.png-ad009d8edebad9c4b5f5f4060453432c.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_blok07.png"
+dest_files=["res://.godot/imported/t_blok07.png-ad009d8edebad9c4b5f5f4060453432c.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_blok08.png b/3d/first_person_shooter/textures/t_blok08.png
new file mode 100644
index 00000000000..3f69f2edd80
Binary files /dev/null and b/3d/first_person_shooter/textures/t_blok08.png differ
diff --git a/3d/first_person_shooter/textures/t_blok08.png.import b/3d/first_person_shooter/textures/t_blok08.png.import
new file mode 100644
index 00000000000..7e569780cc3
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_blok08.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dt1bg5rjat64u"
+path.s3tc="res://.godot/imported/t_blok08.png-17e013c1103bb42822c8c2b37809baa8.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_blok08.png"
+dest_files=["res://.godot/imported/t_blok08.png-17e013c1103bb42822c8c2b37809baa8.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_blok09.png b/3d/first_person_shooter/textures/t_blok09.png
new file mode 100644
index 00000000000..adec1032170
Binary files /dev/null and b/3d/first_person_shooter/textures/t_blok09.png differ
diff --git a/3d/first_person_shooter/textures/t_blok09.png.import b/3d/first_person_shooter/textures/t_blok09.png.import
new file mode 100644
index 00000000000..8c43fcad2a0
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_blok09.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://w6qsmkqsqmnu"
+path.s3tc="res://.godot/imported/t_blok09.png-e99c6b85e5bbc96f26f04dd067f8b28b.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_blok09.png"
+dest_files=["res://.godot/imported/t_blok09.png-e99c6b85e5bbc96f26f04dd067f8b28b.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_blok10.png b/3d/first_person_shooter/textures/t_blok10.png
new file mode 100644
index 00000000000..1ed16ffe64f
Binary files /dev/null and b/3d/first_person_shooter/textures/t_blok10.png differ
diff --git a/3d/first_person_shooter/textures/t_blok10.png.import b/3d/first_person_shooter/textures/t_blok10.png.import
new file mode 100644
index 00000000000..f8e79ef70ad
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_blok10.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://busr72rmugwlj"
+path.s3tc="res://.godot/imported/t_blok10.png-ed80928827f818967e9fa66f6133d1ea.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_blok10.png"
+dest_files=["res://.godot/imported/t_blok10.png-ed80928827f818967e9fa66f6133d1ea.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_blok11b.png b/3d/first_person_shooter/textures/t_blok11b.png
new file mode 100644
index 00000000000..03350dbc5d6
Binary files /dev/null and b/3d/first_person_shooter/textures/t_blok11b.png differ
diff --git a/3d/first_person_shooter/textures/t_blok11b.png.import b/3d/first_person_shooter/textures/t_blok11b.png.import
new file mode 100644
index 00000000000..f307d43abf1
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_blok11b.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bxsfcnlqfwhqm"
+path.s3tc="res://.godot/imported/t_blok11b.png-fcecac08090b299df8c24d521ff2db20.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_blok11b.png"
+dest_files=["res://.godot/imported/t_blok11b.png-fcecac08090b299df8c24d521ff2db20.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_flat01.png b/3d/first_person_shooter/textures/t_flat01.png
new file mode 100644
index 00000000000..595abf4a15c
Binary files /dev/null and b/3d/first_person_shooter/textures/t_flat01.png differ
diff --git a/3d/first_person_shooter/textures/t_flat01.png.import b/3d/first_person_shooter/textures/t_flat01.png.import
new file mode 100644
index 00000000000..f5edb082c96
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_flat01.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dl3qnwqy1a6rb"
+path.s3tc="res://.godot/imported/t_flat01.png-13fc2dbd8bb7bf4cab477bba197e3de5.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_flat01.png"
+dest_files=["res://.godot/imported/t_flat01.png-13fc2dbd8bb7bf4cab477bba197e3de5.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_flat02.png b/3d/first_person_shooter/textures/t_flat02.png
new file mode 100644
index 00000000000..186830d3177
Binary files /dev/null and b/3d/first_person_shooter/textures/t_flat02.png differ
diff --git a/3d/first_person_shooter/textures/t_flat02.png.import b/3d/first_person_shooter/textures/t_flat02.png.import
new file mode 100644
index 00000000000..456f4dcb7d0
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_flat02.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d02e2gpkegm0x"
+path.s3tc="res://.godot/imported/t_flat02.png-24a19656ee3fb312a259891cf1bfa043.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_flat02.png"
+dest_files=["res://.godot/imported/t_flat02.png-24a19656ee3fb312a259891cf1bfa043.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_flor1a.png b/3d/first_person_shooter/textures/t_flor1a.png
new file mode 100644
index 00000000000..2d3f0493ddf
Binary files /dev/null and b/3d/first_person_shooter/textures/t_flor1a.png differ
diff --git a/3d/first_person_shooter/textures/t_flor1a.png.import b/3d/first_person_shooter/textures/t_flor1a.png.import
new file mode 100644
index 00000000000..336f8588a35
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_flor1a.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bey1jsyo1dk0m"
+path.s3tc="res://.godot/imported/t_flor1a.png-0b04ef6b2ba793604859c5473efbbeb7.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_flor1a.png"
+dest_files=["res://.godot/imported/t_flor1a.png-0b04ef6b2ba793604859c5473efbbeb7.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_flor1b.png b/3d/first_person_shooter/textures/t_flor1b.png
new file mode 100644
index 00000000000..fdbadb5e0bd
Binary files /dev/null and b/3d/first_person_shooter/textures/t_flor1b.png differ
diff --git a/3d/first_person_shooter/textures/t_flor1b.png.import b/3d/first_person_shooter/textures/t_flor1b.png.import
new file mode 100644
index 00000000000..bf8f5bb7593
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_flor1b.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cpjc7kr5ocu2x"
+path.s3tc="res://.godot/imported/t_flor1b.png-538419a08e4686f6b4819ad08d24bd3d.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_flor1b.png"
+dest_files=["res://.godot/imported/t_flor1b.png-538419a08e4686f6b4819ad08d24bd3d.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_flor2a.png b/3d/first_person_shooter/textures/t_flor2a.png
new file mode 100644
index 00000000000..6a538dbf3e0
Binary files /dev/null and b/3d/first_person_shooter/textures/t_flor2a.png differ
diff --git a/3d/first_person_shooter/textures/t_flor2a.png.import b/3d/first_person_shooter/textures/t_flor2a.png.import
new file mode 100644
index 00000000000..da0ac3d05a4
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_flor2a.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://datonqxa17l12"
+path.s3tc="res://.godot/imported/t_flor2a.png-5ce4a609a77d4e274d7800dda254ae8d.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_flor2a.png"
+dest_files=["res://.godot/imported/t_flor2a.png-5ce4a609a77d4e274d7800dda254ae8d.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_lit01.png b/3d/first_person_shooter/textures/t_lit01.png
new file mode 100644
index 00000000000..eb48deb0f14
Binary files /dev/null and b/3d/first_person_shooter/textures/t_lit01.png differ
diff --git a/3d/first_person_shooter/textures/t_lit01.png.import b/3d/first_person_shooter/textures/t_lit01.png.import
new file mode 100644
index 00000000000..cdd3f26ed65
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_lit01.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bv4ntrsju41ol"
+path.s3tc="res://.godot/imported/t_lit01.png-dd75cbc388ee2c6ee7855b075a4582e4.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_lit01.png"
+dest_files=["res://.godot/imported/t_lit01.png-dd75cbc388ee2c6ee7855b075a4582e4.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_lit01_emission.png b/3d/first_person_shooter/textures/t_lit01_emission.png
new file mode 100644
index 00000000000..d10febdc379
Binary files /dev/null and b/3d/first_person_shooter/textures/t_lit01_emission.png differ
diff --git a/3d/first_person_shooter/textures/t_lit01_emission.png.import b/3d/first_person_shooter/textures/t_lit01_emission.png.import
new file mode 100644
index 00000000000..588e284321b
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_lit01_emission.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bowrrgkfm0vxp"
+path.s3tc="res://.godot/imported/t_lit01_emission.png-3d7f84e3382dcfa2438fe8ad4015a113.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_lit01_emission.png"
+dest_files=["res://.godot/imported/t_lit01_emission.png-3d7f84e3382dcfa2438fe8ad4015a113.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_lit07.png b/3d/first_person_shooter/textures/t_lit07.png
new file mode 100644
index 00000000000..5d35be9afd4
Binary files /dev/null and b/3d/first_person_shooter/textures/t_lit07.png differ
diff --git a/3d/first_person_shooter/textures/t_lit07.png.import b/3d/first_person_shooter/textures/t_lit07.png.import
new file mode 100644
index 00000000000..7770c7f7552
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_lit07.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cq8ors7wrn8dl"
+path.s3tc="res://.godot/imported/t_lit07.png-5cf89f0b934bb60f84e457e983429e97.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_lit07.png"
+dest_files=["res://.godot/imported/t_lit07.png-5cf89f0b934bb60f84e457e983429e97.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_lit07_emission.png b/3d/first_person_shooter/textures/t_lit07_emission.png
new file mode 100644
index 00000000000..645eee98ec1
Binary files /dev/null and b/3d/first_person_shooter/textures/t_lit07_emission.png differ
diff --git a/3d/first_person_shooter/textures/t_lit07_emission.png.import b/3d/first_person_shooter/textures/t_lit07_emission.png.import
new file mode 100644
index 00000000000..e2acc83f8a8
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_lit07_emission.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://chucvgrcfkvdy"
+path.s3tc="res://.godot/imported/t_lit07_emission.png-651d9b7cf185cb200db5ef71fcd7f792.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_lit07_emission.png"
+dest_files=["res://.godot/imported/t_lit07_emission.png-651d9b7cf185cb200db5ef71fcd7f792.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_lit08.png b/3d/first_person_shooter/textures/t_lit08.png
new file mode 100644
index 00000000000..0a986f8059e
Binary files /dev/null and b/3d/first_person_shooter/textures/t_lit08.png differ
diff --git a/3d/first_person_shooter/textures/t_lit08.png.import b/3d/first_person_shooter/textures/t_lit08.png.import
new file mode 100644
index 00000000000..4c605f4c26f
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_lit08.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d1vd4ojnskvjo"
+path.s3tc="res://.godot/imported/t_lit08.png-e9f9a9e50e17b4e58f5ace20d16abdff.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_lit08.png"
+dest_files=["res://.godot/imported/t_lit08.png-e9f9a9e50e17b4e58f5ace20d16abdff.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_metalsheeta.png b/3d/first_person_shooter/textures/t_metalsheeta.png
new file mode 100644
index 00000000000..a17303a595f
Binary files /dev/null and b/3d/first_person_shooter/textures/t_metalsheeta.png differ
diff --git a/3d/first_person_shooter/textures/t_metalsheeta.png.import b/3d/first_person_shooter/textures/t_metalsheeta.png.import
new file mode 100644
index 00000000000..0a5b4f5780f
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_metalsheeta.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bek8kyf5yxhvr"
+path.s3tc="res://.godot/imported/t_metalsheeta.png-0b56160e98d395a45a5d4f828c35442b.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_metalsheeta.png"
+dest_files=["res://.godot/imported/t_metalsheeta.png-0b56160e98d395a45a5d4f828c35442b.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_rivs01a.png b/3d/first_person_shooter/textures/t_rivs01a.png
new file mode 100644
index 00000000000..7cffd48d43d
Binary files /dev/null and b/3d/first_person_shooter/textures/t_rivs01a.png differ
diff --git a/3d/first_person_shooter/textures/t_rivs01a.png.import b/3d/first_person_shooter/textures/t_rivs01a.png.import
new file mode 100644
index 00000000000..4eae5f510b6
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_rivs01a.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://q7c2c00irwuh"
+path.s3tc="res://.godot/imported/t_rivs01a.png-d8c29f27b83a8243dd8e5c5d9d859e91.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_rivs01a.png"
+dest_files=["res://.godot/imported/t_rivs01a.png-d8c29f27b83a8243dd8e5c5d9d859e91.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_tech01.png b/3d/first_person_shooter/textures/t_tech01.png
new file mode 100644
index 00000000000..5f548138b80
Binary files /dev/null and b/3d/first_person_shooter/textures/t_tech01.png differ
diff --git a/3d/first_person_shooter/textures/t_tech01.png.import b/3d/first_person_shooter/textures/t_tech01.png.import
new file mode 100644
index 00000000000..0a8b7ea0e68
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_tech01.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dmscgdrr4p7i7"
+path.s3tc="res://.godot/imported/t_tech01.png-86d9887093e1b56dd51b1ac6810cffb0.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_tech01.png"
+dest_files=["res://.godot/imported/t_tech01.png-86d9887093e1b56dd51b1ac6810cffb0.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_tech02.png b/3d/first_person_shooter/textures/t_tech02.png
new file mode 100644
index 00000000000..37db443c61b
Binary files /dev/null and b/3d/first_person_shooter/textures/t_tech02.png differ
diff --git a/3d/first_person_shooter/textures/t_tech02.png.import b/3d/first_person_shooter/textures/t_tech02.png.import
new file mode 100644
index 00000000000..acb4e7bbb2e
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_tech02.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bv4o853kbgf54"
+path.s3tc="res://.godot/imported/t_tech02.png-e3b7bc254c19f76c956d549518205d61.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_tech02.png"
+dest_files=["res://.godot/imported/t_tech02.png-e3b7bc254c19f76c956d549518205d61.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_trim1aa.png b/3d/first_person_shooter/textures/t_trim1aa.png
new file mode 100644
index 00000000000..789524f7176
Binary files /dev/null and b/3d/first_person_shooter/textures/t_trim1aa.png differ
diff --git a/3d/first_person_shooter/textures/t_trim1aa.png.import b/3d/first_person_shooter/textures/t_trim1aa.png.import
new file mode 100644
index 00000000000..af1d11f648f
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_trim1aa.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dtfpbtcedui0c"
+path.s3tc="res://.godot/imported/t_trim1aa.png-e06e8794e4304cd439c7f3d8c788611e.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_trim1aa.png"
+dest_files=["res://.godot/imported/t_trim1aa.png-e06e8794e4304cd439c7f3d8c788611e.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_trim1ba.png b/3d/first_person_shooter/textures/t_trim1ba.png
new file mode 100644
index 00000000000..7b825694837
Binary files /dev/null and b/3d/first_person_shooter/textures/t_trim1ba.png differ
diff --git a/3d/first_person_shooter/textures/t_trim1ba.png.import b/3d/first_person_shooter/textures/t_trim1ba.png.import
new file mode 100644
index 00000000000..1a187e6f324
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_trim1ba.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cv108k6xsm7l2"
+path.s3tc="res://.godot/imported/t_trim1ba.png-c68c7171968575decfc07d3ca3940ac4.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_trim1ba.png"
+dest_files=["res://.godot/imported/t_trim1ba.png-c68c7171968575decfc07d3ca3940ac4.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_trim1c.png b/3d/first_person_shooter/textures/t_trim1c.png
new file mode 100644
index 00000000000..0e966a21eaf
Binary files /dev/null and b/3d/first_person_shooter/textures/t_trim1c.png differ
diff --git a/3d/first_person_shooter/textures/t_trim1c.png.import b/3d/first_person_shooter/textures/t_trim1c.png.import
new file mode 100644
index 00000000000..1df265a1ac6
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_trim1c.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c1r6usyvfwepy"
+path.s3tc="res://.godot/imported/t_trim1c.png-2619b1bdf70415235a70e1e6914e7be8.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_trim1c.png"
+dest_files=["res://.godot/imported/t_trim1c.png-2619b1bdf70415235a70e1e6914e7be8.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_trim1ca.png b/3d/first_person_shooter/textures/t_trim1ca.png
new file mode 100644
index 00000000000..4385c17f113
Binary files /dev/null and b/3d/first_person_shooter/textures/t_trim1ca.png differ
diff --git a/3d/first_person_shooter/textures/t_trim1ca.png.import b/3d/first_person_shooter/textures/t_trim1ca.png.import
new file mode 100644
index 00000000000..efa80e13a74
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_trim1ca.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b2tvb86w4h0j3"
+path.s3tc="res://.godot/imported/t_trim1ca.png-2134334957f3d6652e8f553b68992712.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_trim1ca.png"
+dest_files=["res://.godot/imported/t_trim1ca.png-2134334957f3d6652e8f553b68992712.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_trim1d.png b/3d/first_person_shooter/textures/t_trim1d.png
new file mode 100644
index 00000000000..507b7c1edc3
Binary files /dev/null and b/3d/first_person_shooter/textures/t_trim1d.png differ
diff --git a/3d/first_person_shooter/textures/t_trim1d.png.import b/3d/first_person_shooter/textures/t_trim1d.png.import
new file mode 100644
index 00000000000..2487c9d6052
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_trim1d.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bweoclg06x4qp"
+path.s3tc="res://.godot/imported/t_trim1d.png-0a2419d490107285b9ff3098dea8e61b.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_trim1d.png"
+dest_files=["res://.godot/imported/t_trim1d.png-0a2419d490107285b9ff3098dea8e61b.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_trim1e.png b/3d/first_person_shooter/textures/t_trim1e.png
new file mode 100644
index 00000000000..116b3ca15c0
Binary files /dev/null and b/3d/first_person_shooter/textures/t_trim1e.png differ
diff --git a/3d/first_person_shooter/textures/t_trim1e.png.import b/3d/first_person_shooter/textures/t_trim1e.png.import
new file mode 100644
index 00000000000..5fa67f11aa1
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_trim1e.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c1hahh4jdwou4"
+path.s3tc="res://.godot/imported/t_trim1e.png-51802199fa9a2c867e60238c0ead8f51.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_trim1e.png"
+dest_files=["res://.godot/imported/t_trim1e.png-51802199fa9a2c867e60238c0ead8f51.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_trim2aa.png b/3d/first_person_shooter/textures/t_trim2aa.png
new file mode 100644
index 00000000000..481ff76e999
Binary files /dev/null and b/3d/first_person_shooter/textures/t_trim2aa.png differ
diff --git a/3d/first_person_shooter/textures/t_trim2aa.png.import b/3d/first_person_shooter/textures/t_trim2aa.png.import
new file mode 100644
index 00000000000..547b8279f63
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_trim2aa.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bjyqnir0yqako"
+path.s3tc="res://.godot/imported/t_trim2aa.png-0e62f83a8b1d4747207fe63abaf9b02e.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_trim2aa.png"
+dest_files=["res://.godot/imported/t_trim2aa.png-0e62f83a8b1d4747207fe63abaf9b02e.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_trim2ba.png b/3d/first_person_shooter/textures/t_trim2ba.png
new file mode 100644
index 00000000000..403f8c276f1
Binary files /dev/null and b/3d/first_person_shooter/textures/t_trim2ba.png differ
diff --git a/3d/first_person_shooter/textures/t_trim2ba.png.import b/3d/first_person_shooter/textures/t_trim2ba.png.import
new file mode 100644
index 00000000000..4c3847c8fef
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_trim2ba.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dd74vy23bjl3t"
+path.s3tc="res://.godot/imported/t_trim2ba.png-1676ebebdf63c34da5ce2986cf03a05f.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_trim2ba.png"
+dest_files=["res://.godot/imported/t_trim2ba.png-1676ebebdf63c34da5ce2986cf03a05f.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_trim2ca.png b/3d/first_person_shooter/textures/t_trim2ca.png
new file mode 100644
index 00000000000..beaeeb612be
Binary files /dev/null and b/3d/first_person_shooter/textures/t_trim2ca.png differ
diff --git a/3d/first_person_shooter/textures/t_trim2ca.png.import b/3d/first_person_shooter/textures/t_trim2ca.png.import
new file mode 100644
index 00000000000..43f35569bb9
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_trim2ca.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c3iv2ojcjlk3x"
+path.s3tc="res://.godot/imported/t_trim2ca.png-adbf989bf8b4807524d8da1997ab015c.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_trim2ca.png"
+dest_files=["res://.godot/imported/t_trim2ca.png-adbf989bf8b4807524d8da1997ab015c.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_trim2d.png b/3d/first_person_shooter/textures/t_trim2d.png
new file mode 100644
index 00000000000..4c6eaf15c8d
Binary files /dev/null and b/3d/first_person_shooter/textures/t_trim2d.png differ
diff --git a/3d/first_person_shooter/textures/t_trim2d.png.import b/3d/first_person_shooter/textures/t_trim2d.png.import
new file mode 100644
index 00000000000..0945d6b4623
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_trim2d.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c4h5fxgcepxr0"
+path.s3tc="res://.godot/imported/t_trim2d.png-71e4d28d351c917c65c8452826e5c13c.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_trim2d.png"
+dest_files=["res://.godot/imported/t_trim2d.png-71e4d28d351c917c65c8452826e5c13c.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_trim2e.png b/3d/first_person_shooter/textures/t_trim2e.png
new file mode 100644
index 00000000000..03c1be9e478
Binary files /dev/null and b/3d/first_person_shooter/textures/t_trim2e.png differ
diff --git a/3d/first_person_shooter/textures/t_trim2e.png.import b/3d/first_person_shooter/textures/t_trim2e.png.import
new file mode 100644
index 00000000000..c3a02b700b9
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_trim2e.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cybwijabec61e"
+path.s3tc="res://.godot/imported/t_trim2e.png-24f01ffe2202fd2a9a3e1ac7310a5ed4.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_trim2e.png"
+dest_files=["res://.godot/imported/t_trim2e.png-24f01ffe2202fd2a9a3e1ac7310a5ed4.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_tris02.png b/3d/first_person_shooter/textures/t_tris02.png
new file mode 100644
index 00000000000..cb5d022899f
Binary files /dev/null and b/3d/first_person_shooter/textures/t_tris02.png differ
diff --git a/3d/first_person_shooter/textures/t_tris02.png.import b/3d/first_person_shooter/textures/t_tris02.png.import
new file mode 100644
index 00000000000..25d47927d46
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_tris02.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bp1xapp7ute5g"
+path.s3tc="res://.godot/imported/t_tris02.png-6dcee87f1bffc93a9dd9880b07ad5db7.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_tris02.png"
+dest_files=["res://.godot/imported/t_tris02.png-6dcee87f1bffc93a9dd9880b07ad5db7.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_wall05.png b/3d/first_person_shooter/textures/t_wall05.png
new file mode 100644
index 00000000000..44b0aa3fa72
Binary files /dev/null and b/3d/first_person_shooter/textures/t_wall05.png differ
diff --git a/3d/first_person_shooter/textures/t_wall05.png.import b/3d/first_person_shooter/textures/t_wall05.png.import
new file mode 100644
index 00000000000..627c3cf41d9
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_wall05.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dqhdk50keno54"
+path.s3tc="res://.godot/imported/t_wall05.png-84189c482c28e8e3850284867408fec9.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_wall05.png"
+dest_files=["res://.godot/imported/t_wall05.png-84189c482c28e8e3850284867408fec9.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_wall1a.png b/3d/first_person_shooter/textures/t_wall1a.png
new file mode 100644
index 00000000000..35568fb58b8
Binary files /dev/null and b/3d/first_person_shooter/textures/t_wall1a.png differ
diff --git a/3d/first_person_shooter/textures/t_wall1a.png.import b/3d/first_person_shooter/textures/t_wall1a.png.import
new file mode 100644
index 00000000000..be7e3eca8e4
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_wall1a.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cbne0b88vavqg"
+path.s3tc="res://.godot/imported/t_wall1a.png-74abd21321dc9f09b8d7b8928675e6da.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_wall1a.png"
+dest_files=["res://.godot/imported/t_wall1a.png-74abd21321dc9f09b8d7b8928675e6da.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_wall1aa.png b/3d/first_person_shooter/textures/t_wall1aa.png
new file mode 100644
index 00000000000..4b6c4ae838a
Binary files /dev/null and b/3d/first_person_shooter/textures/t_wall1aa.png differ
diff --git a/3d/first_person_shooter/textures/t_wall1aa.png.import b/3d/first_person_shooter/textures/t_wall1aa.png.import
new file mode 100644
index 00000000000..3a89ff27c31
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_wall1aa.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bmj7b6sj4frti"
+path.s3tc="res://.godot/imported/t_wall1aa.png-5dcdbf9d42b5b9bf36f1be6699227a1e.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_wall1aa.png"
+dest_files=["res://.godot/imported/t_wall1aa.png-5dcdbf9d42b5b9bf36f1be6699227a1e.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_wall1b.png b/3d/first_person_shooter/textures/t_wall1b.png
new file mode 100644
index 00000000000..2f7be4baffe
Binary files /dev/null and b/3d/first_person_shooter/textures/t_wall1b.png differ
diff --git a/3d/first_person_shooter/textures/t_wall1b.png.import b/3d/first_person_shooter/textures/t_wall1b.png.import
new file mode 100644
index 00000000000..978dcf9b823
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_wall1b.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dk5ai3yo7gev2"
+path.s3tc="res://.godot/imported/t_wall1b.png-b2c9294d607a9d93537fad04234dbb7a.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_wall1b.png"
+dest_files=["res://.godot/imported/t_wall1b.png-b2c9294d607a9d93537fad04234dbb7a.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_wall1ba.png b/3d/first_person_shooter/textures/t_wall1ba.png
new file mode 100644
index 00000000000..26d15a87b6b
Binary files /dev/null and b/3d/first_person_shooter/textures/t_wall1ba.png differ
diff --git a/3d/first_person_shooter/textures/t_wall1ba.png.import b/3d/first_person_shooter/textures/t_wall1ba.png.import
new file mode 100644
index 00000000000..7ee1dc8d25c
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_wall1ba.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://drtbubv133u57"
+path.s3tc="res://.godot/imported/t_wall1ba.png-306ea0931bcd2cdf3ff4951a3cdb9ab3.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_wall1ba.png"
+dest_files=["res://.godot/imported/t_wall1ba.png-306ea0931bcd2cdf3ff4951a3cdb9ab3.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_wall2a.png b/3d/first_person_shooter/textures/t_wall2a.png
new file mode 100644
index 00000000000..b466ef9bb1b
Binary files /dev/null and b/3d/first_person_shooter/textures/t_wall2a.png differ
diff --git a/3d/first_person_shooter/textures/t_wall2a.png.import b/3d/first_person_shooter/textures/t_wall2a.png.import
new file mode 100644
index 00000000000..a09e70977e0
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_wall2a.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bp87ykjoymbos"
+path.s3tc="res://.godot/imported/t_wall2a.png-a90c91d267114b3a670bbfcd3f370cfc.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_wall2a.png"
+dest_files=["res://.godot/imported/t_wall2a.png-a90c91d267114b3a670bbfcd3f370cfc.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_wall2aa.png b/3d/first_person_shooter/textures/t_wall2aa.png
new file mode 100644
index 00000000000..ce99d59fc62
Binary files /dev/null and b/3d/first_person_shooter/textures/t_wall2aa.png differ
diff --git a/3d/first_person_shooter/textures/t_wall2aa.png.import b/3d/first_person_shooter/textures/t_wall2aa.png.import
new file mode 100644
index 00000000000..836c610a478
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_wall2aa.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://3pjk2x7afmwr"
+path.s3tc="res://.godot/imported/t_wall2aa.png-16bdcaee4fbdd6992702da2c2ef8e648.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_wall2aa.png"
+dest_files=["res://.godot/imported/t_wall2aa.png-16bdcaee4fbdd6992702da2c2ef8e648.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_wall2ab.png b/3d/first_person_shooter/textures/t_wall2ab.png
new file mode 100644
index 00000000000..d1030dc7508
Binary files /dev/null and b/3d/first_person_shooter/textures/t_wall2ab.png differ
diff --git a/3d/first_person_shooter/textures/t_wall2ab.png.import b/3d/first_person_shooter/textures/t_wall2ab.png.import
new file mode 100644
index 00000000000..2f2cf10f14c
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_wall2ab.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dfusxnjf3xahh"
+path.s3tc="res://.godot/imported/t_wall2ab.png-71c61e16a8f69ff89d43d2d2e26d4c13.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_wall2ab.png"
+dest_files=["res://.godot/imported/t_wall2ab.png-71c61e16a8f69ff89d43d2d2e26d4c13.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_wall2b.png b/3d/first_person_shooter/textures/t_wall2b.png
new file mode 100644
index 00000000000..35487998eb0
Binary files /dev/null and b/3d/first_person_shooter/textures/t_wall2b.png differ
diff --git a/3d/first_person_shooter/textures/t_wall2b.png.import b/3d/first_person_shooter/textures/t_wall2b.png.import
new file mode 100644
index 00000000000..acff84362c0
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_wall2b.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://k8m37s5jwbr8"
+path.s3tc="res://.godot/imported/t_wall2b.png-5cbe6c60b9e3ff20dbf2974b9eb1678e.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_wall2b.png"
+dest_files=["res://.godot/imported/t_wall2b.png-5cbe6c60b9e3ff20dbf2974b9eb1678e.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_wall2ba.png b/3d/first_person_shooter/textures/t_wall2ba.png
new file mode 100644
index 00000000000..c3ef7e8da84
Binary files /dev/null and b/3d/first_person_shooter/textures/t_wall2ba.png differ
diff --git a/3d/first_person_shooter/textures/t_wall2ba.png.import b/3d/first_person_shooter/textures/t_wall2ba.png.import
new file mode 100644
index 00000000000..d05dd643059
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_wall2ba.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dvtej1efyw5g7"
+path.s3tc="res://.godot/imported/t_wall2ba.png-b5c4d8bee589df28590593b15d129352.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_wall2ba.png"
+dest_files=["res://.godot/imported/t_wall2ba.png-b5c4d8bee589df28590593b15d129352.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_wall3aa.png b/3d/first_person_shooter/textures/t_wall3aa.png
new file mode 100644
index 00000000000..999e06d8859
Binary files /dev/null and b/3d/first_person_shooter/textures/t_wall3aa.png differ
diff --git a/3d/first_person_shooter/textures/t_wall3aa.png.import b/3d/first_person_shooter/textures/t_wall3aa.png.import
new file mode 100644
index 00000000000..983d6954130
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_wall3aa.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cuqgr7mabf2ka"
+path.s3tc="res://.godot/imported/t_wall3aa.png-4f1af12849f4492a161a2501dece0095.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_wall3aa.png"
+dest_files=["res://.godot/imported/t_wall3aa.png-4f1af12849f4492a161a2501dece0095.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_wall3b.png b/3d/first_person_shooter/textures/t_wall3b.png
new file mode 100644
index 00000000000..b82fa35c511
Binary files /dev/null and b/3d/first_person_shooter/textures/t_wall3b.png differ
diff --git a/3d/first_person_shooter/textures/t_wall3b.png.import b/3d/first_person_shooter/textures/t_wall3b.png.import
new file mode 100644
index 00000000000..01c000dcd58
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_wall3b.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://blpkpxffxfg5g"
+path.s3tc="res://.godot/imported/t_wall3b.png-4c0972639cd1e87821c0df5098fbc47c.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_wall3b.png"
+dest_files=["res://.godot/imported/t_wall3b.png-4c0972639cd1e87821c0df5098fbc47c.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/t_wall3ba.png b/3d/first_person_shooter/textures/t_wall3ba.png
new file mode 100644
index 00000000000..819edc4b6b0
Binary files /dev/null and b/3d/first_person_shooter/textures/t_wall3ba.png differ
diff --git a/3d/first_person_shooter/textures/t_wall3ba.png.import b/3d/first_person_shooter/textures/t_wall3ba.png.import
new file mode 100644
index 00000000000..ddcf3b80c9c
--- /dev/null
+++ b/3d/first_person_shooter/textures/t_wall3ba.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bm0m5gkkyadsg"
+path.s3tc="res://.godot/imported/t_wall3ba.png-99993b398b6beeb585a0c75c67ea5b38.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/t_wall3ba.png"
+dest_files=["res://.godot/imported/t_wall3ba.png-99993b398b6beeb585a0c75c67ea5b38.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tek_door1.png b/3d/first_person_shooter/textures/tek_door1.png
new file mode 100644
index 00000000000..52f6f3bfa32
Binary files /dev/null and b/3d/first_person_shooter/textures/tek_door1.png differ
diff --git a/3d/first_person_shooter/textures/tek_door1.png.import b/3d/first_person_shooter/textures/tek_door1.png.import
new file mode 100644
index 00000000000..bb2cd2de175
--- /dev/null
+++ b/3d/first_person_shooter/textures/tek_door1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d3dypix8ijm2i"
+path.s3tc="res://.godot/imported/tek_door1.png-7e7a786da274d6ba95c8ca90c8ebc2c5.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tek_door1.png"
+dest_files=["res://.godot/imported/tek_door1.png-7e7a786da274d6ba95c8ca90c8ebc2c5.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tek_flr3.png b/3d/first_person_shooter/textures/tek_flr3.png
new file mode 100644
index 00000000000..b5ba44e1a87
Binary files /dev/null and b/3d/first_person_shooter/textures/tek_flr3.png differ
diff --git a/3d/first_person_shooter/textures/tek_flr3.png.import b/3d/first_person_shooter/textures/tek_flr3.png.import
new file mode 100644
index 00000000000..3765b39b585
--- /dev/null
+++ b/3d/first_person_shooter/textures/tek_flr3.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://yfneapt52d8o"
+path.s3tc="res://.godot/imported/tek_flr3.png-b9117a937cd8a9e61f58ab01ac723e84.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tek_flr3.png"
+dest_files=["res://.godot/imported/tek_flr3.png-b9117a937cd8a9e61f58ab01ac723e84.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tek_grate.png b/3d/first_person_shooter/textures/tek_grate.png
new file mode 100644
index 00000000000..b6222854ecc
Binary files /dev/null and b/3d/first_person_shooter/textures/tek_grate.png differ
diff --git a/3d/first_person_shooter/textures/tek_grate.png.import b/3d/first_person_shooter/textures/tek_grate.png.import
new file mode 100644
index 00000000000..31bd2f1a140
--- /dev/null
+++ b/3d/first_person_shooter/textures/tek_grate.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dy57r5atqjaif"
+path.s3tc="res://.godot/imported/tek_grate.png-b5bdca8df8f0a85d375f052b78a54b5e.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tek_grate.png"
+dest_files=["res://.godot/imported/tek_grate.png-b5bdca8df8f0a85d375f052b78a54b5e.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tek_lit3.png b/3d/first_person_shooter/textures/tek_lit3.png
new file mode 100644
index 00000000000..d568da91cfc
Binary files /dev/null and b/3d/first_person_shooter/textures/tek_lit3.png differ
diff --git a/3d/first_person_shooter/textures/tek_lit3.png.import b/3d/first_person_shooter/textures/tek_lit3.png.import
new file mode 100644
index 00000000000..0acebb41a61
--- /dev/null
+++ b/3d/first_person_shooter/textures/tek_lit3.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://o448w4j2t3vj"
+path.s3tc="res://.godot/imported/tek_lit3.png-842b2216197010b557754441d49afc6e.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tek_lit3.png"
+dest_files=["res://.godot/imported/tek_lit3.png-842b2216197010b557754441d49afc6e.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tek_lit3_emission.png b/3d/first_person_shooter/textures/tek_lit3_emission.png
new file mode 100644
index 00000000000..acf2087cbaf
Binary files /dev/null and b/3d/first_person_shooter/textures/tek_lit3_emission.png differ
diff --git a/3d/first_person_shooter/textures/tek_lit3_emission.png.import b/3d/first_person_shooter/textures/tek_lit3_emission.png.import
new file mode 100644
index 00000000000..4009fda2406
--- /dev/null
+++ b/3d/first_person_shooter/textures/tek_lit3_emission.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bktod6tduptje"
+path.s3tc="res://.godot/imported/tek_lit3_emission.png-173cd36d443acd26988b68c098aec20d.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tek_lit3_emission.png"
+dest_files=["res://.godot/imported/tek_lit3_emission.png-173cd36d443acd26988b68c098aec20d.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tek_lit4.png b/3d/first_person_shooter/textures/tek_lit4.png
new file mode 100644
index 00000000000..581063ffe0e
Binary files /dev/null and b/3d/first_person_shooter/textures/tek_lit4.png differ
diff --git a/3d/first_person_shooter/textures/tek_lit4.png.import b/3d/first_person_shooter/textures/tek_lit4.png.import
new file mode 100644
index 00000000000..90fc54a8d34
--- /dev/null
+++ b/3d/first_person_shooter/textures/tek_lit4.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://o5tld0avv8kg"
+path.s3tc="res://.godot/imported/tek_lit4.png-88a6452633e94c0b3677752a552b0fd8.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tek_lit4.png"
+dest_files=["res://.godot/imported/tek_lit4.png-88a6452633e94c0b3677752a552b0fd8.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tek_lit4_emission.png b/3d/first_person_shooter/textures/tek_lit4_emission.png
new file mode 100644
index 00000000000..72031bf8ffd
Binary files /dev/null and b/3d/first_person_shooter/textures/tek_lit4_emission.png differ
diff --git a/3d/first_person_shooter/textures/tek_lit4_emission.png.import b/3d/first_person_shooter/textures/tek_lit4_emission.png.import
new file mode 100644
index 00000000000..e754f9d64ca
--- /dev/null
+++ b/3d/first_person_shooter/textures/tek_lit4_emission.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cwuj303xuhl36"
+path.s3tc="res://.godot/imported/tek_lit4_emission.png-d6366234e0f09438c091c75a30403746.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tek_lit4_emission.png"
+dest_files=["res://.godot/imported/tek_lit4_emission.png-d6366234e0f09438c091c75a30403746.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tek_pipe2.png b/3d/first_person_shooter/textures/tek_pipe2.png
new file mode 100644
index 00000000000..53bcc537253
Binary files /dev/null and b/3d/first_person_shooter/textures/tek_pipe2.png differ
diff --git a/3d/first_person_shooter/textures/tek_pipe2.png.import b/3d/first_person_shooter/textures/tek_pipe2.png.import
new file mode 100644
index 00000000000..062d1f9e4d6
--- /dev/null
+++ b/3d/first_person_shooter/textures/tek_pipe2.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://djs5dgvx0mi2j"
+path.s3tc="res://.godot/imported/tek_pipe2.png-b37389c96855977483a8d7b3d665621d.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tek_pipe2.png"
+dest_files=["res://.godot/imported/tek_pipe2.png-b37389c96855977483a8d7b3d665621d.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tele3.png b/3d/first_person_shooter/textures/tele3.png
new file mode 100644
index 00000000000..420d0639331
Binary files /dev/null and b/3d/first_person_shooter/textures/tele3.png differ
diff --git a/3d/first_person_shooter/textures/tele3.png.import b/3d/first_person_shooter/textures/tele3.png.import
new file mode 100644
index 00000000000..47c806678a8
--- /dev/null
+++ b/3d/first_person_shooter/textures/tele3.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d6jow476l765"
+path.s3tc="res://.godot/imported/tele3.png-bacd5f41a4b8a991b4b619ad6c60fd95.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tele3.png"
+dest_files=["res://.godot/imported/tele3.png-bacd5f41a4b8a991b4b619ad6c60fd95.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tele_frame1.png b/3d/first_person_shooter/textures/tele_frame1.png
new file mode 100644
index 00000000000..b14656280ff
Binary files /dev/null and b/3d/first_person_shooter/textures/tele_frame1.png differ
diff --git a/3d/first_person_shooter/textures/tele_frame1.png.import b/3d/first_person_shooter/textures/tele_frame1.png.import
new file mode 100644
index 00000000000..5f3e8ea8726
--- /dev/null
+++ b/3d/first_person_shooter/textures/tele_frame1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b5epmx20r5tkp"
+path.s3tc="res://.godot/imported/tele_frame1.png-a9012ce214fdb75352ff7d526c21226b.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tele_frame1.png"
+dest_files=["res://.godot/imported/tele_frame1.png-a9012ce214fdb75352ff7d526c21226b.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tele_frame3.png b/3d/first_person_shooter/textures/tele_frame3.png
new file mode 100644
index 00000000000..cff195dc059
Binary files /dev/null and b/3d/first_person_shooter/textures/tele_frame3.png differ
diff --git a/3d/first_person_shooter/textures/tele_frame3.png.import b/3d/first_person_shooter/textures/tele_frame3.png.import
new file mode 100644
index 00000000000..78638c71d4f
--- /dev/null
+++ b/3d/first_person_shooter/textures/tele_frame3.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bhdfx2mjj784r"
+path.s3tc="res://.godot/imported/tele_frame3.png-cd911c66f2f07264dd884f1d835f9ffa.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tele_frame3.png"
+dest_files=["res://.godot/imported/tele_frame3.png-cd911c66f2f07264dd884f1d835f9ffa.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/telepad1.png b/3d/first_person_shooter/textures/telepad1.png
new file mode 100644
index 00000000000..cd1d5ff22cd
Binary files /dev/null and b/3d/first_person_shooter/textures/telepad1.png differ
diff --git a/3d/first_person_shooter/textures/telepad1.png.import b/3d/first_person_shooter/textures/telepad1.png.import
new file mode 100644
index 00000000000..6f571a1dd32
--- /dev/null
+++ b/3d/first_person_shooter/textures/telepad1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b4iumt5cvvbix"
+path.s3tc="res://.godot/imported/telepad1.png-0039dae7d806310657f4694057da00ce.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/telepad1.png"
+dest_files=["res://.godot/imported/telepad1.png-0039dae7d806310657f4694057da00ce.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/telepad1_emission.png b/3d/first_person_shooter/textures/telepad1_emission.png
new file mode 100644
index 00000000000..b36eca7acf0
Binary files /dev/null and b/3d/first_person_shooter/textures/telepad1_emission.png differ
diff --git a/3d/first_person_shooter/textures/telepad1_emission.png.import b/3d/first_person_shooter/textures/telepad1_emission.png.import
new file mode 100644
index 00000000000..1eb486834d9
--- /dev/null
+++ b/3d/first_person_shooter/textures/telepad1_emission.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://euu16qrvnrxs"
+path.s3tc="res://.godot/imported/telepad1_emission.png-2f41f45c5ab34b46767a76b5691ab4b0.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/telepad1_emission.png"
+dest_files=["res://.godot/imported/telepad1_emission.png-2f41f45c5ab34b46767a76b5691ab4b0.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tlight11.png b/3d/first_person_shooter/textures/tlight11.png
new file mode 100644
index 00000000000..d9942f5cead
Binary files /dev/null and b/3d/first_person_shooter/textures/tlight11.png differ
diff --git a/3d/first_person_shooter/textures/tlight11.png.import b/3d/first_person_shooter/textures/tlight11.png.import
new file mode 100644
index 00000000000..633a2d667b0
--- /dev/null
+++ b/3d/first_person_shooter/textures/tlight11.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://buoqry2cp4gkl"
+path.s3tc="res://.godot/imported/tlight11.png-dfc5d8fc5ee42a9ff314c1bf5a522f00.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tlight11.png"
+dest_files=["res://.godot/imported/tlight11.png-dfc5d8fc5ee42a9ff314c1bf5a522f00.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tlight11_emission.png b/3d/first_person_shooter/textures/tlight11_emission.png
new file mode 100644
index 00000000000..64282f97b14
Binary files /dev/null and b/3d/first_person_shooter/textures/tlight11_emission.png differ
diff --git a/3d/first_person_shooter/textures/tlight11_emission.png.import b/3d/first_person_shooter/textures/tlight11_emission.png.import
new file mode 100644
index 00000000000..7f76ae0fcb3
--- /dev/null
+++ b/3d/first_person_shooter/textures/tlight11_emission.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://c7sf0hp5upm0x"
+path.s3tc="res://.godot/imported/tlight11_emission.png-70e6169463a88c29fa98fbf5f00f8bd3.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tlight11_emission.png"
+dest_files=["res://.godot/imported/tlight11_emission.png-70e6169463a88c29fa98fbf5f00f8bd3.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tlight13.png b/3d/first_person_shooter/textures/tlight13.png
new file mode 100644
index 00000000000..31b5c6a8bde
Binary files /dev/null and b/3d/first_person_shooter/textures/tlight13.png differ
diff --git a/3d/first_person_shooter/textures/tlight13.png.import b/3d/first_person_shooter/textures/tlight13.png.import
new file mode 100644
index 00000000000..94c3a0e5576
--- /dev/null
+++ b/3d/first_person_shooter/textures/tlight13.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cqftp7b6x1s45"
+path.s3tc="res://.godot/imported/tlight13.png-04610bd8a6b40aa84a71ef93c0cb6740.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tlight13.png"
+dest_files=["res://.godot/imported/tlight13.png-04610bd8a6b40aa84a71ef93c0cb6740.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/tlight13_emission.png b/3d/first_person_shooter/textures/tlight13_emission.png
new file mode 100644
index 00000000000..64282f97b14
Binary files /dev/null and b/3d/first_person_shooter/textures/tlight13_emission.png differ
diff --git a/3d/first_person_shooter/textures/tlight13_emission.png.import b/3d/first_person_shooter/textures/tlight13_emission.png.import
new file mode 100644
index 00000000000..1783daaf775
--- /dev/null
+++ b/3d/first_person_shooter/textures/tlight13_emission.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bcpekf3ndyugy"
+path.s3tc="res://.godot/imported/tlight13_emission.png-364557e4795f075b83128bcd87e4f055.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/tlight13_emission.png"
+dest_files=["res://.godot/imported/tlight13_emission.png-364557e4795f075b83128bcd87e4f055.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/treadplatemetal.png b/3d/first_person_shooter/textures/treadplatemetal.png
new file mode 100644
index 00000000000..ffeafa2f980
Binary files /dev/null and b/3d/first_person_shooter/textures/treadplatemetal.png differ
diff --git a/3d/first_person_shooter/textures/treadplatemetal.png.import b/3d/first_person_shooter/textures/treadplatemetal.png.import
new file mode 100644
index 00000000000..11a48e5318a
--- /dev/null
+++ b/3d/first_person_shooter/textures/treadplatemetal.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bjimds1ytloxu"
+path.s3tc="res://.godot/imported/treadplatemetal.png-4e6cd8e7650bbff811b9df55c04b444d.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/treadplatemetal.png"
+dest_files=["res://.godot/imported/treadplatemetal.png-4e6cd8e7650bbff811b9df55c04b444d.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/uwall1_2.png b/3d/first_person_shooter/textures/uwall1_2.png
new file mode 100644
index 00000000000..a62f883549c
Binary files /dev/null and b/3d/first_person_shooter/textures/uwall1_2.png differ
diff --git a/3d/first_person_shooter/textures/uwall1_2.png.import b/3d/first_person_shooter/textures/uwall1_2.png.import
new file mode 100644
index 00000000000..25bec10e72f
--- /dev/null
+++ b/3d/first_person_shooter/textures/uwall1_2.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b46chd34f6d8s"
+path.s3tc="res://.godot/imported/uwall1_2.png-fb0c064a953576971a4304b3cf192108.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/uwall1_2.png"
+dest_files=["res://.godot/imported/uwall1_2.png-fb0c064a953576971a4304b3cf192108.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/w17_1.png b/3d/first_person_shooter/textures/w17_1.png
new file mode 100644
index 00000000000..35374017294
Binary files /dev/null and b/3d/first_person_shooter/textures/w17_1.png differ
diff --git a/3d/first_person_shooter/textures/w17_1.png.import b/3d/first_person_shooter/textures/w17_1.png.import
new file mode 100644
index 00000000000..c37d061ce42
--- /dev/null
+++ b/3d/first_person_shooter/textures/w17_1.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://ci4l4gtkadlte"
+path.s3tc="res://.godot/imported/w17_1.png-5a04ba81050c64b7a06112f1b3e84696.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/w17_1.png"
+dest_files=["res://.godot/imported/w17_1.png-5a04ba81050c64b7a06112f1b3e84696.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/wad/lq_conc.wad b/3d/first_person_shooter/textures/wad/lq_conc.wad
new file mode 100644
index 00000000000..1f03d77529f
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_conc.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_conc.wad.import b/3d/first_person_shooter/textures/wad/lq_conc.wad.import
new file mode 100644
index 00000000000..d139a6a9d5d
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_conc.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://1nqjtjpr2rxe"
+path="res://.godot/imported/lq_conc.wad-171fdd0626a7c61dec56a56394c10173.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_conc.wad"
+dest_files=["res://.godot/imported/lq_conc.wad-171fdd0626a7c61dec56a56394c10173.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_dev.wad b/3d/first_person_shooter/textures/wad/lq_dev.wad
new file mode 100644
index 00000000000..bd946a668e0
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_dev.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_dev.wad.import b/3d/first_person_shooter/textures/wad/lq_dev.wad.import
new file mode 100644
index 00000000000..383d102e987
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_dev.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://bci1klimt2wcx"
+path="res://.godot/imported/lq_dev.wad-10db51341b869b03905efaa0683875f2.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_dev.wad"
+dest_files=["res://.godot/imported/lq_dev.wad-10db51341b869b03905efaa0683875f2.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_dev_legacy.wad b/3d/first_person_shooter/textures/wad/lq_dev_legacy.wad
new file mode 100644
index 00000000000..4d62835c772
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_dev_legacy.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_dev_legacy.wad.import b/3d/first_person_shooter/textures/wad/lq_dev_legacy.wad.import
new file mode 100644
index 00000000000..c1694034fd5
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_dev_legacy.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://bsprq6u3sfjnq"
+path="res://.godot/imported/lq_dev_legacy.wad-ccddc59b1381b50ccccc79f2b9dc1ddb.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_dev_legacy.wad"
+dest_files=["res://.godot/imported/lq_dev_legacy.wad-ccddc59b1381b50ccccc79f2b9dc1ddb.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_flesh.wad b/3d/first_person_shooter/textures/wad/lq_flesh.wad
new file mode 100644
index 00000000000..5264bed3d00
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_flesh.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_flesh.wad.import b/3d/first_person_shooter/textures/wad/lq_flesh.wad.import
new file mode 100644
index 00000000000..594853cafc6
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_flesh.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://byd84bbifvlj8"
+path="res://.godot/imported/lq_flesh.wad-032dde7f50fd11ea2a9edcd5d4f795a1.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_flesh.wad"
+dest_files=["res://.godot/imported/lq_flesh.wad-032dde7f50fd11ea2a9edcd5d4f795a1.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_greek.wad b/3d/first_person_shooter/textures/wad/lq_greek.wad
new file mode 100644
index 00000000000..adf6159b253
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_greek.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_greek.wad.import b/3d/first_person_shooter/textures/wad/lq_greek.wad.import
new file mode 100644
index 00000000000..72ec52c8ce9
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_greek.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://bkydwwxkyf4ol"
+path="res://.godot/imported/lq_greek.wad-f76ff554b6f8d0d675829d05c331cac6.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_greek.wad"
+dest_files=["res://.godot/imported/lq_greek.wad-f76ff554b6f8d0d675829d05c331cac6.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_health_ammo.wad b/3d/first_person_shooter/textures/wad/lq_health_ammo.wad
new file mode 100644
index 00000000000..234bc9c04eb
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_health_ammo.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_health_ammo.wad.import b/3d/first_person_shooter/textures/wad/lq_health_ammo.wad.import
new file mode 100644
index 00000000000..a5eae799769
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_health_ammo.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://bobadh0oc6r4o"
+path="res://.godot/imported/lq_health_ammo.wad-365b12b4b82b5fc00ad4073540b572a9.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_health_ammo.wad"
+dest_files=["res://.godot/imported/lq_health_ammo.wad-365b12b4b82b5fc00ad4073540b572a9.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_legacy.wad b/3d/first_person_shooter/textures/wad/lq_legacy.wad
new file mode 100644
index 00000000000..0c22f822dc0
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_legacy.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_legacy.wad.import b/3d/first_person_shooter/textures/wad/lq_legacy.wad.import
new file mode 100644
index 00000000000..4f34a13c3fa
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_legacy.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://b0sq1jvo7gja"
+path="res://.godot/imported/lq_legacy.wad-1592b947e99ccb732358f2fa5ab0aba3.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_legacy.wad"
+dest_files=["res://.godot/imported/lq_legacy.wad-1592b947e99ccb732358f2fa5ab0aba3.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_liquidsky.wad b/3d/first_person_shooter/textures/wad/lq_liquidsky.wad
new file mode 100644
index 00000000000..038903da754
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_liquidsky.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_liquidsky.wad.import b/3d/first_person_shooter/textures/wad/lq_liquidsky.wad.import
new file mode 100644
index 00000000000..a6171bf84ad
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_liquidsky.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://cpd80l3fnxrxk"
+path="res://.godot/imported/lq_liquidsky.wad-78dce6408d798b1e898313e504ba6433.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_liquidsky.wad"
+dest_files=["res://.godot/imported/lq_liquidsky.wad-78dce6408d798b1e898313e504ba6433.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_mayan.wad b/3d/first_person_shooter/textures/wad/lq_mayan.wad
new file mode 100644
index 00000000000..6dbd2883da7
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_mayan.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_mayan.wad.import b/3d/first_person_shooter/textures/wad/lq_mayan.wad.import
new file mode 100644
index 00000000000..aff370aab1b
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_mayan.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://be7hhrv0suku0"
+path="res://.godot/imported/lq_mayan.wad-19ae216078491aa149f03119390aa3c4.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_mayan.wad"
+dest_files=["res://.godot/imported/lq_mayan.wad-19ae216078491aa149f03119390aa3c4.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_medieval.wad b/3d/first_person_shooter/textures/wad/lq_medieval.wad
new file mode 100644
index 00000000000..ccb6d2a4121
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_medieval.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_medieval.wad.import b/3d/first_person_shooter/textures/wad/lq_medieval.wad.import
new file mode 100644
index 00000000000..ab48c80fd32
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_medieval.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://dsmtaelvnfhkl"
+path="res://.godot/imported/lq_medieval.wad-3111f9587c244ecac8e051002fce0f02.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_medieval.wad"
+dest_files=["res://.godot/imported/lq_medieval.wad-3111f9587c244ecac8e051002fce0f02.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_metal.wad b/3d/first_person_shooter/textures/wad/lq_metal.wad
new file mode 100644
index 00000000000..3a57ab9855d
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_metal.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_metal.wad.import b/3d/first_person_shooter/textures/wad/lq_metal.wad.import
new file mode 100644
index 00000000000..e067a9ce138
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_metal.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://gjs8cf4bi0p4"
+path="res://.godot/imported/lq_metal.wad-d710d10adbc901ed395c8f388372527a.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_metal.wad"
+dest_files=["res://.godot/imported/lq_metal.wad-d710d10adbc901ed395c8f388372527a.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_palette.wad b/3d/first_person_shooter/textures/wad/lq_palette.wad
new file mode 100644
index 00000000000..2f896f239ea
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_palette.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_palette.wad.import b/3d/first_person_shooter/textures/wad/lq_palette.wad.import
new file mode 100644
index 00000000000..be6989f9a78
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_palette.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://coplapd2lkyt5"
+path="res://.godot/imported/lq_palette.wad-fa2798139e18d476cfa31ab9ade1147f.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_palette.wad"
+dest_files=["res://.godot/imported/lq_palette.wad-fa2798139e18d476cfa31ab9ade1147f.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_props.wad b/3d/first_person_shooter/textures/wad/lq_props.wad
new file mode 100644
index 00000000000..01eb3c510d0
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_props.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_props.wad.import b/3d/first_person_shooter/textures/wad/lq_props.wad.import
new file mode 100644
index 00000000000..c5ff75ad642
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_props.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://c3eavauopyxae"
+path="res://.godot/imported/lq_props.wad-8f3e48421e793be4ed850e8387ba6c70.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_props.wad"
+dest_files=["res://.godot/imported/lq_props.wad-8f3e48421e793be4ed850e8387ba6c70.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_tech.wad b/3d/first_person_shooter/textures/wad/lq_tech.wad
new file mode 100644
index 00000000000..1d5632b6bf6
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_tech.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_tech.wad.import b/3d/first_person_shooter/textures/wad/lq_tech.wad.import
new file mode 100644
index 00000000000..3eada16b80e
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_tech.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://bu3fkn7owmyil"
+path="res://.godot/imported/lq_tech.wad-456b3bde8e49b09249cf710241d3b522.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_tech.wad"
+dest_files=["res://.godot/imported/lq_tech.wad-456b3bde8e49b09249cf710241d3b522.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_terra.wad b/3d/first_person_shooter/textures/wad/lq_terra.wad
new file mode 100644
index 00000000000..9d5802d571e
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_terra.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_terra.wad.import b/3d/first_person_shooter/textures/wad/lq_terra.wad.import
new file mode 100644
index 00000000000..12d4b59b36f
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_terra.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://cnsahqdpg88gr"
+path="res://.godot/imported/lq_terra.wad-161b947fdd82b5d388a69153e5230723.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_terra.wad"
+dest_files=["res://.godot/imported/lq_terra.wad-161b947fdd82b5d388a69153e5230723.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_utility.wad b/3d/first_person_shooter/textures/wad/lq_utility.wad
new file mode 100644
index 00000000000..6783de820c5
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_utility.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_utility.wad.import b/3d/first_person_shooter/textures/wad/lq_utility.wad.import
new file mode 100644
index 00000000000..c20f3796d34
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_utility.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://o1xknd416frl"
+path="res://.godot/imported/lq_utility.wad-90d0c6f002d1899663f3b357162d52d6.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_utility.wad"
+dest_files=["res://.godot/imported/lq_utility.wad-90d0c6f002d1899663f3b357162d52d6.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/wad/lq_wood.wad b/3d/first_person_shooter/textures/wad/lq_wood.wad
new file mode 100644
index 00000000000..d1afa5f10ea
Binary files /dev/null and b/3d/first_person_shooter/textures/wad/lq_wood.wad differ
diff --git a/3d/first_person_shooter/textures/wad/lq_wood.wad.import b/3d/first_person_shooter/textures/wad/lq_wood.wad.import
new file mode 100644
index 00000000000..0425bfa3c17
--- /dev/null
+++ b/3d/first_person_shooter/textures/wad/lq_wood.wad.import
@@ -0,0 +1,14 @@
+[remap]
+
+importer="bsp"
+type="PackedScene"
+uid="uid://bx1haiylvv21x"
+path="res://.godot/imported/lq_wood.wad-32712bc1f39b41d98e9223a9b543a535.scn"
+
+[deps]
+
+source_file="res://textures/wad/lq_wood.wad"
+dest_files=["res://.godot/imported/lq_wood.wad-32712bc1f39b41d98e9223a9b543a535.scn"]
+
+[params]
+
diff --git a/3d/first_person_shooter/textures/water0.png b/3d/first_person_shooter/textures/water0.png
new file mode 100644
index 00000000000..3045fdac2b2
Binary files /dev/null and b/3d/first_person_shooter/textures/water0.png differ
diff --git a/3d/first_person_shooter/textures/water0.png.import b/3d/first_person_shooter/textures/water0.png.import
new file mode 100644
index 00000000000..28992792f01
--- /dev/null
+++ b/3d/first_person_shooter/textures/water0.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cstttmpruatkr"
+path.s3tc="res://.godot/imported/water0.png-5735bc0ef4a172aea4507cefa0e01f3c.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/water0.png"
+dest_files=["res://.godot/imported/water0.png-5735bc0ef4a172aea4507cefa0e01f3c.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/water4.png b/3d/first_person_shooter/textures/water4.png
new file mode 100644
index 00000000000..f98fa7ab88b
Binary files /dev/null and b/3d/first_person_shooter/textures/water4.png differ
diff --git a/3d/first_person_shooter/textures/water4.png.import b/3d/first_person_shooter/textures/water4.png.import
new file mode 100644
index 00000000000..8543457c973
--- /dev/null
+++ b/3d/first_person_shooter/textures/water4.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cegu6govj5suq"
+path.s3tc="res://.godot/imported/water4.png-3b6f43e5c5c5dd765bf22121e50400c6.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/water4.png"
+dest_files=["res://.godot/imported/water4.png-3b6f43e5c5c5dd765bf22121e50400c6.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/wbrick1_5.png b/3d/first_person_shooter/textures/wbrick1_5.png
new file mode 100644
index 00000000000..277d48657fb
Binary files /dev/null and b/3d/first_person_shooter/textures/wbrick1_5.png differ
diff --git a/3d/first_person_shooter/textures/wbrick1_5.png.import b/3d/first_person_shooter/textures/wbrick1_5.png.import
new file mode 100644
index 00000000000..7d1529214d9
--- /dev/null
+++ b/3d/first_person_shooter/textures/wbrick1_5.png.import
@@ -0,0 +1,41 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b055xilnvnivl"
+path.s3tc="res://.godot/imported/wbrick1_5.png-4764609ac0c4b0510a6d0377462bfb39.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+
+[deps]
+
+source_file="res://textures/wbrick1_5.png"
+dest_files=["res://.godot/imported/wbrick1_5.png-4764609ac0c4b0510a6d0377462bfb39.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/3d/first_person_shooter/textures/wswamp2_1.png b/3d/first_person_shooter/textures/wswamp2_1.png
new file mode 100644
index 00000000000..d7e0a4448bd
Binary files /dev/null and b/3d/first_person_shooter/textures/wswamp2_1.png differ
diff --git a/3d/first_person_shooter/textures/wswamp2_1.png.import b/3d/first_person_shooter/textures/wswamp2_1.png.import
new file mode 100644
index 00000000000..75e64ec5d58
--- /dev/null
+++ b/3d/first_person_shooter/textures/wswamp2_1.png.import
@@ -0,0 +1,40 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cgffiwx3qycnj"
+path="res://.godot/imported/wswamp2_1.png-287dab65e07b44d9ff27f51dc1a25616.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://textures/wswamp2_1.png"
+dest_files=["res://.godot/imported/wswamp2_1.png-287dab65e07b44d9ff27f51dc1a25616.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/uastc_level=0
+compress/rdo_quality_loss=0.0
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/channel_remap/red=0
+process/channel_remap/green=1
+process/channel_remap/blue=2
+process/channel_remap/alpha=3
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/3d/first_person_shooter/water.gd b/3d/first_person_shooter/water.gd
new file mode 100644
index 00000000000..af4421311f7
--- /dev/null
+++ b/3d/first_person_shooter/water.gd
@@ -0,0 +1,14 @@
+extends Area3D
+
+
+func _on_body_entered(body: Node3D) -> void:
+ if body is Player:
+ var player := body as Player
+ player.in_water = true
+ player.water_plane_y = global_position.y
+
+func _on_body_exited(body: Node3D) -> void:
+ if body is Player:
+ var player := body as Player
+ player.in_water = false
+ player.water_plane_y = -INF
diff --git a/3d/first_person_shooter/water.gd.uid b/3d/first_person_shooter/water.gd.uid
new file mode 100644
index 00000000000..fe7f3a864f2
--- /dev/null
+++ b/3d/first_person_shooter/water.gd.uid
@@ -0,0 +1 @@
+uid://cw8nvplg7xn01
diff --git a/3d/first_person_shooter/water.gdshader b/3d/first_person_shooter/water.gdshader
new file mode 100644
index 00000000000..b9e1c6b1555
--- /dev/null
+++ b/3d/first_person_shooter/water.gdshader
@@ -0,0 +1,77 @@
+// NOTE: Shader automatically converted from Godot Engine 4.0's StandardMaterial3D.
+
+shader_type spatial;
+render_mode blend_mix,depth_draw_opaque,cull_disabled,diffuse_burley,specular_schlick_ggx;
+uniform vec4 albedo : source_color;
+uniform sampler2D texture_albedo : source_color,filter_nearest_mipmap_anisotropic,repeat_enable;
+uniform float proximity_fade_distance;
+uniform float distance_fade_min;
+uniform float distance_fade_max;
+uniform float point_size : hint_range(0,128);
+uniform float roughness : hint_range(0,1);
+uniform sampler2D texture_metallic : hint_default_white,filter_nearest_mipmap_anisotropic,repeat_enable;
+uniform vec4 metallic_texture_channel;
+uniform sampler2D texture_roughness : hint_roughness_r,filter_nearest_mipmap_anisotropic,repeat_enable;
+uniform float specular;
+uniform float metallic;
+uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest;
+uniform sampler2D texture_normal : hint_roughness_normal,filter_nearest_mipmap_anisotropic,repeat_enable;
+uniform float normal_scale : hint_range(-16,16);
+varying vec3 uv1_triplanar_pos;
+uniform float uv1_blend_sharpness;
+varying vec3 uv1_power_normal;
+uniform vec3 uv1_scale;
+uniform vec3 uv1_offset;
+uniform vec3 uv2_scale;
+uniform vec3 uv2_offset;
+
+const float WAVE_AMPLITUDE = 0.125;
+const float WAVE_SPEED = 1.3;
+
+
+void vertex() {
+ TANGENT = vec3(0.0,0.0,-1.0) * abs(NORMAL.x);
+ TANGENT+= vec3(1.0,0.0,0.0) * abs(NORMAL.y);
+ TANGENT+= vec3(1.0,0.0,0.0) * abs(NORMAL.z);
+ TANGENT = normalize(TANGENT);
+ BINORMAL = vec3(0.0,1.0,0.0) * abs(NORMAL.x);
+ BINORMAL+= vec3(0.0,0.0,-1.0) * abs(NORMAL.y);
+ BINORMAL+= vec3(0.0,1.0,0.0) * abs(NORMAL.z);
+ BINORMAL = normalize(BINORMAL);
+ uv1_power_normal=pow(abs(NORMAL),vec3(uv1_blend_sharpness));
+ uv1_triplanar_pos = VERTEX * uv1_scale + uv1_offset;
+ uv1_power_normal/=dot(uv1_power_normal,vec3(1.0));
+ uv1_triplanar_pos *= vec3(1.0,-1.0, 1.0);
+
+ // Make the surface wave.
+ VERTEX.y += -WAVE_AMPLITUDE + (sin(VERTEX.x + TIME * WAVE_SPEED) + sin(VERTEX.z * 2.0 + TIME * WAVE_SPEED)) * WAVE_AMPLITUDE;
+}
+
+
+vec4 triplanar_texture(sampler2D p_sampler,vec3 p_weights,vec3 p_triplanar_pos) {
+ vec4 samp=vec4(0.0);
+ samp+= texture(p_sampler,p_triplanar_pos.xy) * p_weights.z;
+ samp+= texture(p_sampler,p_triplanar_pos.xz) * p_weights.y;
+ samp+= texture(p_sampler,p_triplanar_pos.zy * vec2(-1.0,1.0)) * p_weights.x;
+ return samp;
+}
+
+
+void fragment() {
+ vec4 albedo_tex = triplanar_texture(texture_albedo,uv1_power_normal,uv1_triplanar_pos);
+ ALBEDO = albedo.rgb * albedo_tex.rgb;
+ float metallic_tex = dot(triplanar_texture(texture_metallic,uv1_power_normal,uv1_triplanar_pos),metallic_texture_channel);
+ METALLIC = metallic_tex * metallic;
+ vec4 roughness_texture_channel = vec4(1.0,0.0,0.0,0.0);
+ float roughness_tex = dot(triplanar_texture(texture_roughness,uv1_power_normal,uv1_triplanar_pos),roughness_texture_channel);
+ ROUGHNESS = roughness_tex * roughness;
+ SPECULAR = specular;
+ NORMAL_MAP = triplanar_texture(texture_normal,uv1_power_normal,uv1_triplanar_pos).rgb;
+ NORMAL_MAP_DEPTH = normal_scale;
+ ALPHA *= albedo.a * albedo_tex.a;
+ float depth_tex = textureLod(depth_texture,SCREEN_UV,0.0).r;
+ vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV*2.0-1.0,depth_tex,1.0);
+ world_pos.xyz/=world_pos.w;
+ ALPHA*=clamp(1.0-smoothstep(world_pos.z+proximity_fade_distance,world_pos.z,VERTEX.z),0.0,1.0);
+ ALPHA *= clamp(smoothstep(distance_fade_min, distance_fade_max, length(VERTEX)), 0.0, 1.0);
+}
diff --git a/3d/first_person_shooter/water.gdshader.uid b/3d/first_person_shooter/water.gdshader.uid
new file mode 100644
index 00000000000..2d063727647
--- /dev/null
+++ b/3d/first_person_shooter/water.gdshader.uid
@@ -0,0 +1 @@
+uid://ccjch2p4r8kbh
diff --git a/3d/first_person_shooter/water.tscn b/3d/first_person_shooter/water.tscn
new file mode 100644
index 00000000000..99a71e420f5
--- /dev/null
+++ b/3d/first_person_shooter/water.tscn
@@ -0,0 +1,131 @@
+[gd_scene load_steps=14 format=3 uid="uid://bsyjtyf6f54n7"]
+
+[ext_resource type="Script" uid="uid://cw8nvplg7xn01" path="res://water.gd" id="1_x4ob8"]
+[ext_resource type="Shader" uid="uid://ccjch2p4r8kbh" path="res://water.gdshader" id="2_746c1"]
+[ext_resource type="Texture2D" uid="uid://bhpmngp0r2y80" path="res://water_texture_albedo.tres" id="3_3g7ry"]
+[ext_resource type="Texture2D" uid="uid://bjo2g4bppx3gp" path="res://water_texture_normal.tres" id="4_wox83"]
+[ext_resource type="Shader" uid="uid://mvfjq0ami7dx" path="res://water_shadow.gdshader" id="5_ywqbu"]
+
+[sub_resource type="PlaneMesh" id="PlaneMesh_olnn8"]
+size = Vector2(15, 30)
+subdivide_width = 16
+subdivide_depth = 16
+
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_fsido"]
+render_priority = 0
+shader = ExtResource("2_746c1")
+shader_parameter/albedo = Color(1, 1, 1, 1)
+shader_parameter/texture_albedo = ExtResource("3_3g7ry")
+shader_parameter/proximity_fade_distance = 0.5
+shader_parameter/distance_fade_min = 0.0
+shader_parameter/distance_fade_max = 10.0
+shader_parameter/point_size = 0.0
+shader_parameter/roughness = 0.0
+shader_parameter/metallic_texture_channel = Vector4(0, 0, 0, 0)
+shader_parameter/specular = 1.0
+shader_parameter/metallic = 0.0
+shader_parameter/texture_normal = ExtResource("4_wox83")
+shader_parameter/normal_scale = 1.0
+shader_parameter/uv1_blend_sharpness = 1.0
+shader_parameter/uv1_scale = Vector3(0.125, 0.125, 0.125)
+shader_parameter/uv1_offset = Vector3(0, 0, 0)
+shader_parameter/uv2_scale = Vector3(1, 1, 1)
+shader_parameter/uv2_offset = Vector3(0, 0, 0)
+
+[sub_resource type="PlaneMesh" id="PlaneMesh_1yxun"]
+size = Vector2(15, 30)
+subdivide_width = 16
+subdivide_depth = 16
+
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_3vrxf"]
+render_priority = 0
+shader = ExtResource("5_ywqbu")
+
+[sub_resource type="BoxShape3D" id="BoxShape3D_04k8c"]
+size = Vector3(15, 6, 30)
+
+[sub_resource type="Animation" id="Animation_2y52n"]
+length = 0.001
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Surface:surface_material_override/0:shader_parameter/uv1_offset")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 0,
+"values": [Vector3(0, 0, 0)]
+}
+
+[sub_resource type="Animation" id="Animation_as77u"]
+resource_name = "water_surface"
+length = 60.0
+loop_mode = 1
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("Surface:surface_material_override/0:shader_parameter/uv1_offset")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0, 33, 60),
+"transitions": PackedFloat32Array(-2, -2, -2),
+"update": 0,
+"values": [Vector3(0, 0, 0), Vector3(2, 1, 1), Vector3(3, 0, -1)]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_vu6de"]
+_data = {
+&"RESET": SubResource("Animation_2y52n"),
+&"water_surface": SubResource("Animation_as77u")
+}
+
+[node name="Water" type="Area3D"]
+collision_mask = 7
+gravity_space_override = 3
+gravity = -10.0
+linear_damp_space_override = 1
+linear_damp = 4.0
+angular_damp_space_override = 1
+angular_damp = 1.0
+audio_bus_override = true
+script = ExtResource("1_x4ob8")
+
+[node name="Surface" type="MeshInstance3D" parent="."]
+layers = 8
+mesh = SubResource("PlaneMesh_olnn8")
+surface_material_override/0 = SubResource("ShaderMaterial_fsido")
+
+[node name="ShadowBlock" type="MeshInstance3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0)
+layers = 8
+cast_shadow = 3
+mesh = SubResource("PlaneMesh_1yxun")
+surface_material_override/0 = SubResource("ShaderMaterial_3vrxf")
+
+[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -3, 0)
+shape = SubResource("BoxShape3D_04k8c")
+
+[node name="GPUParticlesCollisionBox3D" type="GPUParticlesCollisionBox3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -3, 0)
+cull_mask = 4294967293
+size = Vector3(15, 6, 30)
+
+[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
+libraries = {
+&"": SubResource("AnimationLibrary_vu6de")
+}
+autoplay = "water_surface"
+
+[node name="ReflectionProbe" type="ReflectionProbe" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1.2)
+max_distance = 10000.0
+size = Vector3(18, 20, 29)
+box_projection = true
+ambient_mode = 0
+
+[connection signal="body_entered" from="." to="." method="_on_body_entered"]
+[connection signal="body_exited" from="." to="." method="_on_body_exited"]
diff --git a/3d/first_person_shooter/water_shadow.gdshader b/3d/first_person_shooter/water_shadow.gdshader
new file mode 100644
index 00000000000..ba890abb8c2
--- /dev/null
+++ b/3d/first_person_shooter/water_shadow.gdshader
@@ -0,0 +1,16 @@
+// This shader is used for the shadow-only water plane. A separate MeshInstance3D and shader
+// are required, as an opaque material must be used for GeometryInstance3D's
+// Shadows Only `cast_shadow` mode to work.
+//
+// The shadow plane is placed slightly above the main water plane to compensate
+// for shadow bias.
+shader_type spatial;
+
+// Should match the constants in `water.gdshader`.
+const float WAVE_AMPLITUDE = 0.125;
+const float WAVE_SPEED = 1.3;
+
+void vertex() {
+ // Make the surface wave (same as in `water.gdshader`).
+ VERTEX.y += -WAVE_AMPLITUDE + (sin(VERTEX.x + TIME * WAVE_SPEED) + sin(VERTEX.z * 2.0 + TIME * WAVE_SPEED)) * WAVE_AMPLITUDE;
+}
diff --git a/3d/first_person_shooter/water_shadow.gdshader.uid b/3d/first_person_shooter/water_shadow.gdshader.uid
new file mode 100644
index 00000000000..018b9a4c01f
--- /dev/null
+++ b/3d/first_person_shooter/water_shadow.gdshader.uid
@@ -0,0 +1 @@
+uid://mvfjq0ami7dx
diff --git a/3d/first_person_shooter/water_texture_albedo.tres b/3d/first_person_shooter/water_texture_albedo.tres
new file mode 100644
index 00000000000..a122ef20c35
--- /dev/null
+++ b/3d/first_person_shooter/water_texture_albedo.tres
@@ -0,0 +1,20 @@
+[gd_resource type="NoiseTexture2D" load_steps=3 format=3 uid="uid://bhpmngp0r2y80"]
+
+[sub_resource type="Gradient" id="Gradient_vg3fo"]
+interpolation_mode = 2
+offsets = PackedFloat32Array(0, 0.987013)
+colors = PackedColorArray(0.555, 0.555, 0.74, 0.490196, 0.75, 1, 1, 0.823529)
+
+[sub_resource type="FastNoiseLite" id="FastNoiseLite_e2g8a"]
+noise_type = 2
+fractal_type = 0
+domain_warp_enabled = true
+domain_warp_type = 2
+
+[resource]
+width = 256
+height = 256
+noise = SubResource("FastNoiseLite_e2g8a")
+color_ramp = SubResource("Gradient_vg3fo")
+seamless = true
+seamless_blend_skirt = 1.0
diff --git a/3d/first_person_shooter/water_texture_normal.tres b/3d/first_person_shooter/water_texture_normal.tres
new file mode 100644
index 00000000000..cb6ddf366b9
--- /dev/null
+++ b/3d/first_person_shooter/water_texture_normal.tres
@@ -0,0 +1,16 @@
+[gd_resource type="NoiseTexture2D" load_steps=2 format=3 uid="uid://bjo2g4bppx3gp"]
+
+[sub_resource type="FastNoiseLite" id="FastNoiseLite_e2g8a"]
+noise_type = 2
+fractal_type = 0
+domain_warp_enabled = true
+domain_warp_type = 2
+
+[resource]
+width = 256
+height = 256
+noise = SubResource("FastNoiseLite_e2g8a")
+seamless = true
+as_normal_map = true
+seamless_blend_skirt = 1.0
+bump_strength = 0.2