diff --git a/.gitignore b/.gitignore index a01ec56..488f0d9 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ Assets/ChessEngines/Fairy-Stockfish/* Assets/ChessEngines/fairy-chess-server/* !Assets/ChessEngines/fairy-chess-server/*.js !Assets/ChessEngines/fairy-chess-server/*.json + +build/* \ No newline at end of file diff --git a/Assets/ChessEngines/fairy-chess-server/index.js b/Assets/ChessEngines/fairy-chess-server/index.js index 920d81a..2b38636 100644 --- a/Assets/ChessEngines/fairy-chess-server/index.js +++ b/Assets/ChessEngines/fairy-chess-server/index.js @@ -9,6 +9,9 @@ const port = 27531; let board = null; let engine = null; let isReady = false; +let lastResponse = null +const SERVER_WAIT_THRESHOLD = 10 * 60 * 1000; +const CHECK_INTERVAL = 5000; // Initialize ffish and engine ffish.onRuntimeInitialized = async () => { @@ -29,6 +32,7 @@ ffish.onRuntimeInitialized = async () => { engine.sendCommand('setoption name Threads value 4'); engine.sendCommand('setoption name Hash value 128'); engine.sendCommand('setoption name MultiPV value 1'); + engine.sendCommand('setoption name UCI_LimitStrength value true'); } } catch (error) { console.error('Initialization error:', error); @@ -39,6 +43,7 @@ app.use(express.json()); // Health check endpoint app.get('/health', (req, res) => { + lastResponse = new Date().getTime() res.json({ status: 'ok', engineReady: isReady && engine && engine.isReady, @@ -48,8 +53,47 @@ app.get('/health', (req, res) => { }); }); + + +// Set Options +app.post('/setoptions', (req, res) => { + lastResponse = new Date().getTime() + const { name, value, options } = req.body; + if(name && value !== null){ + engine.sendCommand(`setoption name ${name} value ${value}`); + res.json({ + status: 'ok', + success: name, + errs: null, + }); + }else if(options && Array.isArray(options)){ + let success = []; + let errs = []; + for(let x = 0; x < options.length; x++){ + let option = options[x]; + const {name, value} = option; + if(name && value !== null ){ + engine.sendCommand(`setoption name ${name} value ${value}`); + success.push(name) + }else { + errs.push(name) + } + } + res.json({ + status: 'ok', + success: success, + errs: errs, + }); + }else { + return res.status(400).json({ error: 'No Params Provided' }); + } + + +}); + // Validate FEN endpoint app.post('/validate', (req, res) => { + lastResponse = new Date().getTime() const { fen, variant = 'chess' } = req.body; if (!fen) { @@ -73,6 +117,7 @@ app.post('/validate', (req, res) => { // New game endpoint app.post('/new', (req, res) => { + lastResponse = new Date().getTime() const { variant = 'chess' } = req.body; try { @@ -98,6 +143,7 @@ app.post('/new', (req, res) => { // Set position endpoint app.post('/position', (req, res) => { + lastResponse = new Date().getTime() const { fen, variant = 'chess' } = req.body; if (!fen) { @@ -139,6 +185,7 @@ app.post('/position', (req, res) => { // Make move endpoint app.post('/move', (req, res) => { + lastResponse = new Date().getTime() const { move, notation = 'uci', variant = 'chess' } = req.body; if (!board) { @@ -192,6 +239,7 @@ app.post('/move', (req, res) => { // State endpoint app.get('/state', (req, res) => { + lastResponse = new Date().getTime() if (!board) { return res.status(400).json({ error: 'No active board' }); } @@ -218,6 +266,7 @@ app.get('/state', (req, res) => { // Analysis endpoint app.post('/analyze', async (req, res) => { + lastResponse = new Date().getTime() if (!board) { return res.status(400).json({ error: 'No active board' }); } @@ -257,6 +306,7 @@ app.post('/analyze', async (req, res) => { // Engine move endpoint app.post('/enginemove', async (req, res) => { + lastResponse = new Date().getTime() if (!board) { return res.status(400).json({ error: 'No active board' }); } @@ -304,32 +354,61 @@ app.post('/enginemove', async (req, res) => { } }); -// Cleanup handling -process.on('SIGTERM', () => { - console.log('Shutting down...'); - if (board) board.delete(); - if (engine) engine.quit(); - process.exit(0); -}); - -process.on('SIGINT', () => { - console.log('Received SIGINT, shutting down...'); - if (board) board.delete(); - if (engine) engine.quit(); - process.exit(0); -}); - -app.listen(port, () => { - console.log(`Fairy-Chess server running on port ${port}`); -}); app.post('/shutdown', (req, res) => { + lastResponse = new Date().getTime() res.json({ status: 'shutting_down' }); // Give time for response to be sent setTimeout(() => { - if (board) board.delete(); - if (engine) engine.quit(); - process.exit(0); + closeServer() }, 100); -}); \ No newline at end of file +}); + +// Cleanup handling +process.on('SIGTERM', () => { + console.log('Shutting down...'); + closeServer() +}); + +process.on('SIGINT', () => { + console.log('Received SIGINT, shutting down...'); + closeServer() +}); + +app.listen(port, () => { + startIdleMonitor(); + console.log(`Fairy-Chess server running on port ${port}`); +}); + +function startIdleMonitor() { + const checkIdle = () => { + const currentTime = new Date().getTime(); + const timeSinceLastResponse = currentTime - lastResponse; + + if (timeSinceLastResponse > SERVER_WAIT_THRESHOLD) { + console.log(`Server idle for ${timeSinceLastResponse/1000} seconds. Shutting down...`); + closeServer(); + } + }; + + // Start the monitoring interval + const monitorInterval = setInterval(checkIdle, CHECK_INTERVAL); + + // Clean up interval on server close + process.on('SIGTERM', () => { + clearInterval(monitorInterval); + closeServer(); + }); + + process.on('SIGINT', () => { + clearInterval(monitorInterval); + closeServer(); + }); +} + +function closeServer(){ + if (board) board.delete(); + if (engine) engine.quit(); + process.exit(0); +} \ No newline at end of file diff --git a/Assets/ChessEngines/fairy-chess-server/test.js b/Assets/ChessEngines/fairy-chess-server/test.js index 5caae13..d04bbc3 100644 --- a/Assets/ChessEngines/fairy-chess-server/test.js +++ b/Assets/ChessEngines/fairy-chess-server/test.js @@ -114,12 +114,15 @@ async function testServer() { console.log('Custom analysis:', customAnalysis.data); // Test 14: Final State Check - console.log('\nTest 14: Final State Check'); + console.log('\nTest 14: State Check'); const finalHealth = await axios.get(`${baseURL}/health`); console.log('Final server status:', { engineReady: finalHealth.data.engineReady, status: finalHealth.data.status }); + console.log('\nTest 15: SHUTDOWN'); + await axios.post(`${baseURL}/shutdown`); + console.log('\nAll tests completed successfully!'); diff --git a/Systems/FairyStockfish/ServerManager.gd b/Systems/FairyStockfish/ServerManager.gd index b45066c..2d3f7ef 100644 --- a/Systems/FairyStockfish/ServerManager.gd +++ b/Systems/FairyStockfish/ServerManager.gd @@ -10,10 +10,13 @@ func _ready(): # Get the path to the server directory relative to the project server_path = ProjectSettings.globalize_path("res://Assets/ChessEngines/fairy-chess-server") start_server() + get_tree().set_auto_accept_quit(false) func _exit_tree(): stop_server() - +func _notification(what): + if what == NOTIFICATION_WM_CLOSE_REQUEST: + stop_server() func start_server() -> bool: if running: return true @@ -44,25 +47,27 @@ func start_server() -> bool: # printerr("Failed to start server: ", output) # return false - running = true return true func _on_init_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray): + print("*****************_on_init_request_completed************") var json = JSON.new() json.parse(body.get_string_from_utf8()) var response = json.get_data() # Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org). print(response) - if result != HTTPRequest.RESULT_SUCCESS: + if response == null and result != HTTPRequest.RESULT_SUCCESS: print("HTTP Request failed") server_process_id = OS.create_process("node", [server_path + "/index.js"]) if server_process_id <= 0: printerr("Failed to start server") return false + + running = true print("Chess server started") return - + running = true if response.status != "ok": print("Server error : ", response_code, json.parse(body.get_string_from_utf8()),) return @@ -74,23 +79,13 @@ func stop_server(): print("Stopping chess server...") # Send a stop request to the server + var headers = ["Content-Type: application/json"] var http = HTTPClient.new() - var err = http.connect_to_host("localhost", 27531) - if err == OK: - # Send a POST request to a shutdown endpoint - var headers = ["Content-Type: application/json"] - var data = JSON.stringify({"command": "shutdown"}) - http.request(HTTPClient.METHOD_POST, "/shutdown", headers, data) + var data = JSON.stringify({"command": "shutdown"}) + http.request(HTTPClient.METHOD_POST, "/shutdown", headers, data) running = false print("Chess server stopped") func is_server_running() -> bool: - if not running: - return false - - # Try to connect to the server - var http = HTTPClient.new() - var err = http.connect_to_host("localhost", 27531) - print("is_server_running", err, OK) - return err == OK \ No newline at end of file + return running \ No newline at end of file diff --git a/Systems/FairyStockfish/StockfishClient.gd b/Systems/FairyStockfish/StockfishClient.gd index bf68ef5..6b93872 100644 --- a/Systems/FairyStockfish/StockfishClient.gd +++ b/Systems/FairyStockfish/StockfishClient.gd @@ -71,8 +71,8 @@ func load_fen(fen: String): if not running: return # var http_request = HTTPRequest.new() - # add_child(http_request) - # http_request.request_completed.connect(self._on_request_completed) + # add_child(http_request) + # http_request.request_completed.connect(self._on_request_completed) var headers = ["Content-Type: application/json"] var body = JSON.new().stringify({ "fen": fen @@ -81,7 +81,7 @@ func load_fen(fen: String): print(body) http_request.request(server_url + "/position", headers, HTTPClient.METHOD_POST, body) - + await http_request.request_completed func start_board(): if not running: return @@ -92,11 +92,47 @@ func start_board(): print(server_url + "/new") print(body) http_request.request(server_url + "/new", headers, HTTPClient.METHOD_POST, body) + await http_request.request_completed + setElo(1350) +func _exit_tree(): + ServerManager.stop_server() + disconnect_engine(); + func update_position(fen: String): load_fen(fen) +func setElo(elo: int = 1350) -> void: + if not running: + return + var headers = ["Content-Type: application/json"] + var data = { + "options": [ + { + "name": "UCI_LimitStrength", + "value": "true" + }, + { + "name": "UCI_Elo", + "value": str(elo) # Convert int to string + } + ] + } + + var body = JSON.new().stringify(data) + + # Request engine move + var elo_req = HTTPRequest.new() + add_child(elo_req) + elo_req.request_completed.connect(self._on_request_completed) + elo_req.request( + server_url + "/setoptions", + headers, + HTTPClient.METHOD_POST, + body + ) + func generateMove(think_time_ms: int = 1000) -> void: if not running: return @@ -203,13 +239,4 @@ func _on_request_completed(result: int, response_code: int, headers: PackedStrin if response.status != "ok": print("Server error:", response_code, json.parse(body.get_string_from_utf8()),) return - - - # Handle different response types - if "bestMove" in response: - generated_move = { - "move": response.bestMove, - "ponder": response.get("ponderMove", "") - } - - # You can add more response handling here \ No newline at end of file + diff --git a/export_presets.cfg b/export_presets.cfg new file mode 100644 index 0000000..0377624 --- /dev/null +++ b/export_presets.cfg @@ -0,0 +1,354 @@ +[preset.0] + +name="Linux" +platform="Linux" +runnable=true +advanced_options=false +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="build/Linux/ChessBuilder.x86_64" +encryption_include_filters="" +encryption_exclude_filters="" +encrypt_pck=false +encrypt_directory=false +script_export_mode=2 + +[preset.0.options] + +custom_template/debug="" +custom_template/release="" +debug/export_console_wrapper=1 +binary_format/embed_pck=false +texture_format/s3tc_bptc=true +texture_format/etc2_astc=false +binary_format/architecture="x86_64" +ssh_remote_deploy/enabled=false +ssh_remote_deploy/host="user@host_ip" +ssh_remote_deploy/port="22" +ssh_remote_deploy/extra_args_ssh="" +ssh_remote_deploy/extra_args_scp="" +ssh_remote_deploy/run_script="#!/usr/bin/env bash +export DISPLAY=:0 +unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\" +\"{temp_dir}/{exe_name}\" {cmd_args}" +ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash +kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\") +rm -rf \"{temp_dir}\"" + +[preset.1] + +name="Windows Desktop" +platform="Windows Desktop" +runnable=true +advanced_options=true +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="build/Windows/ChessBuilder.exe" +encryption_include_filters="" +encryption_exclude_filters="" +encrypt_pck=false +encrypt_directory=false +script_export_mode=2 + +[preset.1.options] + +custom_template/debug="" +custom_template/release="" +debug/export_console_wrapper=1 +binary_format/embed_pck=false +texture_format/s3tc_bptc=true +texture_format/etc2_astc=false +binary_format/architecture="x86_64" +codesign/enable=false +codesign/timestamp=true +codesign/timestamp_server_url="" +codesign/digest_algorithm=1 +codesign/description="" +codesign/custom_options=PackedStringArray() +application/modify_resources=false +application/icon="" +application/console_wrapper_icon="" +application/icon_interpolation=4 +application/file_version="" +application/product_version="" +application/company_name="" +application/product_name="" +application/file_description="" +application/copyright="" +application/trademarks="" +application/export_angle=0 +application/export_d3d12=0 +application/d3d12_agility_sdk_multiarch=true +ssh_remote_deploy/enabled=false +ssh_remote_deploy/host="user@host_ip" +ssh_remote_deploy/port="22" +ssh_remote_deploy/extra_args_ssh="" +ssh_remote_deploy/extra_args_scp="" +ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}' +$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}' +$trigger = New-ScheduledTaskTrigger -Once -At 00:00 +$settings = New-ScheduledTaskSettingsSet +$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings +Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true +Start-ScheduledTask -TaskName godot_remote_debug +while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 } +Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue" +ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue +Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue +Remove-Item -Recurse -Force '{temp_dir}'" + +[preset.2] + +name="macOS" +platform="macOS" +runnable=true +advanced_options=false +dedicated_server=false +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="" +encryption_include_filters="" +encryption_exclude_filters="" +encrypt_pck=false +encrypt_directory=false +script_export_mode=2 + +[preset.2.options] + +export/distribution_type=1 +binary_format/architecture="universal" +custom_template/debug="" +custom_template/release="" +debug/export_console_wrapper=1 +application/icon="" +application/icon_interpolation=4 +application/bundle_identifier="com.chessbuilder.game" +application/signature="" +application/app_category="Games" +application/short_version="" +application/version="" +application/copyright="" +application/copyright_localized={} +application/min_macos_version="10.12" +application/export_angle=0 +display/high_res=true +application/additional_plist_content="" +xcode/platform_build="14C18" +xcode/sdk_version="13.1" +xcode/sdk_build="22C55" +xcode/sdk_name="macosx13.1" +xcode/xcode_version="1420" +xcode/xcode_build="14C18" +codesign/codesign=1 +codesign/installer_identity="" +codesign/apple_team_id="" +codesign/identity="" +codesign/entitlements/custom_file="" +codesign/entitlements/allow_jit_code_execution=false +codesign/entitlements/allow_unsigned_executable_memory=false +codesign/entitlements/allow_dyld_environment_variables=false +codesign/entitlements/disable_library_validation=false +codesign/entitlements/audio_input=false +codesign/entitlements/camera=false +codesign/entitlements/location=false +codesign/entitlements/address_book=false +codesign/entitlements/calendars=false +codesign/entitlements/photos_library=false +codesign/entitlements/apple_events=false +codesign/entitlements/debugging=false +codesign/entitlements/app_sandbox/enabled=false +codesign/entitlements/app_sandbox/network_server=false +codesign/entitlements/app_sandbox/network_client=false +codesign/entitlements/app_sandbox/device_usb=false +codesign/entitlements/app_sandbox/device_bluetooth=false +codesign/entitlements/app_sandbox/files_downloads=0 +codesign/entitlements/app_sandbox/files_pictures=0 +codesign/entitlements/app_sandbox/files_music=0 +codesign/entitlements/app_sandbox/files_movies=0 +codesign/entitlements/app_sandbox/files_user_selected=0 +codesign/entitlements/app_sandbox/helper_executables=[] +codesign/custom_options=PackedStringArray() +notarization/notarization=0 +privacy/microphone_usage_description="" +privacy/microphone_usage_description_localized={} +privacy/camera_usage_description="" +privacy/camera_usage_description_localized={} +privacy/location_usage_description="" +privacy/location_usage_description_localized={} +privacy/address_book_usage_description="" +privacy/address_book_usage_description_localized={} +privacy/calendar_usage_description="" +privacy/calendar_usage_description_localized={} +privacy/photos_library_usage_description="" +privacy/photos_library_usage_description_localized={} +privacy/desktop_folder_usage_description="" +privacy/desktop_folder_usage_description_localized={} +privacy/documents_folder_usage_description="" +privacy/documents_folder_usage_description_localized={} +privacy/downloads_folder_usage_description="" +privacy/downloads_folder_usage_description_localized={} +privacy/network_volumes_usage_description="" +privacy/network_volumes_usage_description_localized={} +privacy/removable_volumes_usage_description="" +privacy/removable_volumes_usage_description_localized={} +privacy/tracking_enabled=false +privacy/tracking_domains=PackedStringArray() +privacy/collected_data/name/collected=false +privacy/collected_data/name/linked_to_user=false +privacy/collected_data/name/used_for_tracking=false +privacy/collected_data/name/collection_purposes=0 +privacy/collected_data/email_address/collected=false +privacy/collected_data/email_address/linked_to_user=false +privacy/collected_data/email_address/used_for_tracking=false +privacy/collected_data/email_address/collection_purposes=0 +privacy/collected_data/phone_number/collected=false +privacy/collected_data/phone_number/linked_to_user=false +privacy/collected_data/phone_number/used_for_tracking=false +privacy/collected_data/phone_number/collection_purposes=0 +privacy/collected_data/physical_address/collected=false +privacy/collected_data/physical_address/linked_to_user=false +privacy/collected_data/physical_address/used_for_tracking=false +privacy/collected_data/physical_address/collection_purposes=0 +privacy/collected_data/other_contact_info/collected=false +privacy/collected_data/other_contact_info/linked_to_user=false +privacy/collected_data/other_contact_info/used_for_tracking=false +privacy/collected_data/other_contact_info/collection_purposes=0 +privacy/collected_data/health/collected=false +privacy/collected_data/health/linked_to_user=false +privacy/collected_data/health/used_for_tracking=false +privacy/collected_data/health/collection_purposes=0 +privacy/collected_data/fitness/collected=false +privacy/collected_data/fitness/linked_to_user=false +privacy/collected_data/fitness/used_for_tracking=false +privacy/collected_data/fitness/collection_purposes=0 +privacy/collected_data/payment_info/collected=false +privacy/collected_data/payment_info/linked_to_user=false +privacy/collected_data/payment_info/used_for_tracking=false +privacy/collected_data/payment_info/collection_purposes=0 +privacy/collected_data/credit_info/collected=false +privacy/collected_data/credit_info/linked_to_user=false +privacy/collected_data/credit_info/used_for_tracking=false +privacy/collected_data/credit_info/collection_purposes=0 +privacy/collected_data/other_financial_info/collected=false +privacy/collected_data/other_financial_info/linked_to_user=false +privacy/collected_data/other_financial_info/used_for_tracking=false +privacy/collected_data/other_financial_info/collection_purposes=0 +privacy/collected_data/precise_location/collected=false +privacy/collected_data/precise_location/linked_to_user=false +privacy/collected_data/precise_location/used_for_tracking=false +privacy/collected_data/precise_location/collection_purposes=0 +privacy/collected_data/coarse_location/collected=false +privacy/collected_data/coarse_location/linked_to_user=false +privacy/collected_data/coarse_location/used_for_tracking=false +privacy/collected_data/coarse_location/collection_purposes=0 +privacy/collected_data/sensitive_info/collected=false +privacy/collected_data/sensitive_info/linked_to_user=false +privacy/collected_data/sensitive_info/used_for_tracking=false +privacy/collected_data/sensitive_info/collection_purposes=0 +privacy/collected_data/contacts/collected=false +privacy/collected_data/contacts/linked_to_user=false +privacy/collected_data/contacts/used_for_tracking=false +privacy/collected_data/contacts/collection_purposes=0 +privacy/collected_data/emails_or_text_messages/collected=false +privacy/collected_data/emails_or_text_messages/linked_to_user=false +privacy/collected_data/emails_or_text_messages/used_for_tracking=false +privacy/collected_data/emails_or_text_messages/collection_purposes=0 +privacy/collected_data/photos_or_videos/collected=false +privacy/collected_data/photos_or_videos/linked_to_user=false +privacy/collected_data/photos_or_videos/used_for_tracking=false +privacy/collected_data/photos_or_videos/collection_purposes=0 +privacy/collected_data/audio_data/collected=false +privacy/collected_data/audio_data/linked_to_user=false +privacy/collected_data/audio_data/used_for_tracking=false +privacy/collected_data/audio_data/collection_purposes=0 +privacy/collected_data/gameplay_content/collected=false +privacy/collected_data/gameplay_content/linked_to_user=false +privacy/collected_data/gameplay_content/used_for_tracking=false +privacy/collected_data/gameplay_content/collection_purposes=0 +privacy/collected_data/customer_support/collected=false +privacy/collected_data/customer_support/linked_to_user=false +privacy/collected_data/customer_support/used_for_tracking=false +privacy/collected_data/customer_support/collection_purposes=0 +privacy/collected_data/other_user_content/collected=false +privacy/collected_data/other_user_content/linked_to_user=false +privacy/collected_data/other_user_content/used_for_tracking=false +privacy/collected_data/other_user_content/collection_purposes=0 +privacy/collected_data/browsing_history/collected=false +privacy/collected_data/browsing_history/linked_to_user=false +privacy/collected_data/browsing_history/used_for_tracking=false +privacy/collected_data/browsing_history/collection_purposes=0 +privacy/collected_data/search_hhistory/collected=false +privacy/collected_data/search_hhistory/linked_to_user=false +privacy/collected_data/search_hhistory/used_for_tracking=false +privacy/collected_data/search_hhistory/collection_purposes=0 +privacy/collected_data/user_id/collected=false +privacy/collected_data/user_id/linked_to_user=false +privacy/collected_data/user_id/used_for_tracking=false +privacy/collected_data/user_id/collection_purposes=0 +privacy/collected_data/device_id/collected=false +privacy/collected_data/device_id/linked_to_user=false +privacy/collected_data/device_id/used_for_tracking=false +privacy/collected_data/device_id/collection_purposes=0 +privacy/collected_data/purchase_history/collected=false +privacy/collected_data/purchase_history/linked_to_user=false +privacy/collected_data/purchase_history/used_for_tracking=false +privacy/collected_data/purchase_history/collection_purposes=0 +privacy/collected_data/product_interaction/collected=false +privacy/collected_data/product_interaction/linked_to_user=false +privacy/collected_data/product_interaction/used_for_tracking=false +privacy/collected_data/product_interaction/collection_purposes=0 +privacy/collected_data/advertising_data/collected=false +privacy/collected_data/advertising_data/linked_to_user=false +privacy/collected_data/advertising_data/used_for_tracking=false +privacy/collected_data/advertising_data/collection_purposes=0 +privacy/collected_data/other_usage_data/collected=false +privacy/collected_data/other_usage_data/linked_to_user=false +privacy/collected_data/other_usage_data/used_for_tracking=false +privacy/collected_data/other_usage_data/collection_purposes=0 +privacy/collected_data/crash_data/collected=false +privacy/collected_data/crash_data/linked_to_user=false +privacy/collected_data/crash_data/used_for_tracking=false +privacy/collected_data/crash_data/collection_purposes=0 +privacy/collected_data/performance_data/collected=false +privacy/collected_data/performance_data/linked_to_user=false +privacy/collected_data/performance_data/used_for_tracking=false +privacy/collected_data/performance_data/collection_purposes=0 +privacy/collected_data/other_diagnostic_data/collected=false +privacy/collected_data/other_diagnostic_data/linked_to_user=false +privacy/collected_data/other_diagnostic_data/used_for_tracking=false +privacy/collected_data/other_diagnostic_data/collection_purposes=0 +privacy/collected_data/environment_scanning/collected=false +privacy/collected_data/environment_scanning/linked_to_user=false +privacy/collected_data/environment_scanning/used_for_tracking=false +privacy/collected_data/environment_scanning/collection_purposes=0 +privacy/collected_data/hands/collected=false +privacy/collected_data/hands/linked_to_user=false +privacy/collected_data/hands/used_for_tracking=false +privacy/collected_data/hands/collection_purposes=0 +privacy/collected_data/head/collected=false +privacy/collected_data/head/linked_to_user=false +privacy/collected_data/head/used_for_tracking=false +privacy/collected_data/head/collection_purposes=0 +privacy/collected_data/other_data_types/collected=false +privacy/collected_data/other_data_types/linked_to_user=false +privacy/collected_data/other_data_types/used_for_tracking=false +privacy/collected_data/other_data_types/collection_purposes=0 +ssh_remote_deploy/enabled=false +ssh_remote_deploy/host="user@host_ip" +ssh_remote_deploy/port="22" +ssh_remote_deploy/extra_args_ssh="" +ssh_remote_deploy/extra_args_scp="" +ssh_remote_deploy/run_script="#!/usr/bin/env bash +unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\" +open \"{temp_dir}/{exe_name}.app\" --args {cmd_args}" +ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash +kill $(pgrep -x -f \"{temp_dir}/{exe_name}.app/Contents/MacOS/{exe_name} {cmd_args}\") +rm -rf \"{temp_dir}\"" diff --git a/project.godot b/project.godot index 2171d21..400a1f7 100644 --- a/project.godot +++ b/project.godot @@ -34,4 +34,6 @@ import/blender/enabled=false [rendering] -renderer/rendering_method="mobile" +renderer/rendering_method="gl_compatibility" +renderer/rendering_method.mobile="gl_compatibility" +textures/vram_compression/import_etc2_astc=true