Files
tactical-shooter/client/map_template/template_map.tscn
T
shawn e7299b17e9 Phase 7: netfox + godot-jolt stack upgrade
Stack installed:
- netfox v1.35.3 (core + extras + noray + internals)
- godot-jolt v0.16.0-stable

Architecture:
- Server: ENet transport (works headless, no netfox deps)
- Client/Editor: netfox rollback (RollbackSynchronizer, TickInterpolator)

New/modified:
- docs/migration-netfox-plan.md — migration architecture
- scripts/network/network_manager.gd — netfox-aware ENet fallback
- scripts/network/player.gd — clean base player
- client/characters/player_netfox.gd — rollback player w/ WeaponManager
- client/characters/input/player_net_input.gd — BaseNetInput subclass
- client/characters/character/fps_character_controller.gd — netfox input feed
- client/weapons/ — weapon data, registry, TacticalWeaponHitscan, WeaponManager
- client/scripts/round_replicator.gd — client-side round state bridge
- server/scripts/round_manager.gd — improved state machine
- server/scripts/plugin_api/plugin_manager.gd — refined plugin system
- config: enemy_tag, ally_tag for meatball targeting

Removed: old C++ SimulationServer GDExtension (replaced by netfox rollback)
2026-07-02 17:39:22 -04:00

357 lines
12 KiB
Plaintext

