Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94ffe6e7b7 | ||
|
|
4121c59484 | ||
|
|
c267b62afa | ||
|
|
cde0e28e44 | ||
|
|
18c3d6fc5d | ||
|
|
942cd59db8 | ||
|
|
7faef2e976 | ||
|
|
7f21b40d93 | ||
|
|
3b21cf3182 | ||
|
|
9e3df6c691 | ||
|
|
2cb8a7fb8f | ||
|
|
09e6b4cc90 | ||
|
|
e6a442c98b | ||
|
|
cce8fd3280 | ||
|
|
ffee63dc57 | ||
|
|
2907fabe85 | ||
|
|
3f3136c453 | ||
|
|
84afc199fa | ||
|
|
fecbefc15c | ||
|
|
a9e546a121 | ||
|
|
98220921bd | ||
|
|
42750356b5 | ||
|
|
753a34abd5 | ||
|
|
020ede82b6 | ||
|
|
25de3bf08e |
@@ -4,8 +4,8 @@ This project is a multi-layered application consisting of a Godot-based game and
|
|||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
- `game/`: The Godot 4.5 game project.
|
- `game/`: The Godot 4.6 game project.
|
||||||
- `microservices/`: ASP.NET Core 8.0 microservices providing backend logic (Auth, Character, Inventory, Locations, etc.).
|
- `microservices/`: ASP.NET Core 8.0 microservices providing backend logic (Auth, Character, Crafting, Inventory, Locations, Mail, and World).
|
||||||
- `.gitea/workflows/`: CI/CD pipelines for deploying microservices to Kubernetes.
|
- `.gitea/workflows/`: CI/CD pipelines for deploying microservices to Kubernetes.
|
||||||
|
|
||||||
## Core Mandates
|
## Core Mandates
|
||||||
@@ -17,7 +17,7 @@ This project is a multi-layered application consisting of a Godot-based game and
|
|||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
- **Microservices**: Each microservice can be run individually or via the `micro-services.sln` solution file. They require a MongoDB instance (default: `mongodb://127.0.0.1:27017`).
|
- **Microservices**: Each microservice can be run individually or via the `micro-services.sln` solution file. They require a MongoDB instance (default: `mongodb://127.0.0.1:27017`).
|
||||||
- **Game**: Open `game/project.godot` in Godot Engine 4.5+.
|
- **Game**: Open `game/project.godot` in Godot Engine 4.6+.
|
||||||
|
|
||||||
## Shared Conventions
|
## Shared Conventions
|
||||||
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# Set the default behavior, in case people don't have core.autocrlf set.
|
||||||
|
* text=auto
|
||||||
|
# Explicitly declare text files you want to always be normalized and converted
|
||||||
|
# to native line endings on checkout.
|
||||||
|
*.cs text diff=csharp
|
||||||
|
*.gd text
|
||||||
|
*.tscn text
|
||||||
|
*.tres text
|
||||||
|
*.json text
|
||||||
|
*.md text
|
||||||
|
*.xml text
|
||||||
|
*.yml text
|
||||||
|
*.yaml text
|
||||||
|
*.csproj text
|
||||||
|
*.sln text
|
||||||
|
# Declare files that will always have CRLF line endings on checkout.
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.ps1 text eol=crlf
|
||||||
|
# Denote all files that are truly binary and should not be modified.
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.gif binary
|
||||||
|
*.ico binary
|
||||||
|
*.mov binary
|
||||||
|
*.mp4 binary
|
||||||
|
*.mp3 binary
|
||||||
|
*.wav binary
|
||||||
|
*.ogg binary
|
||||||
|
*.ttf binary
|
||||||
|
*.otf binary
|
||||||
|
*.woff binary
|
||||||
|
*.woff2 binary
|
||||||
|
*.eot binary
|
||||||
|
*.pdf binary
|
||||||
|
*.zip binary
|
||||||
|
*.7z binary
|
||||||
|
*.import binary
|
||||||
|
*.uid binary
|
||||||
|
*.glb filter=lfs diff=lfs merge=lfs -text
|
||||||
@@ -4,6 +4,9 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
paths:
|
||||||
|
- "microservices/AuthApi/**"
|
||||||
|
- ".gitea/workflows/deploy-auth.yml"
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -20,6 +23,16 @@ jobs:
|
|||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Reclaim Docker build space
|
||||||
|
run: |
|
||||||
|
rm -f "${IMAGE_TAR}"
|
||||||
|
docker container prune -f
|
||||||
|
docker image prune -f
|
||||||
|
docker image prune -af --filter "until=24h"
|
||||||
|
docker builder prune -af || true
|
||||||
|
docker system df
|
||||||
|
df -h
|
||||||
|
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
# Build Docker image
|
# Build Docker image
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
@@ -59,18 +72,22 @@ jobs:
|
|||||||
# CLEANUP: delete TAR from nodes
|
# CLEANUP: delete TAR from nodes
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
- name: Clean TAR from nodes
|
- name: Clean TAR from nodes
|
||||||
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
for node in ${NODES}; do
|
for node in ${NODES}; do
|
||||||
echo "Removing image tar on $node ..."
|
echo "Removing image tar on $node ..."
|
||||||
ssh -o StrictHostKeyChecking=no hz@"$node" "rm -f /tmp/promiscuity-auth.tar"
|
ssh -o StrictHostKeyChecking=no hz@"$node" "rm -f /tmp/promiscuity-auth.tar" || true
|
||||||
done
|
done
|
||||||
|
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
# CLEANUP: delete TAR from runner
|
# CLEANUP: delete TAR from runner
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
- name: Clean TAR on runner
|
- name: Clean TAR on runner
|
||||||
|
if: always()
|
||||||
run: |
|
run: |
|
||||||
rm -f "${IMAGE_TAR}"
|
rm -f "${IMAGE_TAR}"
|
||||||
|
docker image rm "${IMAGE_NAME}" 2>/dev/null || true
|
||||||
|
docker image prune -f
|
||||||
|
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
# Write kubeconfig from secret
|
# Write kubeconfig from secret
|
||||||
@@ -91,6 +108,16 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
kubectl create namespace promiscuity-auth --dry-run=client -o yaml | kubectl apply -f -
|
kubectl create namespace promiscuity-auth --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
|
- name: Configure internal API secret
|
||||||
|
env:
|
||||||
|
KUBECONFIG: /tmp/kube/config
|
||||||
|
INTERNAL_PURGE_SECRET: ${{ secrets.INTERNAL_PURGE_SECRET }}
|
||||||
|
run: |
|
||||||
|
test -n "$INTERNAL_PURGE_SECRET"
|
||||||
|
kubectl create secret generic medmind-internal-api \
|
||||||
|
--from-literal=purge-secret="$INTERNAL_PURGE_SECRET" \
|
||||||
|
--dry-run=client -o yaml | kubectl apply -n promiscuity-auth -f -
|
||||||
|
|
||||||
# -----------------------------
|
# -----------------------------
|
||||||
# Apply Kubernetes manifests
|
# Apply Kubernetes manifests
|
||||||
# (You create these files in your repo)
|
# (You create these files in your repo)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
paths:
|
||||||
|
- "microservices/CharacterApi/**"
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
paths:
|
||||||
|
- "microservices/CraftingApi/**"
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
paths:
|
||||||
|
- "microservices/InventoryApi/**"
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
paths:
|
||||||
|
- "microservices/LocationsApi/**"
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
paths:
|
||||||
|
- "microservices/MailApi/**"
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
paths:
|
||||||
|
- "microservices/WorldApi/**"
|
||||||
workflow_dispatch: {}
|
workflow_dispatch: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
@@ -18,5 +18,9 @@
|
|||||||
- Sprint: Shift
|
- Sprint: Shift
|
||||||
- Interact (enter/exit car): E
|
- Interact (enter/exit car): E
|
||||||
- Flashlight: F
|
- Flashlight: F
|
||||||
|
- Radial command menu: Q
|
||||||
|
- Fireball: Shift + B
|
||||||
- Phone: Tab
|
- Phone: Tab
|
||||||
- Pause menu: Esc
|
- Pause menu: Esc
|
||||||
|
- Toggle first/third person: V
|
||||||
|
- Zoom (in/out): Scroll Wheel (snaps to First Person on zoom in)
|
||||||
|
|||||||
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 1.8 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.9 MiB |
|
After Width: | Height: | Size: 1.6 MiB |
@@ -1,21 +1,25 @@
|
|||||||
# Godot Game Development - GEMINI.md
|
# Godot Game Development - GEMINI.md
|
||||||
|
|
||||||
This directory contains the Godot 4.5 game project for "Promiscuity".
|
This directory contains the Godot 4.6 game project for "Promiscuity".
|
||||||
|
|
||||||
## Core Mandates
|
## Core Mandates
|
||||||
|
|
||||||
- **Engine Version**: Godot 4.5 (Forward Plus).
|
- **Engine Version**: Godot 4.6 (Forward Plus).
|
||||||
- **Language**: GDScript is the primary scripting language. C# is enabled but used only when performance or specific library needs arise.
|
- **Language**: GDScript is the primary scripting language. C# is enabled but used only when performance or specific library needs arise.
|
||||||
- **Naming Conventions**:
|
- **Naming Conventions**:
|
||||||
- Files/Folders: `snake_case.gd`, `snake_case.tscn`.
|
- Files/Folders: `snake_case.gd`, `snake_case.tscn`.
|
||||||
- Variables/Functions: `snake_case`.
|
- Variables/Functions: `snake_case`.
|
||||||
- Constants: `SCREAMING_SNAKE_CASE`.
|
- Constants: `SCREAMING_SNAKE_CASE`.
|
||||||
- Classes: `PascalCase`.
|
- Classes: `PascalCase`.
|
||||||
- **Autoloads**: Use the established singletons for global state and services:
|
- **Autoloads**: Use the established singletons for global state and services:
|
||||||
- `AuthState`: JWT authentication and session.
|
- `AuthState`: JWT authentication and session.
|
||||||
- `CharacterService`: API calls for character management.
|
- `CharacterService`: API calls for character management.
|
||||||
- `QuestManager`: Game quest progression.
|
- `SelectedCharacter`: Tracking the currently active character.
|
||||||
- `DialogSystem`: UI dialog and interaction.
|
- `QuestManager`: Game quest progression.
|
||||||
|
- `DialogSystem`: UI dialog and interaction.
|
||||||
|
- `TeleportState`: Handling transitions between levels.
|
||||||
|
- `MenuMusic` / `MenuSfx`: Audio management.
|
||||||
|
- `SimpleGrass`: Singleton for grass rendering.
|
||||||
- **Node Paths**: Prefer `unique names` (%NodeName) or `@onready` variables for node references. Avoid fragile string paths.
|
- **Node Paths**: Prefer `unique names` (%NodeName) or `@onready` variables for node references. Avoid fragile string paths.
|
||||||
|
|
||||||
## Asset Pipeline
|
## Asset Pipeline
|
||||||
@@ -27,11 +31,16 @@ This directory contains the Godot 4.5 game project for "Promiscuity".
|
|||||||
## Project Organization
|
## Project Organization
|
||||||
|
|
||||||
- `scenes/`: Scene files and associated scripts.
|
- `scenes/`: Scene files and associated scripts.
|
||||||
- `Characters/`: Player and NPC scenes.
|
- `Characters/`: Player and NPC scenes.
|
||||||
- `Levels/`: Game world/environments.
|
- `Levels/`: Game world/environments.
|
||||||
- `UI/`: Menus, HUDs, and UI components.
|
- `UI/`: Menus, HUDs, and UI components.
|
||||||
|
- `Interaction/`: Interactive objects and systems (e.g., RadialCommandMenu).
|
||||||
|
- `Projectiles/`: Projectiles like fireballs.
|
||||||
|
- `Quests/`: Quest-related scenes and logic.
|
||||||
|
- `Vehicles/`: Controllable vehicles.
|
||||||
|
- `CardGame/`: Minigame components.
|
||||||
- `assets/`: Raw assets (textures, models, audio).
|
- `assets/`: Raw assets (textures, models, audio).
|
||||||
- `addons/`: Third-party plugins (e.g., `simplegrasstextured`).
|
- `addons/`: Third-party plugins (e.g., `simplegrasstextured`, `godot_mcp`).
|
||||||
|
|
||||||
## Best Practices
|
## Best Practices
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://mcipi7y664aq
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="Godot MCP"
|
||||||
|
description="A plugin to enable communication between Godot Editor and Model Context Protocol (MCP) clients."
|
||||||
|
author="Your Name"
|
||||||
|
version="0.1.0"
|
||||||
|
script="plugin.gd"
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
# Structure for addons/godot_mcp/plugin.gd
|
||||||
|
@tool
|
||||||
|
extends EditorPlugin
|
||||||
|
|
||||||
|
const SERVER_PORT = 6400
|
||||||
|
var server: TCPServer = null
|
||||||
|
var active_connections = []
|
||||||
|
var command_handler
|
||||||
|
|
||||||
|
func _enter_tree():
|
||||||
|
# Initialize the plugin
|
||||||
|
print("Godot MCP Plugin activated")
|
||||||
|
|
||||||
|
# Create command handler
|
||||||
|
command_handler = preload("res://addons/godot_mcp/command_handler.gd").new()
|
||||||
|
command_handler.set_editor_plugin(self)
|
||||||
|
|
||||||
|
# Start the TCP server
|
||||||
|
server = TCPServer.new()
|
||||||
|
var error = server.listen(SERVER_PORT)
|
||||||
|
if error != OK:
|
||||||
|
push_error("Failed to start Godot MCP Server on port %d: %s" % [SERVER_PORT, error])
|
||||||
|
return
|
||||||
|
|
||||||
|
print("Godot MCP Server listening on port %d" % SERVER_PORT)
|
||||||
|
|
||||||
|
# Add UI
|
||||||
|
add_control_to_bottom_panel(
|
||||||
|
preload("res://addons/godot_mcp/ui/mcp_panel.tscn").instantiate(),
|
||||||
|
"MCP"
|
||||||
|
)
|
||||||
|
|
||||||
|
func _exit_tree():
|
||||||
|
# Clean up the plugin when disabled
|
||||||
|
if server:
|
||||||
|
server.stop()
|
||||||
|
server = null
|
||||||
|
|
||||||
|
for connection in active_connections:
|
||||||
|
if connection.get_status() == StreamPeerTCP.STATUS_CONNECTED:
|
||||||
|
connection.disconnect_from_host()
|
||||||
|
|
||||||
|
active_connections.clear()
|
||||||
|
|
||||||
|
# Remove UI
|
||||||
|
remove_control_from_bottom_panel(get_editor_interface().get_base_control().get_node("MCPPanel"))
|
||||||
|
print("Godot MCP Plugin deactivated")
|
||||||
|
|
||||||
|
func _process(delta):
|
||||||
|
# Check for new connections
|
||||||
|
if server and server.is_connection_available():
|
||||||
|
var connection = server.take_connection()
|
||||||
|
if connection:
|
||||||
|
active_connections.append(connection)
|
||||||
|
print("New MCP connection established")
|
||||||
|
|
||||||
|
# Process existing connections
|
||||||
|
var i = 0
|
||||||
|
while i < active_connections.size():
|
||||||
|
var connection = active_connections[i]
|
||||||
|
|
||||||
|
# Check connection status
|
||||||
|
if connection.get_status() != StreamPeerTCP.STATUS_CONNECTED:
|
||||||
|
active_connections.remove_at(i)
|
||||||
|
print("MCP connection closed")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check for incoming messages
|
||||||
|
if connection.get_available_bytes() > 0:
|
||||||
|
var data = _read_message(connection)
|
||||||
|
if data.size() > 0:
|
||||||
|
# Process the command
|
||||||
|
var response = _process_command(data)
|
||||||
|
|
||||||
|
# Send the response
|
||||||
|
_send_message(connection, response)
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
func _read_message(connection):
|
||||||
|
# Read data from the connection
|
||||||
|
var data = PackedByteArray()
|
||||||
|
var bytes_available = connection.get_available_bytes()
|
||||||
|
|
||||||
|
if bytes_available > 0:
|
||||||
|
data = connection.get_data(bytes_available)[1]
|
||||||
|
|
||||||
|
# Attempt to parse as JSON
|
||||||
|
var json_string = data.get_string_from_utf8()
|
||||||
|
var json = JSON.new()
|
||||||
|
var error = json.parse(json_string)
|
||||||
|
|
||||||
|
if error == OK:
|
||||||
|
return json.get_data()
|
||||||
|
else:
|
||||||
|
print("Failed to parse JSON: ", json.get_error_message())
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
func _send_message(connection, data):
|
||||||
|
# Convert to JSON and send
|
||||||
|
var json_string = JSON.stringify(data)
|
||||||
|
connection.put_data(json_string.to_utf8_buffer())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _process_command(data):
|
||||||
|
# Process the command and return a response
|
||||||
|
if data == null or typeof(data) != TYPE_DICTIONARY:
|
||||||
|
return {
|
||||||
|
"status": "error",
|
||||||
|
"error": "Invalid command format. Expected a dictionary."
|
||||||
|
}
|
||||||
|
|
||||||
|
if not data.has("type") or not data.has("params"):
|
||||||
|
return {
|
||||||
|
"status": "error",
|
||||||
|
"error": "Invalid command format. Expected 'type' and 'params' fields."
|
||||||
|
}
|
||||||
|
|
||||||
|
var command_type = data["type"]
|
||||||
|
var params = data["params"]
|
||||||
|
|
||||||
|
if command_type == "ping":
|
||||||
|
return {"status": "success", "result": {"message": "pong"}}
|
||||||
|
|
||||||
|
# Forward to command handler
|
||||||
|
var result = command_handler.handle_command(command_type, params)
|
||||||
|
|
||||||
|
# Check if result is valid
|
||||||
|
if result == null:
|
||||||
|
return {
|
||||||
|
"status": "error",
|
||||||
|
"error": "Command handler returned null result"
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.has("error"):
|
||||||
|
return {"status": "error", "error": result.error}
|
||||||
|
else:
|
||||||
|
return {"status": "success", "result": result}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://ddfhkiyge45tn
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
# addons/godot_mcp/ui/mcp_panel.gd
|
||||||
|
@tool
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
var status_label: Label
|
||||||
|
var port_field: SpinBox
|
||||||
|
var start_button: Button
|
||||||
|
var stop_button: Button
|
||||||
|
var log_display: TextEdit
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
# Set up references to UI elements
|
||||||
|
status_label = $VBoxContainer/StatusPanel/StatusLabel
|
||||||
|
port_field = $VBoxContainer/ConfigPanel/PortField
|
||||||
|
start_button = $VBoxContainer/ButtonPanel/StartButton
|
||||||
|
stop_button = $VBoxContainer/ButtonPanel/StopButton
|
||||||
|
log_display = $VBoxContainer/LogPanel/LogDisplay
|
||||||
|
|
||||||
|
# Initialize UI
|
||||||
|
port_field.value = 6400 # Default port
|
||||||
|
start_button.disabled = false
|
||||||
|
stop_button.disabled = true
|
||||||
|
|
||||||
|
# Connect signals
|
||||||
|
start_button.pressed.connect(_on_start_button_pressed)
|
||||||
|
stop_button.pressed.connect(_on_stop_button_pressed)
|
||||||
|
|
||||||
|
# Set initial status
|
||||||
|
update_status("Not running")
|
||||||
|
add_log_message("Godot MCP Plugin initialized")
|
||||||
|
|
||||||
|
func update_status(status_text: String, is_error: bool = false):
|
||||||
|
status_label.text = "Status: " + status_text
|
||||||
|
if is_error:
|
||||||
|
status_label.add_theme_color_override("font_color", Color(1, 0.3, 0.3))
|
||||||
|
else:
|
||||||
|
status_label.remove_theme_color_override("font_color")
|
||||||
|
|
||||||
|
func add_log_message(message: String):
|
||||||
|
var timestamp = Time.get_datetime_string_from_system()
|
||||||
|
log_display.text += "[" + timestamp + "] " + message + "\n"
|
||||||
|
log_display.scroll_vertical = log_display.get_line_count()
|
||||||
|
|
||||||
|
func _on_start_button_pressed():
|
||||||
|
# This function will be called from the plugin.gd script
|
||||||
|
# when the server is actually started
|
||||||
|
update_status("Running on port " + str(port_field.value))
|
||||||
|
start_button.disabled = true
|
||||||
|
stop_button.disabled = false
|
||||||
|
add_log_message("MCP Server started on port " + str(port_field.value))
|
||||||
|
|
||||||
|
func _on_stop_button_pressed():
|
||||||
|
# This function will be called from the plugin.gd script
|
||||||
|
# when the server is actually stopped
|
||||||
|
update_status("Stopped")
|
||||||
|
start_button.disabled = false
|
||||||
|
stop_button.disabled = true
|
||||||
|
add_log_message("MCP Server stopped")
|
||||||
|
|
||||||
|
# Function to be called from plugin.gd when a client connects
|
||||||
|
func on_client_connected():
|
||||||
|
add_log_message("Client connected")
|
||||||
|
update_status("Client connected")
|
||||||
|
|
||||||
|
# Function to be called from plugin.gd when a client disconnects
|
||||||
|
func on_client_disconnected():
|
||||||
|
add_log_message("Client disconnected")
|
||||||
|
update_status("Running (no clients)")
|
||||||
|
|
||||||
|
# Function to be called from plugin.gd when a command is received
|
||||||
|
func on_command_received(command_type, params):
|
||||||
|
add_log_message("Command received: " + command_type)
|
||||||
|
|
||||||
|
# Function to be called from plugin.gd when a response is sent
|
||||||
|
func on_response_sent(command_type, success):
|
||||||
|
var status = "Success" if success else "Failed"
|
||||||
|
add_log_message("Response sent for " + command_type + ": " + status)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bqabyd7ce60u0
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://dxvt86ck6b2a4"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://addons/godot_mcp/ui/mcp_panel.gd" id="1_4g23r"]
|
||||||
|
|
||||||
|
[node name="MCPPanel" type="Control"]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_4g23r")
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="StatusPanel" type="PanelContainer" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="StatusLabel" type="Label" parent="VBoxContainer/StatusPanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Status: Not running"
|
||||||
|
|
||||||
|
[node name="ConfigPanel" type="PanelContainer" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/ConfigPanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="PortLabel" type="Label" parent="VBoxContainer/ConfigPanel/HBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Port:"
|
||||||
|
|
||||||
|
[node name="PortField" type="SpinBox" parent="VBoxContainer/ConfigPanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
min_value = 1024.0
|
||||||
|
max_value = 65535.0
|
||||||
|
value = 6400.0
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="ButtonPanel" type="PanelContainer" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/ButtonPanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
alignment = 1
|
||||||
|
|
||||||
|
[node name="StartButton" type="Button" parent="VBoxContainer/ButtonPanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "Start Server"
|
||||||
|
|
||||||
|
[node name="StopButton" type="Button" parent="VBoxContainer/ButtonPanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
disabled = true
|
||||||
|
text = "Stop Server"
|
||||||
|
|
||||||
|
[node name="LogPanel" type="PanelContainer" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="LogDisplay" type="TextEdit" parent="VBoxContainer/LogPanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
editable = false
|
||||||
|
wrap_mode = 1
|
||||||
@@ -12,4 +12,4 @@ _surfaces = [{
|
|||||||
"vertex_count": 8,
|
"vertex_count": 8,
|
||||||
"vertex_data": PackedByteArray("AAAAvwAAgD8AAAAAAAAAPwAAAAAAAAAAAAAAvwAAAAAAAAAAAAAAPwAAgD8AAAAAAAAAAAAAgD8AAAC/AAAAAAAAAAAAAAA/AAAAAAAAAAAAAAC/AAAAAAAAgD8AAAA//3//f////7//f/9/////v/9//3////+//3//f////78AAP9//3//vwAA/3//f/+/AAD/f/9//78AAP9//3//vw==")
|
"vertex_data": PackedByteArray("AAAAvwAAgD8AAAAAAAAAPwAAAAAAAAAAAAAAvwAAAAAAAAAAAAAAPwAAgD8AAAAAAAAAAAAAgD8AAAC/AAAAAAAAAAAAAAA/AAAAAAAAAAAAAAC/AAAAAAAAgD8AAAA//3//f////7//f/9/////v/9//3////+//3//f////78AAP9//3//vwAA/3//f/+/AAD/f/9//78AAP9//3//vw==")
|
||||||
}]
|
}]
|
||||||
metadata/GodotVersion = "4.5-stable (official)"
|
metadata/GodotVersion = "4.6.2-stable (official)"
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="oggvorbisstr"
|
||||||
|
type="AudioStreamOggVorbis"
|
||||||
|
uid="uid://dgt3nox7yak72"
|
||||||
|
path="res://.godot/imported/pop.ogg-e15d202808be009bef5e04746dba8616.oggvorbisstr"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/pop.ogg"
|
||||||
|
dest_files=["res://.godot/imported/pop.ogg-e15d202808be009bef5e04746dba8616.oggvorbisstr"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
loop=false
|
||||||
|
loop_offset=0
|
||||||
|
bpm=0
|
||||||
|
beat_count=0
|
||||||
|
bar_beats=4
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://b2e0ls6ymw45i"
|
||||||
|
path="res://.godot/imported/car_brake.wav-359538a9b1ba4240ae07e54477629dbb.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/vehicles/car/car_brake.wav"
|
||||||
|
dest_files=["res://.godot/imported/car_brake.wav-359538a9b1ba4240ae07e54477629dbb.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=2
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://dlg100ft5f2jy"
|
||||||
|
path="res://.godot/imported/car_engine_accel_loop.wav-25b55bfc6e1d41b17513ac3dd914f463.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/vehicles/car/car_engine_accel_loop.wav"
|
||||||
|
dest_files=["res://.godot/imported/car_engine_accel_loop.wav-25b55bfc6e1d41b17513ac3dd914f463.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=1
|
||||||
|
edit/loop_begin=0
|
||||||
|
edit/loop_end=-1
|
||||||
|
compress/mode=2
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://cljhbkwcswalc"
|
||||||
|
path="res://.godot/imported/car_engine_drive_loop.wav-be0d54cca48b174deaff89a90d5364c3.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/vehicles/car/car_engine_drive_loop.wav"
|
||||||
|
dest_files=["res://.godot/imported/car_engine_drive_loop.wav-be0d54cca48b174deaff89a90d5364c3.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=1
|
||||||
|
edit/loop_begin=0
|
||||||
|
edit/loop_end=-1
|
||||||
|
compress/mode=2
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://c28v6t3txgn8w"
|
||||||
|
path="res://.godot/imported/car_engine_idle_loop.wav-56323a2fbc32742f6519b3630f97c275.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/vehicles/car/car_engine_idle_loop.wav"
|
||||||
|
dest_files=["res://.godot/imported/car_engine_idle_loop.wav-56323a2fbc32742f6519b3630f97c275.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=1
|
||||||
|
edit/loop_begin=0
|
||||||
|
edit/loop_end=-1
|
||||||
|
compress/mode=2
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://bhmyl3ie10u53"
|
||||||
|
path="res://.godot/imported/car_enter.wav-aeff3918a465be3f557bb484cf84ed62.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/vehicles/car/car_enter.wav"
|
||||||
|
dest_files=["res://.godot/imported/car_enter.wav-aeff3918a465be3f557bb484cf84ed62.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=2
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://bngm3s2yq2xwi"
|
||||||
|
path="res://.godot/imported/car_exit.wav-f78ac0b868ae38aeb13d15881f6c3491.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/vehicles/car/car_exit.wav"
|
||||||
|
dest_files=["res://.godot/imported/car_exit.wav-f78ac0b868ae38aeb13d15881f6c3491.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=2
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://bq2d35mekg4il"
|
||||||
|
path="res://.godot/imported/car_hit.wav-5f5ca7b335ab69bea356887a03a1eacc.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/vehicles/car/car_hit.wav"
|
||||||
|
dest_files=["res://.godot/imported/car_hit.wav-5f5ca7b335ab69bea356887a03a1eacc.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=2
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wav"
|
||||||
|
type="AudioStreamWAV"
|
||||||
|
uid="uid://y38ybkt3uxik"
|
||||||
|
path="res://.godot/imported/car_horn.wav-4f978ca1d198f5c6c4a5fcfab9ca1ccc.sample"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/audio/vehicles/car/car_horn.wav"
|
||||||
|
dest_files=["res://.godot/imported/car_horn.wav-4f978ca1d198f5c6c4a5fcfab9ca1ccc.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=2
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://bi13nqi11oqhx"
|
||||||
|
path="res://.godot/imported/AshlingSwarmer.glb-69896cc28ddf5352ad63aa98f43893d5.scn"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/models/AshlingSwarmer.glb"
|
||||||
|
dest_files=["res://.godot/imported/AshlingSwarmer.glb-69896cc28ddf5352ad63aa98f43893d5.scn"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/root_script=null
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=1.0
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
nodes/use_name_suffixes=true
|
||||||
|
nodes/use_node_type_suffixes=true
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=false
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=false
|
||||||
|
import_script/path=""
|
||||||
|
materials/extract=0
|
||||||
|
materials/extract_format=0
|
||||||
|
materials/extract_path=""
|
||||||
|
_subresources={}
|
||||||
|
gltf/naming_version=2
|
||||||
|
gltf/embedded_image_handling=1
|
||||||
@@ -48,6 +48,7 @@ blender/meshes/colors=false
|
|||||||
blender/meshes/uvs=true
|
blender/meshes/uvs=true
|
||||||
blender/meshes/normals=true
|
blender/meshes/normals=true
|
||||||
blender/meshes/export_geometry_nodes_instances=false
|
blender/meshes/export_geometry_nodes_instances=false
|
||||||
|
blender/meshes/gpu_instances=false
|
||||||
blender/meshes/tangents=true
|
blender/meshes/tangents=true
|
||||||
blender/meshes/skins=2
|
blender/meshes/skins=2
|
||||||
blender/meshes/export_bones_deforming_mesh_only=false
|
blender/meshes/export_bones_deforming_mesh_only=false
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
Copyright (c) 2023 Manik Sharma.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
Car Demo by Manik Sharma
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -3,13 +3,13 @@
|
|||||||
importer="scene"
|
importer="scene"
|
||||||
importer_version=1
|
importer_version=1
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://cpuebxqhtv72i"
|
uid="uid://civr7hlbf2kqb"
|
||||||
path="res://.godot/imported/humanFemale.glb-45dfb97e0f5fa98244d8cb6255565c65.scn"
|
path="res://.godot/imported/Wheel.glb-dddddd96691989c3e912750c9a47a858.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://assets/models/humanFemale.glb"
|
source_file="res://assets/models/vehicles/doge/Wheel.glb"
|
||||||
dest_files=["res://.godot/imported/humanFemale.glb-45dfb97e0f5fa98244d8cb6255565c65.scn"]
|
dest_files=["res://.godot/imported/Wheel.glb-dddddd96691989c3e912750c9a47a858.scn"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 2.0 MiB |
@@ -0,0 +1,44 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bpklxkc61avg6"
|
||||||
|
path.s3tc="res://.godot/imported/Wheel_RIMMUSCLE_01_DIF.png-5bb5174c5332f74f16abee062d1ed24a.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "cd5730d572d3e9053a526f83b6971226"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/models/vehicles/doge/Wheel_RIMMUSCLE_01_DIF.png"
|
||||||
|
dest_files=["res://.godot/imported/Wheel_RIMMUSCLE_01_DIF.png-5bb5174c5332f74f16abee062d1ed24a.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
|
||||||
|
After Width: | Height: | Size: 1.0 MiB |
@@ -0,0 +1,44 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://djs3o5hanxb70"
|
||||||
|
path.s3tc="res://.godot/imported/Wheel_RIMMUSCLE_01_MET-RIMMUSCLE_01_ROUGH.png-bf036ae2ba8ef4208853e0caa49ac9e7.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "ee91568e12f40d7fce962016fe4791c0"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/models/vehicles/doge/Wheel_RIMMUSCLE_01_MET-RIMMUSCLE_01_ROUGH.png"
|
||||||
|
dest_files=["res://.godot/imported/Wheel_RIMMUSCLE_01_MET-RIMMUSCLE_01_ROUGH.png-bf036ae2ba8ef4208853e0caa49ac9e7.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
|
||||||
|
After Width: | Height: | Size: 1.6 MiB |
@@ -0,0 +1,44 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cxufd33f0bqsx"
|
||||||
|
path.s3tc="res://.godot/imported/Wheel_RIMMUSCLE_01_NRM.png-3149169313dea5a53591f1b5ae2411f6.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "7d86721466688c1cd90634fe6d2f953a"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/models/vehicles/doge/Wheel_RIMMUSCLE_01_NRM.png"
|
||||||
|
dest_files=["res://.godot/imported/Wheel_RIMMUSCLE_01_NRM.png-3149169313dea5a53591f1b5ae2411f6.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=1
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=1
|
||||||
|
roughness/src_normal="res://assets/models/vehicles/doge/Wheel_RIMMUSCLE_01_NRM.png"
|
||||||
|
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
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://dvgiooankbnw3"
|
||||||
|
path="res://.godot/imported/doge-body.glb-d066dc7fd60eda6d05736bc65e3c5ffe.scn"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/models/vehicles/doge/doge-body.glb"
|
||||||
|
dest_files=["res://.godot/imported/doge-body.glb-d066dc7fd60eda6d05736bc65e3c5ffe.scn"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/root_script=null
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=1.0
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
nodes/use_name_suffixes=true
|
||||||
|
nodes/use_node_type_suffixes=true
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=false
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=false
|
||||||
|
import_script/path=""
|
||||||
|
materials/extract=0
|
||||||
|
materials/extract_format=0
|
||||||
|
materials/extract_path=""
|
||||||
|
_subresources={}
|
||||||
|
gltf/naming_version=2
|
||||||
|
gltf/embedded_image_handling=1
|
||||||
|
After Width: | Height: | Size: 2.1 MiB |
@@ -0,0 +1,44 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dx401inrlplo1"
|
||||||
|
path.s3tc="res://.godot/imported/doge-body_GEN4DR_INTERIOR_dif.png-b5a1b7fcdb7b3160f7a0ef7e265e4505.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "b3caf55dd0d9e1e05294308101435166"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/models/vehicles/doge/doge-body_GEN4DR_INTERIOR_dif.png"
|
||||||
|
dest_files=["res://.godot/imported/doge-body_GEN4DR_INTERIOR_dif.png-b5a1b7fcdb7b3160f7a0ef7e265e4505.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
|
||||||
|
After Width: | Height: | Size: 222 KiB |
@@ -0,0 +1,44 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://c63xvtkbodiob"
|
||||||
|
path.s3tc="res://.godot/imported/doge-body_GENERIC_BADGES_DIF.png-796b015ef1e73a8329f18564cd4000af.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "f8fce006f08ef57c4bb09b493a6126d8"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/models/vehicles/doge/doge-body_GENERIC_BADGES_DIF.png"
|
||||||
|
dest_files=["res://.godot/imported/doge-body_GENERIC_BADGES_DIF.png-796b015ef1e73a8329f18564cd4000af.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
|
||||||
|
After Width: | Height: | Size: 2.7 MiB |
@@ -0,0 +1,44 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://e5okom0atmrt"
|
||||||
|
path.s3tc="res://.godot/imported/doge-body_Numberplates_dif.png-c03cf9c73e5d679f02921a9bb6c29d63.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "da3da05f00d3caef6299f64ac091b52f"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/models/vehicles/doge/doge-body_Numberplates_dif.png"
|
||||||
|
dest_files=["res://.godot/imported/doge-body_Numberplates_dif.png-c03cf9c73e5d679f02921a9bb6c29d63.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
|
||||||
|
After Width: | Height: | Size: 942 KiB |
@@ -0,0 +1,44 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://2sf47hajdi3w"
|
||||||
|
path.s3tc="res://.godot/imported/doge-body_Riverside88_lights_dif.png-05ac8d7af58447f0ddebfe66c3707ac9.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "c3cf8ceff55bcc14da25561e2939d3be"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/models/vehicles/doge/doge-body_Riverside88_lights_dif.png"
|
||||||
|
dest_files=["res://.godot/imported/doge-body_Riverside88_lights_dif.png-05ac8d7af58447f0ddebfe66c3707ac9.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
|
||||||
|
After Width: | Height: | Size: 2.6 MiB |
@@ -0,0 +1,44 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://c83x8syn3olne"
|
||||||
|
path.s3tc="res://.godot/imported/doge-body_UCB_BOTTOM_DIF.png-cfc19977dbe1d864173f653d08cb0672.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "0eabb927a9e9ac2e0de40610dbadc3a6"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/models/vehicles/doge/doge-body_UCB_BOTTOM_DIF.png"
|
||||||
|
dest_files=["res://.godot/imported/doge-body_UCB_BOTTOM_DIF.png-cfc19977dbe1d864173f653d08cb0672.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
|
||||||
|
After Width: | Height: | Size: 3.4 MiB |
@@ -0,0 +1,44 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://crxpnsmfsorf5"
|
||||||
|
path.s3tc="res://.godot/imported/doge-body_UCB_BOTTOM_nrm.png-b5e3eff64de1f5b644e5d70c8b7bfe37.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "ce8201694c51a8565f01b6f7688262bf"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/models/vehicles/doge/doge-body_UCB_BOTTOM_nrm.png"
|
||||||
|
dest_files=["res://.godot/imported/doge-body_UCB_BOTTOM_nrm.png-b5e3eff64de1f5b644e5d70c8b7bfe37.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=1
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=1
|
||||||
|
roughness/src_normal="res://assets/models/vehicles/doge/doge-body_UCB_BOTTOM_nrm.png"
|
||||||
|
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
|
||||||
|
After Width: | Height: | Size: 52 KiB |
@@ -0,0 +1,44 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dxcjtnnch0sxr"
|
||||||
|
path.s3tc="res://.godot/imported/doge-body_UCB_GLASS_CLEAN_dif.png-423a718e8cd643fb68b5ef6cfd665641.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "f8a5958ba2b852aaf7e4733c7ca90a83"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/models/vehicles/doge/doge-body_UCB_GLASS_CLEAN_dif.png"
|
||||||
|
dest_files=["res://.godot/imported/doge-body_UCB_GLASS_CLEAN_dif.png-423a718e8cd643fb68b5ef6cfd665641.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
|
||||||
|
After Width: | Height: | Size: 399 B |
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bpcj2xno5aykg"
|
||||||
|
path="res://.godot/imported/ashling_swarmer_palette.png-c771be7c592755dce8c857fa3b76a603.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/textures/ashling_swarmer/ashling_swarmer_palette.png"
|
||||||
|
dest_files=["res://.godot/imported/ashling_swarmer_palette.png-c771be7c592755dce8c857fa3b76a603.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
|
||||||
@@ -40,7 +40,7 @@ compatibility/default_parent_skeleton_in_mesh_instance_3d=true
|
|||||||
|
|
||||||
config/name="Promiscuity"
|
config/name="Promiscuity"
|
||||||
run/main_scene="uid://b4k81taauef4q"
|
run/main_scene="uid://b4k81taauef4q"
|
||||||
config/features=PackedStringArray("4.5", "Forward Plus")
|
config/features=PackedStringArray("4.6", "Forward Plus")
|
||||||
config/icon="res://icon.svg"
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
[audio]
|
[audio]
|
||||||
@@ -56,6 +56,7 @@ CharacterService="*res://scenes/UI/character_service.gd"
|
|||||||
SelectedCharacter="*res://scenes/UI/selected_character.gd"
|
SelectedCharacter="*res://scenes/UI/selected_character.gd"
|
||||||
DialogSystem="*res://scenes/UI/dialog_system.gd"
|
DialogSystem="*res://scenes/UI/dialog_system.gd"
|
||||||
QuestManager="*res://scenes/Quests/quest_manager.gd"
|
QuestManager="*res://scenes/Quests/quest_manager.gd"
|
||||||
|
TeleportState="*res://scenes/Interaction/teleport_state.gd"
|
||||||
SimpleGrass="*res://addons/simplegrasstextured/singleton.tscn"
|
SimpleGrass="*res://addons/simplegrasstextured/singleton.tscn"
|
||||||
|
|
||||||
[dotnet]
|
[dotnet]
|
||||||
@@ -64,7 +65,7 @@ project/assembly_name="Promiscuity"
|
|||||||
|
|
||||||
[editor_plugins]
|
[editor_plugins]
|
||||||
|
|
||||||
enabled=PackedStringArray("res://addons/simplegrasstextured/plugin.cfg")
|
enabled=PackedStringArray("res://addons/godot_mcp/plugin.cfg", "res://addons/simplegrasstextured/plugin.cfg")
|
||||||
|
|
||||||
[input]
|
[input]
|
||||||
|
|
||||||
@@ -105,16 +106,31 @@ player_light={
|
|||||||
"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)
|
"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)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
player_fireball={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":66,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
player_phone={
|
player_phone={
|
||||||
"deadzone": 0.2,
|
"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":4194306,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
"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":4194306,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
player_toggle_perspective={
|
||||||
|
"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":86,"key_label":0,"unicode":118,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
interact={
|
interact={
|
||||||
"deadzone": 0.2,
|
"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":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null)
|
"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":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
OpenRadialCommandMenu={
|
||||||
|
"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":81,"key_label":0,"unicode":113,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
[shader_globals]
|
[shader_globals]
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@export var model_path: NodePath = NodePath("AshlingSwarmerModel")
|
||||||
|
@export var default_animation: StringName = &"Idle"
|
||||||
|
@export var autoplay: bool = true
|
||||||
|
|
||||||
|
var _animation_player: AnimationPlayer
|
||||||
|
var _model_node: Node3D
|
||||||
|
var _current_animation: StringName = &""
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
call_deferred("_setup_animation")
|
||||||
|
|
||||||
|
|
||||||
|
func _setup_animation() -> void:
|
||||||
|
_model_node = get_node_or_null(model_path) as Node3D
|
||||||
|
_animation_player = _find_animation_player(_model_node)
|
||||||
|
if _animation_player == null:
|
||||||
|
if autoplay:
|
||||||
|
push_warning("AshlingSwarmer: no AnimationPlayer found under %s." % model_path)
|
||||||
|
return
|
||||||
|
if autoplay:
|
||||||
|
play_animation(default_animation)
|
||||||
|
|
||||||
|
|
||||||
|
func play_animation(animation_name: StringName = &"") -> void:
|
||||||
|
if _animation_player == null:
|
||||||
|
_animation_player = _find_animation_player(get_node_or_null(model_path))
|
||||||
|
if _animation_player == null:
|
||||||
|
return
|
||||||
|
var requested_animation := animation_name if animation_name != StringName() else default_animation
|
||||||
|
var resolved_animation := _resolve_animation_name(requested_animation)
|
||||||
|
if resolved_animation == StringName():
|
||||||
|
push_warning("AshlingSwarmer: animation '%s' not found. Available animations: %s" % [requested_animation, _animation_player.get_animation_list()])
|
||||||
|
return
|
||||||
|
var animation := _animation_player.get_animation(resolved_animation)
|
||||||
|
if animation != null:
|
||||||
|
animation.loop_mode = Animation.LOOP_LINEAR
|
||||||
|
_animation_player.play(resolved_animation)
|
||||||
|
_current_animation = _classify_animation(resolved_animation)
|
||||||
|
|
||||||
|
|
||||||
|
func play_idle() -> void:
|
||||||
|
play_animation(&"Idle")
|
||||||
|
|
||||||
|
|
||||||
|
func play_run() -> void:
|
||||||
|
play_animation(&"Run")
|
||||||
|
|
||||||
|
|
||||||
|
func play_attack() -> void:
|
||||||
|
play_animation(&"Attack_Leap")
|
||||||
|
|
||||||
|
|
||||||
|
func play_hit() -> void:
|
||||||
|
play_animation(&"Hit")
|
||||||
|
|
||||||
|
|
||||||
|
func play_death() -> void:
|
||||||
|
play_animation(&"Death_Explode")
|
||||||
|
|
||||||
|
|
||||||
|
func _resolve_animation_name(animation_name: StringName) -> StringName:
|
||||||
|
if _animation_player.has_animation(animation_name):
|
||||||
|
return animation_name
|
||||||
|
var desired := String(animation_name).to_lower()
|
||||||
|
for candidate in _animation_player.get_animation_list():
|
||||||
|
var candidate_text := String(candidate)
|
||||||
|
if candidate_text.to_lower() == desired:
|
||||||
|
return StringName(candidate)
|
||||||
|
for candidate in _animation_player.get_animation_list():
|
||||||
|
var candidate_text := String(candidate)
|
||||||
|
if candidate_text.to_lower().contains(desired):
|
||||||
|
return StringName(candidate)
|
||||||
|
for candidate in _animation_player.get_animation_list():
|
||||||
|
var candidate_text := String(candidate)
|
||||||
|
if candidate_text.to_lower().contains("idle"):
|
||||||
|
return StringName(candidate)
|
||||||
|
var animations := _animation_player.get_animation_list()
|
||||||
|
if animations.size() > 0:
|
||||||
|
return StringName(animations[0])
|
||||||
|
return StringName()
|
||||||
|
|
||||||
|
|
||||||
|
func _classify_animation(animation_name: StringName) -> StringName:
|
||||||
|
var text := String(animation_name).to_lower()
|
||||||
|
if text.contains("run"):
|
||||||
|
return &"Run"
|
||||||
|
if text.contains("idle"):
|
||||||
|
return &"Idle"
|
||||||
|
if text.contains("attack"):
|
||||||
|
return &"Attack_Leap"
|
||||||
|
if text.contains("hit"):
|
||||||
|
return &"Hit"
|
||||||
|
if text.contains("death"):
|
||||||
|
return &"Death_Explode"
|
||||||
|
return animation_name
|
||||||
|
|
||||||
|
|
||||||
|
func _find_animation_player(root: Node) -> AnimationPlayer:
|
||||||
|
if root == null:
|
||||||
|
return null
|
||||||
|
if root is AnimationPlayer:
|
||||||
|
return root
|
||||||
|
for child in root.get_children():
|
||||||
|
var found := _find_animation_player(child)
|
||||||
|
if found != null:
|
||||||
|
return found
|
||||||
|
return null
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dptxcarifu7e1
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
[gd_scene load_steps=5 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scenes/Characters/ashling_swarmer.gd" id="1_script"]
|
||||||
|
[ext_resource type="PackedScene" path="res://assets/models/AshlingSwarmer.glb" id="2_model"]
|
||||||
|
[ext_resource type="Script" path="res://scenes/Interaction/dialog_trigger_area.gd" id="3_dialog"]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_body"]
|
||||||
|
radius = 0.45
|
||||||
|
height = 1.6
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_interact"]
|
||||||
|
radius = 1.8
|
||||||
|
|
||||||
|
[node name="AshlingSwarmer" type="Node3D"]
|
||||||
|
script = ExtResource("1_script")
|
||||||
|
autoplay = false
|
||||||
|
|
||||||
|
[node name="Body" type="StaticBody3D" parent="."]
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Body"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.8, 0)
|
||||||
|
shape = SubResource("CapsuleShape3D_body")
|
||||||
|
|
||||||
|
[node name="AshlingSwarmerModel" parent="." instance=ExtResource("2_model")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
||||||
|
|
||||||
|
[node name="InteractArea" type="Area3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.8, 0)
|
||||||
|
script = ExtResource("3_dialog")
|
||||||
|
collision_layer = 2
|
||||||
|
collision_mask = 1
|
||||||
|
prompt_text = "Press E to inspect"
|
||||||
|
dialog_text = "Ashling Swarmer: A small ember-born creature watches you."
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="InteractArea"]
|
||||||
|
shape = SubResource("SphereShape3D_interact")
|
||||||
@@ -1,249 +0,0 @@
|
|||||||
extends RigidBody3D
|
|
||||||
# Initially I used a CharacterBody3D, however, I wanted the player to bounce off
|
|
||||||
# other objects in the environment and that would have required manual handling
|
|
||||||
# of collisions. So that's why we're using a RigidBody3D instead.
|
|
||||||
signal vehicle_entered(vehicle: Node)
|
|
||||||
signal vehicle_exited(vehicle: Node)
|
|
||||||
|
|
||||||
const MOVE_SPEED := 8.0
|
|
||||||
const SPRINT_MOVE_SPEED :=13
|
|
||||||
const ACCELLERATION := 30.0
|
|
||||||
const DECELLERATION := 40.0
|
|
||||||
const JUMP_SPEED := 4.0
|
|
||||||
const MAX_NUMBER_OF_JUMPS := 2
|
|
||||||
const MIN_FOV := 10.0
|
|
||||||
const MAX_FOV := 179.0
|
|
||||||
const ZOOM_FACTOR := 1.1 # Zoom out when >1, in when < 1
|
|
||||||
var mouse_sensitivity := 0.005
|
|
||||||
var rotation_x := 0.0
|
|
||||||
var rotation_y := 0.0
|
|
||||||
var cameraMoveMode := false
|
|
||||||
var current_number_of_jumps := 0
|
|
||||||
var _pending_mouse_delta := Vector2.ZERO
|
|
||||||
var _last_move_forward := Vector3(0, 0, 1)
|
|
||||||
var _last_move_right := Vector3(1, 0, 0)
|
|
||||||
var _camera_offset_local := Vector3.ZERO
|
|
||||||
var _camera_yaw := 0.0
|
|
||||||
var _camera_pitch := 0.0
|
|
||||||
var _in_vehicle := false
|
|
||||||
var _vehicle_collision_layer := 0
|
|
||||||
var _vehicle_collision_mask := 0
|
|
||||||
var _vehicle_original_parent: Node = null
|
|
||||||
var _light_was_on := false
|
|
||||||
var _jump_triggered := false
|
|
||||||
@onready var _flashlight: SpotLight3D = $SpotLight3D
|
|
||||||
@onready var _anim_player: AnimationPlayer = find_child("AnimationPlayer", true, false) as AnimationPlayer
|
|
||||||
@onready var _anim_tree: AnimationTree = find_child("AnimationTree", true, false) as AnimationTree
|
|
||||||
@onready var _model_root: Node3D = find_child("TestCharAnimated", true, false) as Node3D
|
|
||||||
|
|
||||||
@export var camera_follow_speed := 10.0
|
|
||||||
@export var anim_idle_name := "Idle"
|
|
||||||
@export var anim_walk_name := "Walk"
|
|
||||||
@export var anim_jump_name := "Jump"
|
|
||||||
@export var anim_run_name := "Run"
|
|
||||||
@export var anim_walk_speed_threshold := 0.25
|
|
||||||
@export var anim_sprint_speed_threshold := 10.0
|
|
||||||
|
|
||||||
var jump_sound = preload("res://assets/audio/jump.ogg")
|
|
||||||
var audio_player = AudioStreamPlayer.new()
|
|
||||||
|
|
||||||
@export var camera_path: NodePath
|
|
||||||
@onready var cam: Camera3D = get_node(camera_path) if camera_path != NodePath("") else null
|
|
||||||
@export var phone_path: NodePath
|
|
||||||
@onready var phone: CanvasLayer = get_node(phone_path) if phone_path != NodePath("") else null
|
|
||||||
var phone_visible := false
|
|
||||||
|
|
||||||
func _ready() -> void:
|
|
||||||
add_to_group("player")
|
|
||||||
if _anim_tree:
|
|
||||||
_anim_tree.active = false
|
|
||||||
axis_lock_angular_x = true
|
|
||||||
axis_lock_angular_z = true
|
|
||||||
angular_damp = 6.0
|
|
||||||
contact_monitor = true
|
|
||||||
max_contacts_reported = 4
|
|
||||||
add_child(audio_player)
|
|
||||||
audio_player.stream = jump_sound
|
|
||||||
audio_player.volume_db = -20
|
|
||||||
if cam:
|
|
||||||
_camera_offset_local = cam.transform.origin
|
|
||||||
_camera_pitch = cam.rotation.x
|
|
||||||
_camera_yaw = global_transform.basis.get_euler().y
|
|
||||||
cam.set_as_top_level(true)
|
|
||||||
cam.global_position = global_position + (Basis(Vector3.UP, _camera_yaw) * _camera_offset_local)
|
|
||||||
cam.global_rotation = Vector3(_camera_pitch, _camera_yaw, 0.0)
|
|
||||||
var move_basis := cam.global_transform.basis if cam else global_transform.basis
|
|
||||||
var forward := move_basis.z
|
|
||||||
var right := move_basis.x
|
|
||||||
forward.y = 0.0
|
|
||||||
right.y = 0.0
|
|
||||||
if forward.length() > 0.0001:
|
|
||||||
_last_move_forward = forward.normalized()
|
|
||||||
if right.length() > 0.0001:
|
|
||||||
_last_move_right = right.normalized()
|
|
||||||
_vehicle_collision_layer = collision_layer
|
|
||||||
_vehicle_collision_mask = collision_mask
|
|
||||||
|
|
||||||
func _integrate_forces(state):
|
|
||||||
if _in_vehicle:
|
|
||||||
linear_velocity = Vector3.ZERO
|
|
||||||
return
|
|
||||||
if cameraMoveMode and _pending_mouse_delta != Vector2.ZERO:
|
|
||||||
rotation_x -= _pending_mouse_delta.y * mouse_sensitivity
|
|
||||||
rotation_y -= _pending_mouse_delta.x * mouse_sensitivity
|
|
||||||
rotation_x = clamp(rotation_x, deg_to_rad(-90), deg_to_rad(90))
|
|
||||||
_camera_pitch = rotation_x
|
|
||||||
rotation.y = rotation_y
|
|
||||||
_pending_mouse_delta = Vector2.ZERO
|
|
||||||
|
|
||||||
var input2v := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
|
|
||||||
var forward := Vector3.FORWARD * -1.0
|
|
||||||
var right := Vector3.RIGHT
|
|
||||||
if cam:
|
|
||||||
forward = cam.global_transform.basis.z
|
|
||||||
right = cam.global_transform.basis.x
|
|
||||||
forward.y = 0.0
|
|
||||||
right.y = 0.0
|
|
||||||
if forward.length() > 0.0001:
|
|
||||||
forward = forward.normalized()
|
|
||||||
_last_move_forward = forward
|
|
||||||
else:
|
|
||||||
forward = _last_move_forward
|
|
||||||
if right.length() > 0.0001:
|
|
||||||
right = right.normalized()
|
|
||||||
_last_move_right = right
|
|
||||||
else:
|
|
||||||
right = _last_move_right
|
|
||||||
|
|
||||||
var dir := (right * input2v.x + forward * input2v.y).normalized()
|
|
||||||
var target_v := dir * MOVE_SPEED
|
|
||||||
if Input.is_key_pressed(KEY_SHIFT):
|
|
||||||
target_v = dir * SPRINT_MOVE_SPEED
|
|
||||||
|
|
||||||
var ax := ACCELLERATION if dir != Vector3.ZERO else DECELLERATION
|
|
||||||
linear_velocity.x = move_toward(linear_velocity.x, target_v.x, ax * state.step)
|
|
||||||
linear_velocity.z = move_toward(linear_velocity.z, target_v.z, ax * state.step)
|
|
||||||
|
|
||||||
var on_floor = false
|
|
||||||
for i in state.get_contact_count():
|
|
||||||
var normal = state.get_contact_local_normal(i)
|
|
||||||
if normal.y > 0.5:
|
|
||||||
on_floor = true
|
|
||||||
break
|
|
||||||
|
|
||||||
if Input.is_action_just_pressed("ui_accept") and (on_floor or current_number_of_jumps == 1):
|
|
||||||
current_number_of_jumps = (current_number_of_jumps + 1) % 2
|
|
||||||
linear_velocity.y = JUMP_SPEED
|
|
||||||
audio_player.play()
|
|
||||||
_jump_triggered = true
|
|
||||||
|
|
||||||
if cam:
|
|
||||||
var target_yaw := global_transform.basis.get_euler().y
|
|
||||||
_camera_yaw = lerp_angle(_camera_yaw, target_yaw, camera_follow_speed * state.step)
|
|
||||||
var target_basis := Basis(Vector3.UP, _camera_yaw)
|
|
||||||
var target_pos := global_position + (target_basis * _camera_offset_local)
|
|
||||||
cam.global_position = cam.global_position.lerp(target_pos, camera_follow_speed * state.step)
|
|
||||||
cam.global_rotation = Vector3(_camera_pitch, _camera_yaw, 0.0)
|
|
||||||
|
|
||||||
_update_animation(on_floor, state.linear_velocity)
|
|
||||||
_jump_triggered = false
|
|
||||||
|
|
||||||
func _input(event):
|
|
||||||
if event.is_action_pressed("player_phone"):
|
|
||||||
phone_visible = !phone_visible
|
|
||||||
if phone:
|
|
||||||
phone.visible = phone_visible
|
|
||||||
return
|
|
||||||
|
|
||||||
if _in_vehicle:
|
|
||||||
return
|
|
||||||
if event is InputEventMouseButton:
|
|
||||||
if event.button_index == MOUSE_BUTTON_MIDDLE:
|
|
||||||
if event.pressed:
|
|
||||||
cameraMoveMode = true
|
|
||||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
|
||||||
else:
|
|
||||||
cameraMoveMode = false
|
|
||||||
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
|
||||||
|
|
||||||
if event is InputEventMouseMotion and cameraMoveMode:
|
|
||||||
_pending_mouse_delta += event.relative
|
|
||||||
|
|
||||||
if event is InputEventMouseButton and event.pressed:
|
|
||||||
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
|
|
||||||
zoom_camera(1.0 / ZOOM_FACTOR)
|
|
||||||
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
|
||||||
zoom_camera(ZOOM_FACTOR)
|
|
||||||
|
|
||||||
if event.is_action_pressed("player_light"):
|
|
||||||
_flashlight.visible = !_flashlight.visible
|
|
||||||
|
|
||||||
func zoom_camera(factor):
|
|
||||||
if cam == null:
|
|
||||||
return
|
|
||||||
var new_fov = cam.fov * factor
|
|
||||||
cam.fov = clamp(new_fov, MIN_FOV, MAX_FOV)
|
|
||||||
|
|
||||||
func _update_animation(on_floor: bool, velocity: Vector3) -> void:
|
|
||||||
if _anim_player == null:
|
|
||||||
return
|
|
||||||
var horizontal_speed := Vector3(velocity.x, 0.0, velocity.z).length()
|
|
||||||
if _jump_triggered and _anim_player.has_animation(anim_jump_name):
|
|
||||||
if _anim_player.current_animation != anim_jump_name:
|
|
||||||
_anim_player.play(anim_jump_name)
|
|
||||||
return
|
|
||||||
if not on_floor and _anim_player.has_animation(anim_jump_name):
|
|
||||||
if _anim_player.current_animation != anim_jump_name:
|
|
||||||
_anim_player.play(anim_jump_name)
|
|
||||||
return
|
|
||||||
if on_floor and horizontal_speed > anim_sprint_speed_threshold and _anim_player.has_animation(anim_run_name):
|
|
||||||
if _anim_player.current_animation != anim_run_name:
|
|
||||||
_anim_player.play(anim_run_name)
|
|
||||||
return
|
|
||||||
if horizontal_speed > anim_walk_speed_threshold and _anim_player.has_animation(anim_walk_name):
|
|
||||||
if _anim_player.current_animation != anim_walk_name:
|
|
||||||
_anim_player.play(anim_walk_name)
|
|
||||||
return
|
|
||||||
if _anim_player.has_animation(anim_idle_name):
|
|
||||||
if _anim_player.current_animation != anim_idle_name:
|
|
||||||
_anim_player.play(anim_idle_name)
|
|
||||||
|
|
||||||
func enter_vehicle(_vehicle: Node, seat: Node3D, vehicle_camera: Camera3D) -> void:
|
|
||||||
_in_vehicle = true
|
|
||||||
freeze = true
|
|
||||||
sleeping = true
|
|
||||||
collision_layer = 0
|
|
||||||
collision_mask = 0
|
|
||||||
_vehicle_original_parent = get_parent()
|
|
||||||
_light_was_on = _flashlight.visible
|
|
||||||
_flashlight.visible = false
|
|
||||||
if _model_root:
|
|
||||||
_model_root.visible = false
|
|
||||||
if seat:
|
|
||||||
reparent(seat, true)
|
|
||||||
global_transform = seat.global_transform
|
|
||||||
if cam:
|
|
||||||
cam.current = false
|
|
||||||
if vehicle_camera:
|
|
||||||
vehicle_camera.current = true
|
|
||||||
vehicle_entered.emit(_vehicle)
|
|
||||||
|
|
||||||
func exit_vehicle(exit_point: Node3D, vehicle_camera: Camera3D) -> void:
|
|
||||||
_in_vehicle = false
|
|
||||||
freeze = false
|
|
||||||
sleeping = false
|
|
||||||
collision_layer = _vehicle_collision_layer
|
|
||||||
collision_mask = _vehicle_collision_mask
|
|
||||||
if _vehicle_original_parent:
|
|
||||||
reparent(_vehicle_original_parent, true)
|
|
||||||
_vehicle_original_parent = null
|
|
||||||
_flashlight.visible = _light_was_on
|
|
||||||
if _model_root:
|
|
||||||
_model_root.visible = true
|
|
||||||
if exit_point:
|
|
||||||
global_transform = exit_point.global_transform
|
|
||||||
if vehicle_camera:
|
|
||||||
vehicle_camera.current = false
|
|
||||||
if cam:
|
|
||||||
cam.current = true
|
|
||||||
vehicle_exited.emit(null)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
uid://kgqaeqappow3
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[gd_scene load_steps=4 format=3]
|
[gd_scene load_steps=4 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scenes/Characters/location_player.gd" id="1_player_script"]
|
[ext_resource type="Script" path="res://scenes/player.gd" id="1_player_script"]
|
||||||
[ext_resource type="PackedScene" path="res://assets/models/TestCharAnimated.glb" id="2_model"]
|
[ext_resource type="PackedScene" path="res://assets/models/TestCharAnimated.glb" id="2_model"]
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_player"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_player"]
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
@export var radius: float = 150.0
|
||||||
|
@export var transition_speed: float = 0.2
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
hide() # Start hidden
|
||||||
|
_arrange_buttons()
|
||||||
|
|
||||||
|
func _input(event):
|
||||||
|
if event.is_action_pressed("OpenRadialCommandMenu"): # Map 'Q' to "open_menu" in Input Map
|
||||||
|
_toggle_menu()
|
||||||
|
|
||||||
|
func _toggle_menu():
|
||||||
|
visible = !visible
|
||||||
|
if visible:
|
||||||
|
# Center the menu on the mouse or screen
|
||||||
|
global_position = get_viewport().get_mouse_position()
|
||||||
|
_animate_menu(true)
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
||||||
|
else:
|
||||||
|
_animate_menu(false)
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||||
|
|
||||||
|
func _arrange_buttons():
|
||||||
|
var buttons = get_children().filter(func(child): return child is Control)
|
||||||
|
var count = buttons.size()
|
||||||
|
if count == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
for i in range(count):
|
||||||
|
# Calculate the angle for each button in radians
|
||||||
|
var angle = i * (2 * PI / count)
|
||||||
|
|
||||||
|
# Standard circle math: x = cos(a) * r, y = sin(a) * r
|
||||||
|
var target_pos = Vector2(cos(angle), sin(angle)) * radius
|
||||||
|
|
||||||
|
# Offset by button size to keep them centered
|
||||||
|
buttons[i].position = target_pos - (buttons[i].size / 2)
|
||||||
|
|
||||||
|
func _animate_menu(opening: bool):
|
||||||
|
var tween = create_tween().set_parallel(true)
|
||||||
|
for button in get_children().filter(func(child): return child is Control):
|
||||||
|
var final_scale = Vector2.ONE if opening else Vector2.ZERO
|
||||||
|
tween.tween_property(button, "scale", final_scale, transition_speed).from(Vector2.ZERO if opening else Vector2.ONE)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_btn_follow_pressed() -> void:
|
||||||
|
print("Follow command pressed")
|
||||||
|
_toggle_menu() # Closes the menu after clicking
|
||||||
|
|
||||||
|
|
||||||
|
func _on_btn_go_to_pressed() -> void:
|
||||||
|
print("Go to command pressed")
|
||||||
|
_toggle_menu() # Closes the menu after clicking
|
||||||
|
|
||||||
|
|
||||||
|
func _on_btn_attack_pressed() -> void:
|
||||||
|
print("Attack command pressed")
|
||||||
|
_toggle_menu() # Closes the menu after clicking
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cjfhlslc5vp7b
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
[gd_scene format=3 uid="uid://bnwpu7p8sbsfa"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://cjfhlslc5vp7b" path="res://scenes/Interaction/RadialCommandMenu.gd" id="1_j0xof"]
|
||||||
|
|
||||||
|
[node name="RadialCommandCanvas" type="CanvasLayer" unique_id=1002896311]
|
||||||
|
|
||||||
|
[node name="PivotControl" type="Control" parent="." unique_id=374070149]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -20.0
|
||||||
|
offset_top = -20.0
|
||||||
|
offset_right = 20.0
|
||||||
|
offset_bottom = 20.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_j0xof")
|
||||||
|
|
||||||
|
[node name="BtnFollow" type="Button" parent="PivotControl" unique_id=1839549428]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_right = 8.0
|
||||||
|
offset_bottom = 8.0
|
||||||
|
text = "Follow"
|
||||||
|
|
||||||
|
[node name="BtnGoTo" type="Button" parent="PivotControl" unique_id=818273339]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_right = 8.0
|
||||||
|
offset_bottom = 8.0
|
||||||
|
text = "Go To"
|
||||||
|
|
||||||
|
[node name="BtnAttack" type="Button" parent="PivotControl" unique_id=744805255]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_right = 8.0
|
||||||
|
offset_bottom = 8.0
|
||||||
|
text = "Attack"
|
||||||
|
|
||||||
|
[connection signal="pressed" from="PivotControl/BtnFollow" to="PivotControl" method="_on_btn_follow_pressed"]
|
||||||
|
[connection signal="pressed" from="PivotControl/BtnGoTo" to="PivotControl" method="_on_btn_go_to_pressed"]
|
||||||
|
[connection signal="pressed" from="PivotControl/BtnAttack" to="PivotControl" method="_on_btn_attack_pressed"]
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@export var spread_radius := 2.0
|
||||||
|
@export var spread_interval_min := 5.0
|
||||||
|
@export var spread_interval_max := 15.0
|
||||||
|
@export var max_mushrooms_in_radius := 3
|
||||||
|
@export var check_radius := 1.5
|
||||||
|
@export var max_total_mushrooms := 50
|
||||||
|
@export var interact_radius := 2.0
|
||||||
|
@export var look_at_threshold := 0.95
|
||||||
|
|
||||||
|
static var total_mushrooms := 0
|
||||||
|
|
||||||
|
@onready var spread_timer: Timer = $SpreadTimer
|
||||||
|
@onready var ground_ray: RayCast3D = $GroundRay
|
||||||
|
@onready var cap: MeshInstance3D = $Cap
|
||||||
|
@onready var stem: MeshInstance3D = $Stem
|
||||||
|
|
||||||
|
var _player_in_range := false
|
||||||
|
var _is_highlighted := false
|
||||||
|
var highlight_mat: StandardMaterial3D
|
||||||
|
var _audio_player: AudioStreamPlayer3D
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
total_mushrooms += 1
|
||||||
|
_setup_timer()
|
||||||
|
|
||||||
|
# Randomize initial scale for variety
|
||||||
|
scale = Vector3.ONE * randf_range(0.8, 1.2)
|
||||||
|
rotation.y = randf_range(0, TAU)
|
||||||
|
|
||||||
|
# Setup interaction area
|
||||||
|
var area = Area3D.new()
|
||||||
|
add_child(area)
|
||||||
|
var shape = CollisionShape3D.new()
|
||||||
|
var sphere = SphereShape3D.new()
|
||||||
|
sphere.radius = interact_radius
|
||||||
|
shape.shape = sphere
|
||||||
|
area.add_child(shape)
|
||||||
|
|
||||||
|
area.body_entered.connect(_on_body_entered)
|
||||||
|
area.body_exited.connect(_on_body_exited)
|
||||||
|
|
||||||
|
highlight_mat = StandardMaterial3D.new()
|
||||||
|
highlight_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
||||||
|
highlight_mat.albedo_color = Color(1.0, 1.0, 1.0, 0.3)
|
||||||
|
highlight_mat.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||||
|
|
||||||
|
_audio_player = AudioStreamPlayer3D.new()
|
||||||
|
_audio_player.stream = preload("res://assets/audio/pop.ogg")
|
||||||
|
add_child(_audio_player)
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
if not _player_in_range:
|
||||||
|
_set_highlight(false)
|
||||||
|
return
|
||||||
|
|
||||||
|
var cam = get_viewport().get_camera_3d()
|
||||||
|
if not cam:
|
||||||
|
_set_highlight(false)
|
||||||
|
return
|
||||||
|
|
||||||
|
var dir_to_mushroom = (global_position - cam.global_position).normalized()
|
||||||
|
var forward = -cam.global_transform.basis.z
|
||||||
|
var my_dot = forward.dot(dir_to_mushroom)
|
||||||
|
|
||||||
|
if my_dot > look_at_threshold:
|
||||||
|
# Check if we are the most directly looked-at mushroom in range
|
||||||
|
var is_best = true
|
||||||
|
for mushroom in get_tree().get_nodes_in_group("mushrooms"):
|
||||||
|
if mushroom == self or not mushroom.get("_player_in_range"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
var m_dir = (mushroom.global_position - cam.global_position).normalized()
|
||||||
|
var m_dot = forward.dot(m_dir)
|
||||||
|
|
||||||
|
if m_dot > my_dot:
|
||||||
|
is_best = false
|
||||||
|
break
|
||||||
|
elif m_dot == my_dot and mushroom.get_instance_id() > get_instance_id():
|
||||||
|
# Tie breaker
|
||||||
|
is_best = false
|
||||||
|
break
|
||||||
|
|
||||||
|
_set_highlight(is_best)
|
||||||
|
else:
|
||||||
|
_set_highlight(false)
|
||||||
|
|
||||||
|
func _set_highlight(value: bool) -> void:
|
||||||
|
if _is_highlighted == value: return
|
||||||
|
_is_highlighted = value
|
||||||
|
|
||||||
|
if value:
|
||||||
|
if cap: cap.material_overlay = highlight_mat
|
||||||
|
if stem: stem.material_overlay = highlight_mat
|
||||||
|
else:
|
||||||
|
if cap: cap.material_overlay = null
|
||||||
|
if stem: stem.material_overlay = null
|
||||||
|
|
||||||
|
func _on_body_entered(body: Node3D) -> void:
|
||||||
|
if body.is_in_group("player"):
|
||||||
|
_player_in_range = true
|
||||||
|
|
||||||
|
func _on_body_exited(body: Node3D) -> void:
|
||||||
|
if body.is_in_group("player"):
|
||||||
|
_player_in_range = false
|
||||||
|
_set_highlight(false)
|
||||||
|
|
||||||
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
if _is_highlighted and event.is_action_pressed("interact"):
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
_collect_mushroom()
|
||||||
|
|
||||||
|
func _collect_mushroom() -> void:
|
||||||
|
# Disable interaction and visuals
|
||||||
|
_is_highlighted = false
|
||||||
|
_set_highlight(false)
|
||||||
|
_player_in_range = false
|
||||||
|
|
||||||
|
if cap: cap.visible = false
|
||||||
|
if stem: stem.visible = false
|
||||||
|
|
||||||
|
# Stop spreading logic
|
||||||
|
spread_timer.stop()
|
||||||
|
|
||||||
|
# Disable processing so it can't be interacted with again
|
||||||
|
set_process_unhandled_input(false)
|
||||||
|
set_process(false)
|
||||||
|
|
||||||
|
# Play sound
|
||||||
|
_audio_player.play()
|
||||||
|
|
||||||
|
# Wait for sound to finish, then free
|
||||||
|
await _audio_player.finished
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
func _setup_timer() -> void:
|
||||||
|
spread_timer.wait_time = randf_range(spread_interval_min, spread_interval_max)
|
||||||
|
spread_timer.start()
|
||||||
|
|
||||||
|
func _on_spread_timer_timeout() -> void:
|
||||||
|
if total_mushrooms >= max_total_mushrooms:
|
||||||
|
return
|
||||||
|
|
||||||
|
if _count_nearby_mushrooms() >= max_mushrooms_in_radius:
|
||||||
|
# Too crowded, try again later
|
||||||
|
_setup_timer()
|
||||||
|
return
|
||||||
|
|
||||||
|
_attempt_spread()
|
||||||
|
_setup_timer()
|
||||||
|
|
||||||
|
func _attempt_spread() -> void:
|
||||||
|
var random_angle := randf_range(0, TAU)
|
||||||
|
var random_dist := randf_range(spread_radius * 0.5, spread_radius)
|
||||||
|
var offset := Vector3(cos(random_angle) * random_dist, 5.0, sin(random_angle) * random_dist)
|
||||||
|
|
||||||
|
ground_ray.position = offset
|
||||||
|
ground_ray.force_raycast_update()
|
||||||
|
|
||||||
|
if ground_ray.is_colliding():
|
||||||
|
var collision_point := ground_ray.get_collision_point()
|
||||||
|
var collision_normal := ground_ray.get_collision_normal()
|
||||||
|
|
||||||
|
# Only spread on relatively flat surfaces
|
||||||
|
if collision_normal.dot(Vector3.UP) > 0.7:
|
||||||
|
_spawn_mushroom(collision_point)
|
||||||
|
|
||||||
|
func _spawn_mushroom(pos: Vector3) -> void:
|
||||||
|
var mushroom_scene = load(scene_file_path)
|
||||||
|
var new_mushroom = mushroom_scene.instantiate()
|
||||||
|
get_parent().add_child(new_mushroom)
|
||||||
|
new_mushroom.global_position = pos
|
||||||
|
|
||||||
|
# Visual feedback/animation
|
||||||
|
new_mushroom.scale = Vector3.ZERO
|
||||||
|
var tween = create_tween()
|
||||||
|
tween.tween_property(new_mushroom, "scale", Vector3.ONE * randf_range(0.8, 1.2), 1.0).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT)
|
||||||
|
|
||||||
|
func _count_nearby_mushrooms() -> int:
|
||||||
|
var count := 0
|
||||||
|
for mushroom in get_tree().get_nodes_in_group("mushrooms"):
|
||||||
|
if mushroom == self: continue
|
||||||
|
if global_position.distance_to(mushroom.global_position) < check_radius:
|
||||||
|
count += 1
|
||||||
|
return count
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
total_mushrooms -= 1
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://brtwt4rp650ao
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
[gd_scene load_steps=6 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scenes/Interaction/mushroom.gd" id="1_m1s2h"]
|
||||||
|
|
||||||
|
[sub_resource type="CylinderMesh" id="CylinderMesh_stem"]
|
||||||
|
top_radius = 0.05
|
||||||
|
bottom_radius = 0.05
|
||||||
|
height = 0.15
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_stem"]
|
||||||
|
albedo_color = Color(0.9, 0.85, 0.7, 1)
|
||||||
|
|
||||||
|
[sub_resource type="SphereMesh" id="SphereMesh_cap"]
|
||||||
|
radius = 0.15
|
||||||
|
height = 0.1
|
||||||
|
is_hemisphere = true
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_cap"]
|
||||||
|
albedo_color = Color(0.8, 0.2, 0.2, 1)
|
||||||
|
|
||||||
|
[node name="Mushroom" type="Node3D" groups=["mushrooms"]]
|
||||||
|
script = ExtResource("1_m1s2h")
|
||||||
|
|
||||||
|
[node name="Stem" type="MeshInstance3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.075, 0)
|
||||||
|
mesh = SubResource("CylinderMesh_stem")
|
||||||
|
surface_material_override/0 = SubResource("StandardMaterial3D_stem")
|
||||||
|
|
||||||
|
[node name="Cap" type="MeshInstance3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.15, 0)
|
||||||
|
mesh = SubResource("SphereMesh_cap")
|
||||||
|
surface_material_override/0 = SubResource("StandardMaterial3D_cap")
|
||||||
|
|
||||||
|
[node name="SpreadTimer" type="Timer" parent="."]
|
||||||
|
one_shot = true
|
||||||
|
|
||||||
|
[node name="GroundRay" type="RayCast3D" parent="."]
|
||||||
|
target_position = Vector3(0, -10, 0)
|
||||||
|
|
||||||
|
[connection signal="timeout" from="SpreadTimer" to="." method="_on_spread_timer_timeout"]
|
||||||
@@ -16,6 +16,21 @@ extends Node3D
|
|||||||
one_shot = value
|
one_shot = value
|
||||||
_sync_teleporter()
|
_sync_teleporter()
|
||||||
|
|
||||||
|
@export var target_spawn_name: StringName = &"":
|
||||||
|
set(value):
|
||||||
|
target_spawn_name = value
|
||||||
|
_sync_teleporter()
|
||||||
|
|
||||||
|
@export var quest_event_name: StringName = &"":
|
||||||
|
set(value):
|
||||||
|
quest_event_name = value
|
||||||
|
_sync_teleporter()
|
||||||
|
|
||||||
|
@export var quest_id_filter: String = "":
|
||||||
|
set(value):
|
||||||
|
quest_id_filter = value
|
||||||
|
_sync_teleporter()
|
||||||
|
|
||||||
@onready var teleporter: Area3D = $Teleporter
|
@onready var teleporter: Area3D = $Teleporter
|
||||||
|
|
||||||
|
|
||||||
@@ -29,3 +44,6 @@ func _sync_teleporter() -> void:
|
|||||||
teleporter.set("target_scene_path", target_scene_path)
|
teleporter.set("target_scene_path", target_scene_path)
|
||||||
teleporter.set("target_group", target_group)
|
teleporter.set("target_group", target_group)
|
||||||
teleporter.set("one_shot", one_shot)
|
teleporter.set("one_shot", one_shot)
|
||||||
|
teleporter.set("target_spawn_name", target_spawn_name)
|
||||||
|
teleporter.set("quest_event_name", quest_event_name)
|
||||||
|
teleporter.set("quest_id_filter", quest_id_filter)
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ extends Area3D
|
|||||||
@export_file("*.tscn") var target_scene_path := "res://scenes/Levels/transportation_level.tscn"
|
@export_file("*.tscn") var target_scene_path := "res://scenes/Levels/transportation_level.tscn"
|
||||||
@export var target_group: StringName = &"player"
|
@export var target_group: StringName = &"player"
|
||||||
@export var one_shot := true
|
@export var one_shot := true
|
||||||
|
@export var target_spawn_name: StringName = &""
|
||||||
|
@export var quest_event_name: StringName = &""
|
||||||
|
@export var quest_id_filter: String = ""
|
||||||
|
|
||||||
var _is_transitioning := false
|
var _is_transitioning := false
|
||||||
|
|
||||||
@@ -22,6 +25,9 @@ func _on_body_entered(body: Node) -> void:
|
|||||||
if not ResourceLoader.exists(target_scene_path):
|
if not ResourceLoader.exists(target_scene_path):
|
||||||
push_warning("Teleporter target scene does not exist: %s" % target_scene_path)
|
push_warning("Teleporter target scene does not exist: %s" % target_scene_path)
|
||||||
return
|
return
|
||||||
|
_emit_quest_event(body)
|
||||||
|
if TeleportState != null:
|
||||||
|
TeleportState.request_spawn(target_spawn_name)
|
||||||
|
|
||||||
_is_transitioning = true
|
_is_transitioning = true
|
||||||
if one_shot:
|
if one_shot:
|
||||||
@@ -29,6 +35,17 @@ func _on_body_entered(body: Node) -> void:
|
|||||||
call_deferred("_deferred_change_scene")
|
call_deferred("_deferred_change_scene")
|
||||||
|
|
||||||
|
|
||||||
|
func _emit_quest_event(body: Node) -> void:
|
||||||
|
if quest_event_name == StringName() or QuestManager == null:
|
||||||
|
return
|
||||||
|
if quest_id_filter.strip_edges() != "" and QuestManager.get_active_quest_id() != StringName(quest_id_filter):
|
||||||
|
return
|
||||||
|
QuestManager.emit_event(quest_event_name, {
|
||||||
|
"body": body,
|
||||||
|
"source": self,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
func _deferred_change_scene() -> void:
|
func _deferred_change_scene() -> void:
|
||||||
var err := get_tree().change_scene_to_file(target_scene_path)
|
var err := get_tree().change_scene_to_file(target_scene_path)
|
||||||
if err == OK:
|
if err == OK:
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
extends Node
|
||||||
|
|
||||||
|
var _requested_spawn_name: StringName = &""
|
||||||
|
var camera_zoom_dist: float = 3.0
|
||||||
|
var third_person_camera_zoom_dist: float = 3.0
|
||||||
|
var camera_is_first_person: bool = false
|
||||||
|
|
||||||
|
|
||||||
|
func request_spawn(spawn_name: StringName) -> void:
|
||||||
|
_requested_spawn_name = spawn_name
|
||||||
|
|
||||||
|
|
||||||
|
func consume_spawn_name() -> StringName:
|
||||||
|
var spawn_name := _requested_spawn_name
|
||||||
|
_requested_spawn_name = &""
|
||||||
|
return spawn_name
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://ds35gqf0obsxf
|
||||||