Compare commits

..

2 commits

Author SHA1 Message Date
ToasterPanic
fca7af83df Why was this not staged fuuuck yooooooou 2026-05-08 10:23:01 -04:00
ToasterPanic
61269f7865 Build most core compenents and various other things and stuffs 2026-05-08 10:22:54 -04:00
34 changed files with 1754 additions and 0 deletions

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Bartosz Budnik (BudzioT)
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.
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.

View file

@ -0,0 +1,153 @@
<a id="readme-top"></a>
<!-- SHIELDS -->
[![Contributors][contributors-shield]][contributors-url]
[![Forks][forks-shield]][forks-url]
[![Stargazers][stars-shield]][stars-url]
[![Issues][issues-shield]][issues-url]
[![MIT License][license-shield]][license-url]
<!-- HEADER -->
<br />
<div align="center">
<a href="https://github.com/BudzioT/Godot_Super-Wakatime">
<img src="https://cloud-bo1ln2br1-hack-club-bot.vercel.app/0godotwaka22.png" alt="Godot Wakatime"/>
</a>
<h3 align="center"> Godot Super Wakatime </h3>
<p align="center">
Tool to measure time spent in loved by many people game engine - Godot
<br />
Officially approved to use in events created by Hack Club
<br />
<br />
<a href="https://godotengine.org/asset-library/asset/3484">Get from Asset Lib</a>
·
<a href="https://youtu.be/rqAc-YdVXyM">View Demo</a>
·
<a href="https://github.com/BudzioT/Godot_Super-Wakatime/issues/new">Report Bug / Request Feature</a>
</p>
</div>
<!-- CONTENTS -->
<details>
<summary>Table of Contents</summary>
<ol>
<li>
<a href="#about">About The Project</a>
<ul>
<li><a href="#built-with">Built Using</a></li>
</ul>
</li>
<li>
<a href="#getting-started">Getting Started</a>
<ul>
<li><a href="#installation">Installation</a></li>
</ul>
</li>
<li><a href="#usage">Usage</a></li>
<li><a href="#license">License</a></li>
</ol>
</details>
<!-- ABOUT -->
## About The Project
<br />
[![Product Screenshot][product-screenshot]](https://waka.hackclub.com)
This tool can successfully measure time spent building your games or apps in Godot.
<br />
Here's why:
* It differentiates between switching a scene and script
* It counts key presses as coding and mouse clicks as building scene
* Changing scene structure results in a heartbeat sent
* It correctly detects OS, machine name, language, editor, files
* It can detect your cursor line and position
* Time is split between: Building, Coding, Testing
* In the future it will also detect testing your projects
It works on both Linux and Windows, it wasn't tested on macOS yet
<br />
You can also see your time spent in the editor itself:
[![Time in editor][time-screenshot]]
<p align="right">(<a href="#readme-top">top</a>)</p>
### Built Using
I used the Ouch! CLI tool for decompression of files <br />
This project was built using one simple, yet powerful language.<br />
It required a lot of workarounds, but it was a pleasure to use it
* [![GDScript][Godot]][Godot-url]
* [![Ouch!][Ouch-shield]][Ouch-url]
<p align="right">(<a href="#readme-top">top</a>)</p>
<!-- GETTING STARTED -->
## Getting Started
How to install and use this software? It's easy!
### Installation
You can either download it from asset lib (will provide a link, once it gets accepted)
<br />Or you can manually install it, here's how to do it!
1. Clone the repository
```sh
git clone https://github.com/BudzioT/Godot_Super-Wakatime.git
```
2. Go into your project
3. Insert the entire `./addons` folder into your project `res://` directory
<p align="right">(<a href="#readme-top">top</a>)</p>
<!-- USAGE -->
## Usage
Don't know how to use this plugin? Here are the steps:
1. Turn on the plugin in your plugins. In your `Project -> Project Settings -> Plugins -> `Click the `Enable` checkbox near this plugin
2. If prompted for API key, provide it from Wakatime website
3. if there is an issue with it, please manually create `~/.wakatime.cfg` file with these contents:
```sh
[settings]
api_key=xxxx
```
Where xxxx is your api key
<br /><br />
If you are coming from Hack Club use this:
```sh
[settings]
api_url = https://hackatime.hackclub.com/api/hackatime/v1
api_key=xxxx
```
4. Wakatime CLI should have been installed automatically along with Ouch! Decompression library
5. Work on your project! You should see your results on either Wakatime or Hackatime!
6. You can also see your time at the bottom panel
<p align="right">(<a href="#readme-top">top</a>)</p>
<!-- LICENSE -->
## License
Distributed under the MIT License. See `LICENSE` for more information.
<p align="right">(<a href="#readme-top">back to top</a>)</p>
<!-- URLS -->
[contributors-shield]: https://img.shields.io/github/contributors/budziot/Godot_Super-Wakatime?style=for-the-badge
[contributors-url]: https://github.com/BudzioT/Godot_Super-Wakatime/graphs/contributors
[forks-shield]: https://img.shields.io/github/forks/budziot/Godot_Super-Wakatime?style=for-the-badge
[forks-url]: https://github.com/BudzioT/Godot_Super-Wakatime/forks
[stars-shield]: https://img.shields.io/github/stars/budziot/Godot_Super-Wakatime?style=for-the-badge
[stars-url]: https://github.com/BudzioT/Godot_Super-Wakatime/stargazers
[issues-shield]: https://img.shields.io/github/issues/budziot/Godot_Super-Wakatime?style=for-the-badge
[issues-url]: https://github.com/BudzioT/Godot_Super-Wakatime/issues
[license-shield]: https://img.shields.io/github/license/budziot/Godot_Super-Wakatime?style=for-the-badge
[license-url]: https://github.com/BudzioT/Godot_Super-Wakatime/blob/master/addons/godot_super-wakatime/LICENSE
[product-screenshot]: https://cloud-j4wibbzz7-hack-club-bot.vercel.app/0image.png
[product-logo]: https://cloud-j4wibbzz7-hack-club-bot.vercel.app/2godotwaka2.png
[Godot]: https://img.shields.io/badge/Godot%20Engine-478CBF?logo=godotengine&logoColor=fff&style=flat
[Godot-url]: https://godotengine.org/
[Ouch-shield]: https://img.shields.io/badge/Ouch!-tool-blue?label=Ouch!
[Ouch-url]: https://github.com/ouch-org/ouch
[time-screenshot]: https://cloud-l88kldf50-hack-club-bot.vercel.app/0image.png

View file

@ -0,0 +1,55 @@
[gd_scene load_steps=3 format=3 uid="uid://bv3rxl15k7bj6"]
[sub_resource type="Theme" id="Theme_qedjm"]
[sub_resource type="Theme" id="Theme_1xn0x"]
[node name="ApiKeyPrompt" type="PopupPanel"]
title = "API key configuration"
initial_position = 1
size = Vector2i(350, 100)
visible = true
content_scale_aspect = 4
content_scale_stretch = 1
theme = SubResource("Theme_qedjm")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 4.0
offset_top = 4.0
offset_right = -4.0
offset_bottom = -4.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 4
size_flags_vertical = 4
theme = SubResource("Theme_1xn0x")
[node name="HBoxContainerTop" type="HBoxContainer" parent="VBoxContainer"]
layout_mode = 2
[node name="LineEdit" type="LineEdit" parent="VBoxContainer/HBoxContainerTop"]
custom_minimum_size = Vector2(200, 25)
layout_mode = 2
size_flags_horizontal = 6
size_flags_vertical = 0
placeholder_text = "Provide Your Wakatime API Key"
expand_to_text_length = true
secret = true
[node name="ShowButton" type="Button" parent="VBoxContainer/HBoxContainerTop"]
layout_mode = 2
size_flags_horizontal = 6
size_flags_vertical = 4
text = "Show"
[node name="HBoxContainerBottom" type="HBoxContainer" parent="VBoxContainer"]
layout_mode = 2
[node name="SubmitButton" type="Button" parent="VBoxContainer/HBoxContainerBottom"]
layout_mode = 2
size_flags_horizontal = 6
size_flags_vertical = 0
text = "Submit"

View file

@ -0,0 +1,29 @@
[gd_scene format=3 uid="uid://c4t47uj61wtu5"]
[node name="Counter" type="Panel"]
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -228.0
offset_top = -36.0
grow_horizontal = 0
grow_vertical = 0
size_flags_vertical = 8
[node name="HBoxContainer" type="HBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Label" type="Label" parent="HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 1
text = "00 hrs 00 mins"
horizontal_alignment = 1
vertical_alignment = 1

View file

@ -0,0 +1,21 @@
var Utils = preload("res://addons/godot_super-wakatime/utils.gd").new()
func decompressor_cli(current_decompressor, platform: String, plugin_path: String) -> String:
"""Get path to the decompressor cli"""
var build = Utils.get_ouch_build(platform)
var ext: String = ".exe" if platform == "windows" else ""
if current_decompressor == null:
if platform == "windows":
current_decompressor = "%s/%s%s" % [plugin_path, build, ext]
else:
current_decompressor = "%s%s" % [build, ext]
else:
current_decompressor = "%s%s" % [build, ext]
return current_decompressor
func lib_exists(current_decompressor, platform: String, plugin_path: String) -> bool:
"""Return if ouch already exists"""
return FileAccess.file_exists(decompressor_cli(current_decompressor, platform, plugin_path));

View file

@ -0,0 +1 @@
uid://hk0ile7qa8oi

View file

@ -0,0 +1,568 @@
@tool
extends EditorPlugin
#------------------------------- SETUP -------------------------------
# Utilities
var Utils = preload("res://addons/godot_super-wakatime/utils.gd").new()
var DecompressorUtils = preload("res://addons/godot_super-wakatime/decompressor.gd").new()
# Paths, Urls
const PLUGIN_PATH: String = "res://addons/godot_super-wakatime"
const ZIP_PATH: String = "%s/wakatime.zip" % PLUGIN_PATH
const WAKATIME_URL_FMT: String = \
"https://github.com/wakatime/wakatime-cli/releases/download/v1.54.0/{wakatime_build}.zip"
const DECOMPERSSOR_URL_FMT: String = \
"https://github.com/ouch-org/ouch/releases/download/0.3.1/{ouch_build}"
# Names for menu
const API_MENU_ITEM: String = "Wakatime API key"
const CONFIG_MENU_ITEM: String = "Wakatime Config File"
# Directories to grab wakatime from
var wakatime_dir = null
var wakatime_cli = null
var decompressor_cli = null
var ApiKeyPrompt: PackedScene = preload("res://addons/godot_super-wakatime/api_key_prompt.tscn")
var Counter: PackedScene = preload("res://addons/godot_super-wakatime/counter.tscn")
# Set platform
var system_platform: String = Utils.set_platform()[0]
var system_architecture: String = Utils.set_platform()[1]
var debug: bool = false
# parity with kate-wakatime
const LOG_INTERVAL: int = 120000
var key_get_tries: int = 0
var counter_instance: Node
var current_time: String = "0 hrs, 0mins"
# #------------------------------- DIRECT PLUGIN FUNCTIONS -------------------------------
func _ready() -> void:
setup_plugin()
set_process(true)
func _exit_tree() -> void:
_disable_plugin()
set_process(false)
class DataSnapshot:
var file_path: String
var line_no: int
var cursor_pos: int
var lines: int
func get_coding_data(file: Script = null) -> DataSnapshot:
var snapshot = DataSnapshot.new()
if not file:
file = get_editor_interface().get_script_editor().get_current_script()
if not file:
return null
snapshot.file_path = ProjectSettings.globalize_path(file.resource_path)
var code_edit: CodeEdit = get_editor_interface().get_script_editor().get_current_editor().get_base_editor()
if code_edit is not CodeEdit:
return null
snapshot.line_no = code_edit.get_caret_line()
snapshot.cursor_pos = code_edit.get_caret_column()
snapshot.lines = code_edit.get_line_count()
return snapshot
func get_building_data(mouse_event: InputEventMouse, file_path: String = "") -> DataSnapshot:
"""Generate"""
var snapshot = DataSnapshot.new()
if file_path == "":
if EditorInterface.get_edited_scene_root() == null:
return null
var file = EditorInterface.get_edited_scene_root().scene_file_path
if not file:
return null
snapshot.file_path = ProjectSettings.globalize_path(file)
else:
snapshot.file_path = file_path
snapshot.line_no = int(roundf(mouse_event.position.x))
snapshot.cursor_pos = int(roundf(mouse_event.position.y))
# no line numbers in a screen lol
snapshot.lines = 0
return snapshot
var last_tick_frame: int = 0
var last_mouse_event: InputEventMouse
var moved_on_edit: bool = false
func _input(event: InputEvent) -> void:
"""Handle all input events"""
if Time.get_ticks_msec() - last_tick_frame > LOG_INTERVAL:
if tab_open == "Script":
if event is InputEventKey:
var key_event = event as InputEventKey
if (key_event.keycode == KEY_UP || key_event.keycode == KEY_DOWN
|| key_event.keycode == KEY_LEFT || key_event.keycode == KEY_RIGHT
|| key_event.keycode == KEY_ALT || key_event.keycode == KEY_SHIFT):
return
var snapshot = get_coding_data()
if snapshot == null:
return
send_heartbeat(snapshot.file_path, "coding", snapshot.line_no, snapshot.cursor_pos, snapshot.lines, false)
last_tick_frame = Time.get_ticks_msec()
elif tab_open == "2D" || tab_open == "3D":
if event is InputEventMouseButton: # we dont really care if people are typing in node editor
var snapshot = get_building_data(event)
if snapshot == null:
return
send_heartbeat(snapshot.file_path, "building", snapshot.line_no, snapshot.cursor_pos, snapshot.lines, false)
last_tick_frame = Time.get_ticks_msec()
# store the mouse data for scene saved
if tab_open == "2D" || tab_open == "3D":
if event is InputEventMouse:
last_mouse_event = event
moved_on_edit = true
# 2D, 3D, Script, Game, or AssetLib
var tab_open: String = "2D"
func _main_screen_changed(tab_name: String):
"""Update the curent tab so we can know where our input events are going to"""
tab_open = tab_name
# no cooldown for writes
func _scene_saved(file_path: String):
"""Handle heartbeats to be sent on scene save"""
if last_mouse_event == null:
return
if !moved_on_edit:
return
moved_on_edit = false
var snapshot = get_building_data(last_mouse_event)
if snapshot == null:
return
send_heartbeat(snapshot.file_path, "building", snapshot.line_no, snapshot.cursor_pos, snapshot.lines, true)
func _resource_saved(resource: Resource):
"""Handle heartbeats to be sent on file save"""
if not resource is GDScript:
return
var snapshot = get_coding_data(resource)
if snapshot == null:
return
send_heartbeat(snapshot.file_path, "coding", snapshot.line_no, snapshot.cursor_pos, snapshot.lines, true)
func setup_plugin() -> void:
"""Setup Wakatime plugin, download dependencies if needed, initialize menu"""
Utils.plugin_print("Setting up %s" % get_user_agent())
check_dependencies()
main_screen_changed.connect(_main_screen_changed)
scene_saved.connect(_scene_saved)
resource_saved.connect(_resource_saved)
# Grab API key if needed
var api_key = get_api_key()
if api_key == null:
request_api_key()
await get_tree().process_frame
# Add menu buttons
add_tool_menu_item(API_MENU_ITEM, request_api_key)
add_tool_menu_item(CONFIG_MENU_ITEM, open_config)
counter_instance = Counter.instantiate()
add_control_to_bottom_panel(counter_instance, current_time)
func _disable_plugin() -> void:
"""Cleanup after disabling plugin"""
# Remove items from menu
remove_tool_menu_item(API_MENU_ITEM)
remove_tool_menu_item(CONFIG_MENU_ITEM)
remove_control_from_bottom_panel(counter_instance)
func send_heartbeat(filepath: String, catagory: String, line_num: int, cursor_pos: int, lines: int, is_write: bool) -> void:
"""Send Wakatimde heartbeat for the specified file"""
if not Utils.wakatime_cli_exists(get_waka_cli()):
print("Wakatime not installed!")
return
# Check Wakatime API key
var api_key = get_api_key()
if api_key == null:
Utils.plugin_print("Failed to get Wakatime API key. Are you sure it's correct?")
if (key_get_tries < 3):
request_api_key()
key_get_tries += 1
else:
Utils.plugin_print("If this keep occuring, please create a file: ~/.wakatime.cfg\n
initialize it with:\n[settings]\napi_key={your_key}")
return
# Append all informations as Wakatime CLI arguments
var cmd: Array[Variant] = ["--entity", filepath, "--key", api_key]
if is_write:
cmd.append("--write")
cmd.append_array(["--alternate-project", ProjectSettings.get("application/config/name")])
cmd.append_array(["--time", str(Time.get_unix_time_from_system())])
cmd.append_array(["--lineno", str(line_num)])
cmd.append_array(["--cursorpos", str(cursor_pos)])
cmd.append_array(["--lines-in-file", str(lines)])
cmd.append_array(["--plugin", get_user_agent()])
cmd.append_array(["--category", catagory])
# Send heartbeat using Wakatime CLI
var cmd_callable = Callable(self, "_handle_heartbeat").bind(cmd)
WorkerThreadPool.add_task(cmd_callable)
func _find_code_edit_recursive(node: Node) -> CodeEdit:
"""Find recursively code editor in a node"""
# If node is already a code editor, return it
if node is CodeEdit:
return node
# Try to find it in every child of a given node
for child in node.get_children():
var editor = _find_code_edit_recursive(child)
if editor:
return editor
return null
func _handle_heartbeat(cmd_arguments) -> void:
"""Handle sending the heartbeat"""
# Get Wakatime CLI and try to send a heartbeat
if wakatime_cli == null:
wakatime_cli = Utils.get_waka_cli()
var output: Array[Variant] = []
var exit_code: int = OS.execute(wakatime_cli, cmd_arguments, output, true)
update_today_time(wakatime_cli)
# Inform about success or errors if user is in debug
if debug:
if exit_code == -1:
Utils.plugin_print("Failed to send heartbeat: %s" % output)
else:
Utils.plugin_print("Heartbeat sent: %s" % output)
func update_today_time(wakatime_cli) -> void:
"""Update today's time in menu"""
var output: Array[Variant] = []
# I would use --plugin "godot/4.6.2 Godot_Super-Wakatime/2.0.1" but it doesn't seem to do anything with --today
# Get today's time from Wakatime CLI
var exit_code: int = OS.execute(wakatime_cli, ["--today"], output, true)
# Convert it and combine different categories into
if exit_code == 0:
current_time = output[0]
else:
current_time = "Wakatime"
#print(current_time)
call_deferred("_update_panel_label", current_time, output[0])
func _update_panel_label(label: String, content: String):
"""Update bottom panel name that shows time"""
# If counter exists and it has a label, update both the label and panel's name
if counter_instance and counter_instance.get_node("HBoxContainer/Label"):
counter_instance.get_node("HBoxContainer/Label").text = content
# Workaround to rename panel
remove_control_from_bottom_panel(counter_instance)
add_control_to_bottom_panel(counter_instance, label)
#------------------------------- FILE FUNCTIONS -------------------------------
func open_config() -> void:
"""Open wakatime config file"""
OS.shell_open(Utils.config_filepath(system_platform, PLUGIN_PATH))
func get_waka_dir() -> String:
"""Search for and return wakatime directory"""
if wakatime_dir == null:
wakatime_dir = "%s/.wakatime" % Utils.home_directory(system_platform, PLUGIN_PATH)
return wakatime_dir
func get_waka_cli() -> String:
"""Get wakatime_cli file"""
if wakatime_cli == null:
var build = Utils.get_waka_build(system_platform, system_architecture)
var ext: String = ".exe" if system_platform == "windows" else ''
wakatime_cli = "%s/%s%s" % [get_waka_dir(), build, ext]
return wakatime_cli
func check_dependencies() -> void:
"""Make sure all dependencies exist"""
if !Utils.wakatime_cli_exists(get_waka_cli()):
download_wakatime()
if !DecompressorUtils.lib_exists(decompressor_cli, system_platform, PLUGIN_PATH):
download_decompressor()
func download_wakatime() -> void:
"""Download wakatime cli"""
Utils.plugin_print("Downloading Wakatime CLI...")
var url: String = WAKATIME_URL_FMT.format({"wakatime_build":
Utils.get_waka_build(system_platform, system_architecture)})
# Try downloading wakatime
var http = HTTPRequest.new()
http.download_file = ZIP_PATH
http.connect("request_completed", Callable(self, "_wakatime_download_completed"))
add_child(http)
# Handle errors
var status = http.request(url)
if status != OK:
Utils.plugin_print_err("Failed to start downloading Wakatime [Error: %s]" % status)
_disable_plugin()
func download_decompressor() -> void:
"""Download ouch decompressor"""
Utils.plugin_print("Downloading Ouch! decompression library...")
var url: String = DECOMPERSSOR_URL_FMT.format({"ouch_build":
Utils.get_ouch_build(system_platform)})
if system_platform == "windows":
url += ".exe"
# Try to download ouch
var http = HTTPRequest.new()
http.download_file = DecompressorUtils.decompressor_cli(decompressor_cli, system_platform, PLUGIN_PATH)
http.connect("request_completed", Callable(self, "_decompressor_download_finished"))
add_child(http)
# Handle errors
var status = http.request(url)
if status != OK:
_disable_plugin()
Utils.plugin_print_err("Failed to start downloading Ouch! library [Error: %s]" % status)
func _wakatime_download_completed(result, status, headers, body) -> void:
"""Finish downloading wakatime, handle errors"""
if result != HTTPRequest.RESULT_SUCCESS:
Utils.plugin_print_err("Error while downloading Wakatime CLI")
_disable_plugin()
return
Utils.plugin_print("Wakatime CLI has been installed succesfully! Located at %s" % ZIP_PATH)
extract_files(ZIP_PATH, get_waka_dir())
func _decompressor_download_finished(result, status, headers, body) -> void:
"""Handle errors and finishi decompressor download"""
# Error while downloading
if result != HTTPRequest.RESULT_SUCCESS:
Utils.plugin_print_err("Error while downloading Ouch! library")
_disable_plugin()
return
# Error while saving
if !DecompressorUtils.lib_exists(decompressor_cli, system_platform, PLUGIN_PATH):
Utils.plugin_print_err("Failed to save Ouch! library")
_disable_plugin()
return
# Save decompressor path, give write permissions to it
var decompressor: String = \
ProjectSettings.globalize_path(DecompressorUtils.decompressor_cli(decompressor_cli,
system_platform, PLUGIN_PATH))
if system_platform == "linux" or system_platform == "darwin":
OS.execute("chmod", ["+x", decompressor], [], true)
# Extract files, allowing usage of Ouch!
Utils.plugin_print("Ouch! has been installed succesfully! Located at %s" % \
DecompressorUtils.decompressor_cli(decompressor_cli, system_platform, PLUGIN_PATH))
extract_files(ZIP_PATH, get_waka_dir())
func extract_files(source: String, destination: String) -> void:
"""Extract downloaded Wakatime zip"""
# If decompression library and wakatime zip folder don't exist, return
if not DecompressorUtils.lib_exists(decompressor_cli, system_platform,
PLUGIN_PATH) and not Utils.wakatime_zip_exists(ZIP_PATH):
return
# Get paths as global
Utils.plugin_print("Extracting Wakatime...")
var decompressor: String
if system_platform == "windows":
decompressor = ProjectSettings.globalize_path(
DecompressorUtils.decompressor_cli(decompressor_cli, system_platform, PLUGIN_PATH))
else:
decompressor = ProjectSettings.globalize_path("res://" +
DecompressorUtils.decompressor_cli(decompressor_cli, system_platform, PLUGIN_PATH))
var src: String = ProjectSettings.globalize_path(source)
var dest: String = ProjectSettings.globalize_path(destination)
# Execute Ouch! decompression command, catch errors
var errors: Array[Variant] = []
var args: Array[String] = ["--yes", "decompress", src, "--dir", dest]
var error: int = OS.execute(decompressor, args, errors, true)
if error:
Utils.plugin_print(errors)
_disable_plugin()
return
# Results
if Utils.wakatime_cli_exists(get_waka_cli()):
Utils.plugin_print("Wakatime CLI installed (path: %s)" % get_waka_cli())
else:
Utils.plugin_print_err("Installation of Wakatime failed")
_disable_plugin()
# Remove leftover files
clean_files()
func clean_files():
"""Delete files that aren't needed anymore"""
if Utils.wakatime_zip_exists(ZIP_PATH):
delete_file(ZIP_PATH)
if DecompressorUtils.lib_exists(decompressor_cli, system_platform, PLUGIN_PATH):
delete_file(ZIP_PATH)
func delete_file(path: String) -> void:
"""Delete file at specified path"""
var dir: DirAccess = DirAccess.open("res://")
var status: int = dir.remove(path)
if status != OK:
Utils.plugin_print_err("Failed to clean unnecesary file at %s" % path)
else:
Utils.plugin_print("Clean unncecesary file at %s" % path)
#------------------------------- API KEY FUNCTIONS -------------------------------
func get_api_key():
"""Get wakatime api key"""
var result = []
# Handle errors while getting the key
var err = OS.execute(get_waka_cli(), ["--config-read", "api_key"], result)
if err == -1:
return null
# Trim API key from whitespaces and return it
var key = result[0].strip_edges()
if key.is_empty():
return null
return key
func request_api_key() -> void:
"""Request Wakatime API key from the user"""
# Prepare prompt
var prompt = ApiKeyPrompt.instantiate()
_set_api_key(prompt, get_api_key())
_register_api_key_signals(prompt)
# Show prompt and hide it on request
add_child(prompt)
prompt.popup_centered()
await prompt.popup_hide
prompt.queue_free()
func _set_api_key(prompt: PopupPanel, api_key) -> void:
"""Set API key from prompt"""
# Safeguard against empty key
if api_key == null:
api_key = ''
# Set correct text, to show API key
var edit_field: Node = prompt.get_node("VBoxContainer/HBoxContainerTop/LineEdit")
edit_field.text = api_key
func _register_api_key_signals(prompt: PopupPanel) -> void:
"""Connect all signals related to API key popup"""
# Get all Nodes
var show_button: Node = prompt.get_node("VBoxContainer/HBoxContainerTop/ShowButton")
var save_button: Node = prompt.get_node("VBoxContainer/HBoxContainerBottom/SubmitButton")
# Connect them to press events
show_button.connect("pressed", Callable(self, "_on_toggle_key_text").bind(prompt))
save_button.connect("pressed", Callable(self, "_on_save_key").bind(prompt))
prompt.connect("popup_hide", Callable(self, "_on_popup_hide").bind(prompt))
func _on_popup_hide(prompt: PopupPanel):
"""Close the popup window when user wants to hide it"""
prompt.queue_free()
func _on_toggle_key_text(prompt: PopupPanel) -> void:
"""Handle hiding and showing API key"""
# Get nodes
var show_button: Node = prompt.get_node("VBoxContainer/HBoxContainerTop/ShowButton")
var edit_field: Node = prompt.get_node("VBoxContainer/HBoxContainerTop/LineEdit")
# Set the correct text and hide field if needed
edit_field.secret = not edit_field.secret
show_button.text = "Show" if edit_field.secret else "Hide"
func _on_save_key(prompt: PopupPanel) -> void:
"""Handle entering API key"""
# Get text field node and api key that's entered
var edit_field: Node = prompt.get_node("VBoxContainer/HBoxContainerTop/LineEdit")
var api_key = edit_field.text.strip_edges()
# Try to set api key for wakatime and handle errors
var err: int = OS.execute(get_waka_cli(), ["--config-write", "api-key=%s" % api_key])
if err == -1:
Utils.plugin_print("Failed to save API key")
prompt.visible = false
#------------------------------- PLUGIN INFORMATIONS -------------------------------
func get_user_agent() -> String:
"""Get user agent identifier"""
var os_name = OS.get_name().to_lower()
return "godot/%s %s/%s" % [
get_engine_version(),
_get_plugin_name(),
_get_plugin_version()
]
func _get_plugin_name() -> String:
"""Get name of the plugin"""
return "Godot_Super-Wakatime"
func _get_plugin_version() -> String:
"""Get version of the plugin"""
if get_plugin_version() == "":
return "unknown"
return get_plugin_version()
func get_engine_version() -> String:
"""Get verison of currently used engine"""
return "%s.%s.%s" % [Engine.get_version_info()["major"], Engine.get_version_info()["minor"],
Engine.get_version_info()["patch"]]

View file

@ -0,0 +1 @@
uid://cvox0hdbntt3o

View file

@ -0,0 +1,7 @@
[plugin]
name="Godot Super-Wakatime"
description="Wakatime plugin for Godot, which provides many information to track your time in the best way possible. Made for Hack Club, to allow teenagers to spend time building games and earn rewards"
author="Bartosz Budnik + Fox Ellison-Taylor"
version="2.0.1"
script="godot_super-wakatime.gd"

View file

@ -0,0 +1,71 @@
func plugin_print(msg) -> void:
"""Print message from plugin"""
print("[Godot_Super-Wakatime]: %s" % msg)
func plugin_print_err(err) -> void:
"""Inform about error from plugin"""
push_error("[Godot_Super-Wakatime]: %s" % err)
func set_platform():
"""Set currently used platform"""
var platform: String = "linux"
var architecture: String = "arm64"
if OS.has_feature("windows") or OS.has_feature("uwp"):
platform = "windows"
elif OS.has_feature("linux"):
platform = "linux"
elif OS.has_feature("macos"):
platform = "darwin"
elif OS.has_feature("android"):
platform = "android"
elif OS.has_feature("ios"):
platform = "ios"
if OS.has_feature("x86_64"):
architecture = "amd64"
elif OS.has_feature("x86_32"):
architecture = "amd32"
elif OS.has_feature("arm64"):
architecture = "arm64"
elif OS.has_feature("arm32"):
architecture = "arm32"
return [platform, architecture]
func get_waka_build(platform: String, architecture: String) -> String:
"""Return wakatime build for current OS"""
return "wakatime-cli-%s-%s" % [platform, architecture]
func get_ouch_build(system_platform: String) -> String:
"""Get build for ouch (compression and decompression tool)"""
var platform: String = "linux-musl"
if system_platform == "windows":
platform = "pc-windows-msvc"
elif system_platform == "darwin":
platform = "apple-darwin"
return "ouch-%s-%s" % ["x86_64", platform]
func home_directory(platform: String, plugin_path: String) -> String:
"""Get home directory from """
var home = null
for env in ["WAKATIME_HOME", "USERPROFILE", "HOME"]:
home = OS.get_environment(env)
if home:
if platform == "windows":
home = home.replace("\\", '/')
return home
return plugin_path
func config_filepath(platform: String, plugin_path: String) -> String:
"""Get path to wakatime configuration file"""
return "%s/.wakatime.cfg" % home_directory(platform, plugin_path)
func wakatime_cli_exists(wakatime_cli) -> bool:
"""Return if wakatime cli tool exists already"""
return FileAccess.file_exists(wakatime_cli)
func wakatime_zip_exists(wakatime_zip: String) -> bool:
"Check if wakatime zip file exists"
return FileAccess.file_exists(wakatime_zip)

View file

@ -0,0 +1 @@
uid://cg2vp0pl0l1bs

View file

@ -0,0 +1,7 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://bn423gccnsj5s"]
[ext_resource type="Texture2D" uid="uid://poepp7kmc5us" path="res://textures/stalagmite.png" id="1_3arcn"]
[resource]
albedo_texture = ExtResource("1_3arcn")
texture_filter = 0

File diff suppressed because one or more lines are too long

1
models/stalagmite.gltf Normal file
View file

@ -0,0 +1 @@
{"asset":{"version":"2.0","generator":"Blockbench 5.1.3 glTF exporter"},"scenes":[{"nodes":[0],"name":"blockbench_export"}],"scene":0,"nodes":[{"translation":[0,1,0],"name":"mesh","mesh":0}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":864,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":864,"byteLength":864,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1728,"byteLength":576,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":2304,"byteLength":216,"target":34963}],"buffers":[{"byteLength":2520,"uri":"data:application/octet-stream;base64,AABwPwAAgL8AAHA/AABwvwAAgL8AAHA/AABwPwAAgL8AAHC/AABwvwAAgL8AAHC/AABAvQAAAEAAAEA9AAAQPgAAoD8AABA+AAAQvgAAoD8AABA+AABAPQAAAEAAAEA9AABAPQAABEAAAEC9AAAQvgAAoD8AABC+AAAQPgAAoD8AABC+AABAvQAAAEAAAEC9AABwvwAAgL8AAHC/AAAEvwAAQL4AAPC+AAAEPwAAgL4AAPC+AABwPwAAgL8AAHC/AAAEvwAAQL4AAPC+AACQvgAAAD8AAJC+AACQPgAAAD8AAJC+AAAEPwAAgL4AAPC+AACQvgAAAD8AAJC+AAAQvgAAoD8AABC+AAAQPgAAoD8AABC+AACQPgAAAD8AAJC+AABwPwAAgL8AAHA/AAAEPwAAgL4AABA/AAAEvwAAgL4AABA/AABwvwAAgL8AAHA/AAAEPwAAgL4AABA/AABwPgAAAD8AAKg+AABwvgAAAD8AAKg+AAAEvwAAgL4AABA/AABwPgAAAD8AAKg+AAAQPgAAoD8AABA+AAAQvgAAoD8AABA+AABwvgAAAD8AAKg+AABAPQAAAEAAAEA9AABAPQAABEAAAEC9AABAvQAAAEAAAEA9AABAvQAAAEAAAEC9AAAQPgAAoD8AABA+AABAPQAABEAAAEC9AAAQPgAAoD8AABC+AABAPQAAAEAAAEA9AAAEPwAAgL4AABA/AABwPwAAgL8AAHA/AAAEPwAAgL4AAPC+AABwPwAAgL8AAHC/AABwPgAAAD8AAKg+AAAEPwAAgL4AABA/AACQPgAAAD8AAJC+AAAEPwAAgL4AAPC+AAAQPgAAoD8AABA+AABwPgAAAD8AAKg+AAAQPgAAoD8AABC+AACQPgAAAD8AAJC+AABAvQAAAEAAAEC9AAAQvgAAoD8AABA+AAAQvgAAoD8AABC+AABAvQAAAEAAAEA9AABwvwAAgL8AAHA/AAAEvwAAgL4AABA/AAAEvwAAQL4AAPC+AABwvwAAgL8AAHC/AAAEvwAAgL4AABA/AABwvgAAAD8AAKg+AACQvgAAAD8AAJC+AAAEvwAAQL4AAPC+AABwvgAAAD8AAKg+AAAQvgAAoD8AABA+AAAQvgAAoD8AABC+AACQvgAAAD8AAJC+AAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAOwF/j3sBX4/AAAAAOwF/j3sBX4/AAAAAOwF/j3sBX4/AAAAAOwF/j3sBX4/AAAAAAvA6j0MUH6/AAAAAAvA6j0MUH6/AAAAAAvA6j0MUH6/AAAAAAvA6j0MUH6/J0HyPDDT+T4QVF+/J0HyPDDT+T4QVF+/J0HyPDDT+T4QVF+/J0HyPDDT+T4QVF+/AAAAAFO3hj7D+na/AAAAAFO3hj7D+na/AAAAAFO3hj7D+na/AAAAAFO3hj7D+na/AAAAACK2PD6DnXu/AAAAACK2PD6DnXu/AAAAACK2PD6DnXu/AAAAACK2PD6DnXu/AAAAAC755D4u+WQ/AAAAAC755D4u+WQ/AAAAAC755D4u+WQ/AAAAAC755D4u+WQ/AAAAAIC3mD7NWHQ/AAAAAIC3mD7NWHQ/AAAAAIC3mD7NWHQ/AAAAAIC3mD7NWHQ/AAAAAEJbeD5CW3g/AAAAAEJbeD5CW3g/AAAAAEJbeD5CW3g/AAAAAEJbeD5CW3g/AAAAAEABVT/VAA4/AAAAAEABVT/VAA4/AAAAAEABVT/VAA4/AAAAAEABVT/VAA4/DFB+PwvA6j0AAAAADFB+PwvA6j0AAAAADFB+PwvA6j0AAAAADFB+PwvA6j0AAAAAkx9fP4UD+z4AAAAAkx9fP4UD+z4AAAAAkx9fP4UD+z4AAAAAkx9fP4UD+z4AAAAADiptP3xGvT5+8pE9DiptP3xGvT5+8pE9DiptP3xGvT5+8pE9DiptP3xGvT5+8pE97AV+P+wF/j0AAAAA7AV+P+wF/j0AAAAA7AV+P+wF/j0AAAAA7AV+P+wF/j0AAAAA7AV+v+wF/j0AAAAA7AV+v+wF/j0AAAAA7AV+v+wF/j0AAAAA7AV+v+wF/j0AAAAAkVZdv7dkAD9jAfk8kVZdv7dkAD9jAfk8kVZdv7dkAD9jAfk8kVZdv7dkAD9jAfk8Diptv3xGvT5+8pE9Diptv3xGvT5+8pE9Diptv3xGvT5+8pE9Diptv3xGvT5+8pE97AV+v+wF/j0AAAAA7AV+v+wF/j0AAAAA7AV+v+wF/j0AAAAA7AV+v+wF/j0AAAAAAAAOPwAAAAAAAKQ+AAAAAAAADj8AAHA+AACkPgAAcD4AAOQ9AADUPgAACj7SLwI/AADMPdIvAj8AAPw9AADUPmaglD4AACA+ZqCgPkRYhD5moI4+RFiEPmagmj588ic+DvnTPhpVDz9moLg+1MniPl48bT7QpeY+5A04PsSqDz9moLg+1MniPmagqT5kLrU+ZqCFPmQutT7MQG0+rqXmPmagqT5kLrU+ZqCgPkRYhD5moI4+RFiEPmaghT5kLrU+AABwPh7nTj8AADo+7BE0PwAAWD3sETQ/AAAAAB7nTj8AADo+7BE0PwAAFj7n7Bo/AAC0PefsGj8AAFg97BE0PwAAFj7n7Bo/AAAKPtIvAj8AAMw90i8CPwAAtD3n7Bo/AACAPAAAgDwAAIA8AAAAAAAAAAAAAIA8AAAAAAABjjtRIsQ9EGHRPVEi9D0AAAAAKBEGPhBh0T1RItw9gE/+O8a6Nz0EP5g+3F+vNxbDzz6q6DE+4v+WPoX6bz7Wfs0+USKUPdRvST7Gujc9BD+YPjtLGD7YLko+xJIxPrIAlz5RIsQ9EGHRPVEilD3Ub0k+KBEGPhBh0T0oERg+SC5KPjAk7z4AAKg+MCT7PqRf2D4wJOk+pF/YPjAk9T4AAKg+dfoVPyjwOT+2mgo/MiMePz1G0z6Mpxs/Fgu0PtKROD+2mgo/MiMePxiSAz+kXwQ/JwfgPmaPBD9PWtM+TqgbPxiSAz+kXwQ/MCT7PqRf2D4wJOk+pF/YPjAk4D5CjwQ/AgAAAAEAAgABAAMABAAGAAUABAAFAAcACAAKAAkACAAJAAsADAANAA4ADAAOAA8AEAARABIAEAASABMAFAAVABYAFAAWABcAGAAZABoAGAAaABsAHAAdAB4AHAAeAB8AIAAhACIAIAAiACMAJgAkACUAJgAlACcAKAAqACkAKAApACsALgAsAC0ALgAtAC8AMgAwADEAMgAxADMANgA0ADUANgA1ADcAOAA6ADkAOAA5ADsAPAA9AD4APAA+AD8AQABBAEIAQABCAEMARABFAEYARABGAEcA"}],"accessors":[{"bufferView":0,"componentType":5126,"count":72,"max":[0.9375,2.0625,0.9375],"min":[-0.9375,-1,-0.9375],"type":"VEC3"},{"bufferView":1,"componentType":5126,"count":72,"max":[0.9934089183807373,0.8320503234863281,0.9922778606414795],"min":[-0.9922778606414795,-1,-0.9934089183807373],"type":"VEC3"},{"bufferView":2,"componentType":5126,"count":72,"max":[0.5858529210090637,0.8082140684127808],"min":[0,0],"type":"VEC2"},{"bufferView":3,"componentType":5123,"count":108,"max":[71],"min":[0],"type":"SCALAR"}],"materials":[{"pbrMetallicRoughness":{"metallicFactor":0,"roughnessFactor":1,"baseColorTexture":{"index":0}},"alphaMode":"MASK","alphaCutoff":0.05,"doubleSided":true}],"textures":[{"sampler":0,"source":0,"name":"texture"}],"samplers":[{"magFilter":9728,"minFilter":9728,"wrapS":33071,"wrapT":33071}],"images":[{"mimeType":"image/png","name":"stalagmite.png","uri":"stalagmite.png"}],"meshes":[{"primitives":[{"mode":4,"attributes":{"POSITION":0,"NORMAL":1,"TEXCOORD_0":2},"indices":3,"material":0}]}]}

View file

@ -0,0 +1,55 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://b0kty7juk7rfo"
path="res://.godot/imported/stalagmite.gltf-4c02b99ef3dda914e07f122e9a21af15.scn"
[deps]
source_file="res://models/stalagmite.gltf"
dest_files=["res://.godot/imported/stalagmite.gltf-4c02b99ef3dda914e07f122e9a21af15.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={
"materials": {
"material_0": {
"use_external/enabled": true,
"use_external/fallback_path": "res://materials/stalagmite.tres",
"use_external/path": "uid://bn423gccnsj5s"
}
},
"nodes": {
"PATH:mesh": {
"generate/physics": true
}
}
}
gltf/naming_version=2
gltf/embedded_image_handling=1

View file

@ -11,14 +11,62 @@ config_version=5
[application] [application]
config/name="Cave of Dreams" config/name="Cave of Dreams"
run/main_scene="uid://bxdnehietcpkj"
config/features=PackedStringArray("4.6", "Mobile") config/features=PackedStringArray("4.6", "Mobile")
config/icon="res://icon.svg" config/icon="res://icon.svg"
[editor_plugins]
enabled=PackedStringArray("res://addons/godot_super-wakatime/plugin.cfg")
[input]
move_left={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194319,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
move_right={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194321,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
move_up={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194320,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
move_down={
"deadzone": 0.2,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194322,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
jump={
"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":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
]
}
dodge={
"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)
]
}
[physics] [physics]
3d/physics_engine="Jolt Physics" 3d/physics_engine="Jolt Physics"
[rendering] [rendering]
textures/canvas_textures/default_texture_filter=0
rendering_device/driver.windows="d3d12" rendering_device/driver.windows="d3d12"
renderer/rendering_method="mobile" renderer/rendering_method="mobile"
lights_and_shadows/directional_shadow/size=2048
lights_and_shadows/directional_shadow/size.mobile=1024
lights_and_shadows/directional_shadow/soft_shadow_filter_quality=0
textures/decals/filter=0
textures/light_projectors/filter=0

399
scenes/game.tscn Normal file
View file

@ -0,0 +1,399 @@
[gd_scene format=3 uid="uid://bxdnehietcpkj"]
[ext_resource type="Script" uid="uid://crf3d7dpjvlsl" path="res://scripts/player_camera.gd" id="1_lnu2h"]
[ext_resource type="Script" uid="uid://66iq60cxqomg" path="res://scripts/player.gd" id="1_yqjtg"]
[ext_resource type="Texture2D" uid="uid://dp3jbqmr5toth" path="res://textures/character-body.png" id="3_p57ef"]
[ext_resource type="Texture2D" uid="uid://b6krbvbco0jt6" path="res://textures/shadow.png" id="4_lbhrr"]
[ext_resource type="Texture2D" uid="uid://3ptkafoafq14" path="res://textures/character-leg.png" id="4_u5sy4"]
[ext_resource type="PackedScene" uid="uid://b0kty7juk7rfo" path="res://models/stalagmite.gltf" id="5_iywne"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_lbhrr"]
albedo_color = Color(0.61, 0.28791997, 0.17079999, 1)
[sub_resource type="Environment" id="Environment_uwrxv"]
[sub_resource type="CameraAttributesPractical" id="CameraAttributesPractical_yqjtg"]
[sub_resource type="Animation" id="Animation_gee14"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Body/BackLeg:rotation")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Body/FrontLeg:rotation")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Body/FrontLeg:position")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0.045, -0.09000015, 0)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("Body/BackLeg:position")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(-0.044999994, -0.09000015, 0)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("Body:position")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("Body:rotation")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
[sub_resource type="Animation" id="Animation_u5sy4"]
resource_name = "fall"
length = 0.2
loop_mode = 1
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Body/FrontLeg:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0.045, -0.09000015, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Body/FrontLeg:rotation")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0.10471976)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Body/BackLeg:position")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(-0.044999994, -0.09000015, 0)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("Body/BackLeg:rotation")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0.10471976)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("Body:position")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("Body:rotation")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
[sub_resource type="Animation" id="Animation_p57ef"]
resource_name = "jump"
length = 0.2
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Body/FrontLeg:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.06666667, 0.15),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0.045, -0.09000015, 0), Vector3(-0.065, -0.045, 0), Vector3(0.045, -0.09000015, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Body/FrontLeg:rotation")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.06666667, 0.15),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, 0, 0.57072264), Vector3(0, 0, 0.10471976)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("Body/BackLeg:position")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0, 0.06666667, 0.15),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(-0.044999994, -0.09000015, 0), Vector3(-0.095, 0, 0), Vector3(-0.044999994, -0.09000015, 0)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("Body/BackLeg:rotation")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0, 0.06666667, 0.15),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(0, 0, 0.10471976)]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("Body:position")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0, 0.06666667, 0.15),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, -0.15, 0), Vector3(0, 0, 0)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("Body:rotation")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(0, 0.06666667, 0.15),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(0, 0, 0.06981317), Vector3(0, 0, 0)]
}
[sub_resource type="Animation" id="Animation_0tnpc"]
resource_name = "move"
loop_mode = 1
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Body/BackLeg:rotation")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.5, 1),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, -0.34906584), Vector3(0, 0, 0.34906584), Vector3(0, 0, -0.34906584)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Body/FrontLeg:rotation")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.5, 1),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(0, 0, 0.34906584), Vector3(0, 0, -0.34906584), Vector3(0, 0, 0.34906584)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_vtaks"]
_data = {
&"RESET": SubResource("Animation_gee14"),
&"fall": SubResource("Animation_u5sy4"),
&"jump": SubResource("Animation_p57ef"),
&"move": SubResource("Animation_0tnpc")
}
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_p57ef"]
animation = &"jump"
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_gee14"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_u5sy4"]
animation = &"fall"
[sub_resource type="AnimationNodeOneShot" id="AnimationNodeOneShot_u5sy4"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_gee14"]
animation = &"move"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_0tnpc"]
animation = &"RESET"
[sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_vtaks"]
[sub_resource type="AnimationNodeTimeScale" id="AnimationNodeTimeScale_p57ef"]
[sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_kvpfn"]
graph_offset = Vector2(-299.60645, 18.418121)
nodes/output/position = Vector2(1020, 160)
nodes/jump/node = SubResource("AnimationNodeOneShot_u5sy4")
nodes/jump/position = Vector2(680, 140)
nodes/reset/node = SubResource("AnimationNodeAnimation_0tnpc")
nodes/reset/position = Vector2(60, 20)
nodes/move/node = SubResource("AnimationNodeAnimation_gee14")
nodes/move/position = Vector2(-80, 220)
nodes/walk/node = SubResource("AnimationNodeBlend2_vtaks")
nodes/walk/position = Vector2(240, 80)
nodes/Animation/node = SubResource("AnimationNodeAnimation_p57ef")
nodes/Animation/position = Vector2(480, 360)
nodes/walk_speed/node = SubResource("AnimationNodeTimeScale_p57ef")
nodes/walk_speed/position = Vector2(80, 220)
nodes/fall/node = SubResource("AnimationNodeBlend2_gee14")
nodes/fall/position = Vector2(480, 100)
nodes/fall_anim/node = SubResource("AnimationNodeAnimation_u5sy4")
nodes/fall_anim/position = Vector2(260, 400)
node_connections = [&"output", 0, &"jump", &"jump", 0, &"fall", &"jump", 1, &"Animation", &"walk", 0, &"reset", &"walk", 1, &"walk_speed", &"walk_speed", 0, &"move", &"fall", 0, &"walk", &"fall", 1, &"fall_anim"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_yqjtg"]
radius = 0.25
height = 1.0
[node name="Game" type="Node3D" unique_id=1358608749]
[node name="CSGBox3D" type="CSGBox3D" parent="." unique_id=1781956012]
use_collision = true
size = Vector3(16, 1, 16)
material = SubResource("StandardMaterial3D_lbhrr")
[node name="PlayerCamera" type="Camera3D" parent="." unique_id=1101523944]
transform = Transform3D(0.70710677, -0.32650557, 0.62721133, 0, 0.8870108, 0.46174863, -0.70710677, -0.32650557, 0.62721133, 4, 6, 4)
environment = SubResource("Environment_uwrxv")
attributes = SubResource("CameraAttributesPractical_yqjtg")
fov = 70.0
script = ExtResource("1_lnu2h")
[node name="Player" type="CharacterBody3D" parent="." unique_id=1201448850]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0)
script = ExtResource("1_yqjtg")
[node name="DreamerBody" type="Node3D" parent="Player" unique_id=827683712]
[node name="Body" type="Sprite3D" parent="Player/DreamerBody" unique_id=2055611556]
pixel_size = 0.03
texture_filter = 0
render_priority = 2
texture = ExtResource("3_p57ef")
[node name="FrontLeg" type="Sprite3D" parent="Player/DreamerBody/Body" unique_id=1282701626]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.045, -0.09000015, 0)
offset = Vector2(-0.5, -10)
pixel_size = 0.03
texture_filter = 0
render_priority = 1
texture = ExtResource("4_u5sy4")
[node name="BackLeg" type="Sprite3D" parent="Player/DreamerBody/Body" unique_id=1621844440]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.044999994, -0.09000015, 0)
offset = Vector2(-0.5, -10)
pixel_size = 0.03
texture_filter = 0
texture = ExtResource("4_u5sy4")
[node name="Animations" type="AnimationPlayer" parent="Player/DreamerBody" unique_id=708762765]
libraries/ = SubResource("AnimationLibrary_vtaks")
[node name="Animator" type="AnimationTree" parent="Player/DreamerBody" unique_id=794846221]
tree_root = SubResource("AnimationNodeBlendTree_kvpfn")
anim_player = NodePath("../Animations")
parameters/jump/active = false
parameters/jump/internal_active = false
parameters/jump/request = 0
parameters/walk/blend_amount = 0.0
parameters/walk_speed/scale = 3.1400000000000006
parameters/fall/blend_amount = 0.0
[node name="Shadow" type="Sprite3D" parent="Player" unique_id=495232250]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -2, 0)
modulate = Color(1, 1, 1, 0.5764706)
pixel_size = 0.03
axis = 1
texture_filter = 0
texture = ExtResource("4_lbhrr")
[node name="Collision" type="CollisionShape3D" parent="Player" unique_id=1487040988]
shape = SubResource("CapsuleShape3D_yqjtg")
[node name="Floorcast" type="RayCast3D" parent="Player" unique_id=991770843]
target_position = Vector3(0, -16, 0)
[node name="Sun" type="DirectionalLight3D" parent="." unique_id=1000747668]
transform = Transform3D(5.337265e-08, 0.90171933, -0.4323222, -0.3453802, 0.40571806, 0.8462301, 0.93846303, 0.14931537, 0.31143594, 0, 0, 0)
shadow_enabled = true
[node name="blockbench_export" parent="." unique_id=1479648799 instance=ExtResource("5_iywne")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.48141205, 3)

57
scripts/player.gd Normal file
View file

@ -0,0 +1,57 @@
extends CharacterBody3D
const SPEED = 2.5
const JUMP_VELOCITY = 4.5
var walk_animation_time = 0
@onready var game = get_parent()
func _ready() -> void:
$DreamerBody.look_at(game.get_node("PlayerCamera").global_position)
$DreamerBody.rotation.x = 0
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity += get_gravity() * delta
if Input.is_action_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
$DreamerBody/Animator.set("parameters/jump/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE)
var input_dir := Input.get_vector("move_left", "move_right", "move_up", "move_down")
var direction := (transform.basis * Vector3(input_dir.y + input_dir.x, 0, input_dir.y - input_dir.x)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
$DreamerBody/Animator.set("parameters/walk/blend_amount", abs(direction.length()))
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
$DreamerBody/Animator.set("parameters/walk/blend_amount", 0)
if direction and is_on_floor():
walk_animation_time += delta * 25
$DreamerBody.position.y = sin(walk_animation_time + 1) / 8
$DreamerBody.rotation.z = sin(walk_animation_time / 2) / 16
else:
walk_animation_time = 0
$DreamerBody.rotation.z /= 1 + (delta * 2.5)
$DreamerBody.position.y /= 1 + (delta * 12)
if is_on_floor():
$DreamerBody/Animator.set("parameters/fall/blend_amount", 0)
else:
$DreamerBody/Animator.set("parameters/fall/blend_amount", 1)
move_and_slide()
$Shadow.global_position.y = $Floorcast.get_collision_point().y + 0.01

1
scripts/player.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://66iq60cxqomg

11
scripts/player_camera.gd Normal file
View file

@ -0,0 +1,11 @@
extends Camera3D
@onready var player = get_parent().get_node("Player")
@onready var offset = position - player.position
func _ready() -> void:
pass
func _process(delta: float) -> void:
var goal_position = player.global_position + offset
global_position += (goal_position - global_position) / (500 * delta)

View file

@ -0,0 +1 @@
uid://crf3d7dpjvlsl

BIN
textures/character-body.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B

View file

@ -0,0 +1,41 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dp3jbqmr5toth"
path.s3tc="res://.godot/imported/character-body.png-b4b3595119e895d1393a566f473773cc.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://textures/character-body.png"
dest_files=["res://.godot/imported/character-body.png-b4b3595119e895d1393a566f473773cc.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

BIN
textures/character-leg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

View file

@ -0,0 +1,41 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://3ptkafoafq14"
path.s3tc="res://.godot/imported/character-leg.png-435f124d74528e441bf58df30a6019be.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://textures/character-leg.png"
dest_files=["res://.godot/imported/character-leg.png-435f124d74528e441bf58df30a6019be.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://btqaj6yslgvax"
path="res://.godot/imported/example-character-hand.png-363b3285c631aacb16602f2b09024d62.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://textures/example-character-hand.png"
dest_files=["res://.godot/imported/example-character-hand.png-363b3285c631aacb16602f2b09024d62.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

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

View file

@ -0,0 +1,41 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://qatyqocle17x"
path.s3tc="res://.godot/imported/example-character-test.png-ffbe7ade23ee84b3d006d4c0e69d0525.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://textures/example-character-test.png"
dest_files=["res://.godot/imported/example-character-test.png-ffbe7ade23ee84b3d006d4c0e69d0525.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

BIN
textures/shadow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

View file

@ -0,0 +1,41 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b6krbvbco0jt6"
path.s3tc="res://.godot/imported/shadow.png-7612836bee885b8ff4de477fcb4dc22f.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://textures/shadow.png"
dest_files=["res://.godot/imported/shadow.png-7612836bee885b8ff4de477fcb4dc22f.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

BIN
textures/stalagmite.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,41 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://poepp7kmc5us"
path.s3tc="res://.godot/imported/stalagmite.png-8582147c49db821ce6dd503fc3ba7287.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://textures/stalagmite.png"
dest_files=["res://.godot/imported/stalagmite.png-8582147c49db821ce6dd503fc3ba7287.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