[gd_scene load_steps=32 format=3]
; === Prefab references ===
[ext_resource type="PackedScene" path="res://assets/prefabs/ct_spawn.tscn" id="1"]
[ext_resource type="PackedScene" path="res://assets/prefabs/t_spawn.tscn" id="2"]
[ext_resource type="PackedScene" path="res://assets/prefabs/buy_zone.tscn" id="3"]
[ext_resource type="PackedScene" path="res://assets/prefabs/bomb_site.tscn" id="4"]
[ext_resource type="PackedScene" path="res://assets/prefabs/cubemap_origin.tscn" id="5"]
[ext_resource type="PackedScene" path="res://assets/prefabs/map_bounds.tscn" id="6"]
; === Script ===
[ext_resource type="Script" path="res://template_map.gd" id="7"]
; === Subresources — Materials ===
[sub_resource type="StandardMaterial3D" id="FloorMat"]
albedo_color = Color(0.3, 0.3, 0.32, 1.0)
metallic = 0.0
roughness = 0.9
[sub_resource type="StandardMaterial3D" id="WallMat"]
albedo_color = Color(0.55, 0.55, 0.58, 1.0)
metallic = 0.0
roughness = 0.85
[sub_resource type="StandardMaterial3D" id="TrimMat"]
albedo_color = Color(0.25, 0.25, 0.28, 1.0)
metallic = 0.3
roughness = 0.6
[sub_resource type="StandardMaterial3D" id="FloorTrimMat"]
albedo_color = Color(0.2, 0.2, 0.22, 1.0)
metallic = 0.1
roughness = 0.7
[sub_resource type="StandardMaterial3D" id="SiteAFloorMat"]
albedo_color = Color(0.45, 0.35, 0.25, 1.0)
metallic = 0.0
roughness = 0.9
[sub_resource type="StandardMaterial3D" id="SiteBFloorMat"]
albedo_color = Color(0.3, 0.35, 0.45, 1.0)
metallic = 0.0
roughness = 0.9
[sub_resource type="StandardMaterial3D" id="PillarMat"]
albedo_color = Color(0.4, 0.4, 0.42, 1.0)
metallic = 0.2
roughness = 0.7
; === Subresources — Environment ===
[sub_resource type="Environment" id="Env"]
background_mode = 0
tonemap_mode = 0
glow_enabled = false
ambient_light_color = Color(0.2, 0.22, 0.25, 1.0)
ambient_light_energy = 0.35
ambient_light_sky_contribution = 0.0
; ============================
; === SHOWROOM DEMO MAP ===
; ============================
; This template demonstrates a 3-lane layout with:
; - CSG floor, walls, pillars, and dividers
; - CT spawn (left) and T spawn (right) with buy zones
; - Bomb sites A (CT-side) and B (T-side)
; - Cubemap origin for reflections
; - Map bounds around the perimeter
;
; Copy this .tscn + assets/prefabs/ to start a new map.
; Replace CSG geometry with the modular kit pieces from the main project.
[node name="TemplateMap" type="Node3D"]
script = ExtResource("7")
; ============ FLOOR ============
; Main floor — CSG box covering the entire playable area
; Subdivided into functional zones with different floor materials
[node name="Floor" type="CSGBox3D" parent="."]
size = Vector3(20.0, 0.08, 16.0)
material = SubResource("FloorMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
; Bombsite A floor — warmer tones (CT side, middle-left)
[node name="SiteAFloor" type="CSGCombiner3D" parent="."]
use_collision = false
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.0, 0, -3.0)
[node name="Base" type="CSGBox3D" parent="SiteAFloor"]
operation = 0
size = Vector3(5.0, 0.09, 5.0)
material = SubResource("SiteAFloorMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.005, 0)
; Bombsite B floor — cooler tones (T side, middle-right)
[node name="SiteBFloor" type="CSGCombiner3D" parent="."]
use_collision = false
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.0, 0, -3.0)
[node name="Base" type="CSGBox3D" parent="SiteBFloor"]
operation = 0
size = Vector3(5.0, 0.09, 5.0)
material = SubResource("SiteBFloorMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.005, 0)
; Floor trim — baseboard around perimeter
; North wall trim
[node name="FloorTrim_N" type="CSGBox3D" parent="."]
size = Vector3(20.0, 0.24, 0.08)
material = SubResource("FloorTrimMat")
use_collision = false
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.04, -8.04)
; South wall trim
[node name="FloorTrim_S" type="CSGBox3D" parent="."]
size = Vector3(20.0, 0.24, 0.08)
material = SubResource("FloorTrimMat")
use_collision = false
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.04, 8.04)
; West wall trim
[node name="FloorTrim_W" type="CSGBox3D" parent="."]
size = Vector3(0.08, 0.24, 16.0)
material = SubResource("FloorTrimMat")
use_collision = false
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10.04, 0.04, 0)
; East wall trim
[node name="FloorTrim_E" type="CSGBox3D" parent="."]
size = Vector3(0.08, 0.24, 16.0)
material = SubResource("FloorTrimMat")
use_collision = false
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10.04, 0.04, 0)
; Center divider wall (floor-level trim)
[node name="DividerTrim" type="CSGBox3D" parent="."]
size = Vector3(0.08, 0.32, 8.0)
material = SubResource("TrimMat")
use_collision = false
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.04, 1.0)
; ============ WALLS ============
; --- North wall (Z = -8) ---
[node name="Wall_N" type="CSGBox3D" parent="."]
size = Vector3(20.0, 3.0, 0.16)
material = SubResource("WallMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, -8.0)
; --- South wall (Z = 8) ---
[node name="Wall_S" type="CSGBox3D" parent="."]
size = Vector3(20.0, 3.0, 0.16)
material = SubResource("WallMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 8.0)
; --- West wall (X = -10) ---
[node name="Wall_W" type="CSGBox3D" parent="."]
size = Vector3(0.16, 3.0, 16.0)
material = SubResource("WallMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10.0, 1.5, 0)
; --- East wall (X = 10) ---
[node name="Wall_E" type="CSGBox3D" parent="."]
size = Vector3(0.16, 3.0, 16.0)
material = SubResource("WallMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10.0, 1.5, 0)
; ============ INTERIOR DIVIDERS ============
; CT-side cover wall — partial wall to create a corridor
[node name="Divider_CT" type="CSGBox3D" parent="."]
size = Vector3(0.16, 2.4, 4.0)
material = SubResource("WallMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -6.0, 1.2, -4.0)
; T-side cover wall
[node name="Divider_T" type="CSGBox3D" parent="."]
size = Vector3(0.16, 2.4, 4.0)
material = SubResource("WallMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6.0, 1.2, -4.0)
; Mid divider — lane separator running from CT area toward T area
[node name="MidWall" type="CSGBox3D" parent="."]
size = Vector3(0.16, 2.0, 6.0)
material = SubResource("WallMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0, 1.0)
; Mid divider short — second offset wall for zigzag corridor
[node name="MidWallShort" type="CSGBox3D" parent="."]
size = Vector3(3.0, 2.0, 0.16)
material = SubResource("WallMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.0, 1.0, -3.0)
; ============ PILLARS ============
[node name="Pillar_1" type="CSGBox3D" parent="."]
size = Vector3(0.4, 2.8, 0.4)
material = SubResource("PillarMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.0, 1.4, 2.0)
[node name="Pillar_2" type="CSGBox3D" parent="."]
size = Vector3(0.4, 2.8, 0.4)
material = SubResource("PillarMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.0, 1.4, 2.0)
[node name="Pillar_3" type="CSGBox3D" parent="."]
size = Vector3(0.4, 2.8, 0.4)
material = SubResource("PillarMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.0, 1.4, -5.0)
[node name="Pillar_4" type="CSGBox3D" parent="."]
size = Vector3(0.4, 2.8, 0.4)
material = SubResource("PillarMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.0, 1.4, -5.0)
; ============ CEILING / SKYBOX BOUNDARY ============
; Ceiling panel (roof) — encloses the room for lightmap baking
[node name="Ceiling" type="CSGBox3D" parent="."]
size = Vector3(20.0, 0.08, 16.0)
material = SubResource("TrimMat")
use_collision = true
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3.0, 0)
; ============ GAMEPLAY PREFABS ============
; --- Spawn points ---
; CT spawns (left side of map)
[node name="CTSpawn1" parent="." instance=ExtResource("1")]
; CT spawn 1 — main position
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.0, 0.03, -5.0)
[node name="CTSpawn2" parent="." instance=ExtResource("1")]
; CT spawn 2 — staggered offset for multi-player spawn
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.0, 0.03, -3.0)
[node name="CTSpawn3" parent="." instance=ExtResource("1")]
; CT spawn 3
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.0, 0.03, -1.0)
; T spawns (right side of map)
[node name="TSpawn1" parent="." instance=ExtResource("2")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8.0, 0.03, 5.0)
[node name="TSpawn2" parent="." instance=ExtResource("2")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8.0, 0.03, 3.0)
[node name="TSpawn3" parent="." instance=ExtResource("2")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8.0, 0.03, 1.0)
; --- Buy zones ---
[node name="CTBuyZone" parent="." instance=ExtResource("3")]
; Buy zone at CT spawn — players can buy in this area
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8.0, 1.5, -3.0)
; Resize the CollisionShape3D child to cover the CT spawn area
[node name="TBuyZone" parent="." instance=ExtResource("3")]
; Buy zone at T spawn
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 8.0, 1.5, 3.0)
; --- Bomb sites ---
[node name="BombsiteA" parent="." instance=ExtResource("4")]
; Bomb site A — CT-side area (warm floor zone)
groups = ["bomb_site"]
; Additional group "bombsite_a" for game logic identification
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.0, 0.5, -3.0)
; Resize Child/CollisionShape3D to match the brown floor zone (5x5)
[node name="BombsiteB" parent="." instance=ExtResource("4")]
; Bomb site B — T-side area (cool floor zone)
groups = ["bomb_site", "bombsite_b"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.0, 0.5, -3.0)
; Resize Child/CollisionShape3D to match the blue floor zone (5x5)
; --- Cubemap origin ---
[node name="CubemapOrigin" parent="." instance=ExtResource("5")]
; Reflection probe capture position at eye height in the middle lane
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6, 0)
; --- Map bounds ---
; Perimeter boundary walls — extend slightly beyond visible walls
[node name="Bound_N" parent="." instance=ExtResource("6")]
; North bounds
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.0, -10.0)
[node name="Bound_S" parent="." instance=ExtResource("6")]
; South bounds
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.0, 10.0)
[node name="Bound_W" parent="." instance=ExtResource("6")]
; West bounds — rotate 90°
transform = Transform3D(0, 0, -1, 0, 1, 0, 1, 0, 0, -12.0, 2.0, 0)
[node name="Bound_E" parent="." instance=ExtResource("6")]
; East bounds — rotate 90°
transform = Transform3D(0, 0, 1, 0, 1, 0, -1, 0, 0, 12.0, 2.0, 0)
; ============ LIGHTING ============
; WorldEnvironment — sky and ambient light
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Env")
; Directional light — key light from high angle (slightly warm)
[node name="SunLight" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.866, 0, -0.5, -0.354, 0.707, -0.612, 0.354, 0.707, 0.612, 0, 5, 0)
light_energy = 1.0
light_indirect_energy = 0.8
light_color = Color(1.0, 0.95, 0.9, 1.0)
shadow_enabled = true
light_bake_mode = 2
directional_shadow_max_distance = 30.0
directional_shadow_split_1 = 0.1
directional_shadow_split_2 = 0.3
directional_shadow_split_3 = 0.6
directional_shadow_blend_splits = true
; Fill light — warm interior ambient from the center
[node name="FillLight" type="OmniLight3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, -2.0)
light_energy = 0.3
light_indirect_energy = 0.4
light_color = Color(1.0, 0.85, 0.7, 1.0)
light_bake_mode = 2
omni_range = 8.0
omni_attenuation = 0.8
shadow_enabled = false
; Reflection probe — interior specular reflections, positioned at cubemap origin
[node name="ReflectionProbe" type="ReflectionProbe" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6, 0)
box_projection = true
interior = true
extents = Vector3(10.0, 1.8, 8.0)
intensity = 1.0
max_distance = 15.0
; LightmapGI — baked global illumination
[node name="LightmapGI" type="LightmapGI" parent="."]
quality = 2
bounces = 3
bounce_indirect_energy = 1.0
texel_scale = 1.0
max_texture_size = 2048
use_denoiser = true
interior = true