added server cleanup

This commit is contained in:
2ManyProjects 2025-02-16 13:51:46 -06:00
parent 221850654d
commit 1e42cf8ba2
7 changed files with 517 additions and 55 deletions

2
.gitignore vendored
View file

@ -15,3 +15,5 @@ Assets/ChessEngines/Fairy-Stockfish/*
Assets/ChessEngines/fairy-chess-server/* Assets/ChessEngines/fairy-chess-server/*
!Assets/ChessEngines/fairy-chess-server/*.js !Assets/ChessEngines/fairy-chess-server/*.js
!Assets/ChessEngines/fairy-chess-server/*.json !Assets/ChessEngines/fairy-chess-server/*.json
build/*

View file

@ -9,6 +9,9 @@ const port = 27531;
let board = null; let board = null;
let engine = null; let engine = null;
let isReady = false; let isReady = false;
let lastResponse = null
const SERVER_WAIT_THRESHOLD = 10 * 60 * 1000;
const CHECK_INTERVAL = 5000;
// Initialize ffish and engine // Initialize ffish and engine
ffish.onRuntimeInitialized = async () => { ffish.onRuntimeInitialized = async () => {
@ -29,6 +32,7 @@ ffish.onRuntimeInitialized = async () => {
engine.sendCommand('setoption name Threads value 4'); engine.sendCommand('setoption name Threads value 4');
engine.sendCommand('setoption name Hash value 128'); engine.sendCommand('setoption name Hash value 128');
engine.sendCommand('setoption name MultiPV value 1'); engine.sendCommand('setoption name MultiPV value 1');
engine.sendCommand('setoption name UCI_LimitStrength value true');
} }
} catch (error) { } catch (error) {
console.error('Initialization error:', error); console.error('Initialization error:', error);
@ -39,6 +43,7 @@ app.use(express.json());
// Health check endpoint // Health check endpoint
app.get('/health', (req, res) => { app.get('/health', (req, res) => {
lastResponse = new Date().getTime()
res.json({ res.json({
status: 'ok', status: 'ok',
engineReady: isReady && engine && engine.isReady, 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 // Validate FEN endpoint
app.post('/validate', (req, res) => { app.post('/validate', (req, res) => {
lastResponse = new Date().getTime()
const { fen, variant = 'chess' } = req.body; const { fen, variant = 'chess' } = req.body;
if (!fen) { if (!fen) {
@ -73,6 +117,7 @@ app.post('/validate', (req, res) => {
// New game endpoint // New game endpoint
app.post('/new', (req, res) => { app.post('/new', (req, res) => {
lastResponse = new Date().getTime()
const { variant = 'chess' } = req.body; const { variant = 'chess' } = req.body;
try { try {
@ -98,6 +143,7 @@ app.post('/new', (req, res) => {
// Set position endpoint // Set position endpoint
app.post('/position', (req, res) => { app.post('/position', (req, res) => {
lastResponse = new Date().getTime()
const { fen, variant = 'chess' } = req.body; const { fen, variant = 'chess' } = req.body;
if (!fen) { if (!fen) {
@ -139,6 +185,7 @@ app.post('/position', (req, res) => {
// Make move endpoint // Make move endpoint
app.post('/move', (req, res) => { app.post('/move', (req, res) => {
lastResponse = new Date().getTime()
const { move, notation = 'uci', variant = 'chess' } = req.body; const { move, notation = 'uci', variant = 'chess' } = req.body;
if (!board) { if (!board) {
@ -192,6 +239,7 @@ app.post('/move', (req, res) => {
// State endpoint // State endpoint
app.get('/state', (req, res) => { app.get('/state', (req, res) => {
lastResponse = new Date().getTime()
if (!board) { if (!board) {
return res.status(400).json({ error: 'No active board' }); return res.status(400).json({ error: 'No active board' });
} }
@ -218,6 +266,7 @@ app.get('/state', (req, res) => {
// Analysis endpoint // Analysis endpoint
app.post('/analyze', async (req, res) => { app.post('/analyze', async (req, res) => {
lastResponse = new Date().getTime()
if (!board) { if (!board) {
return res.status(400).json({ error: 'No active board' }); return res.status(400).json({ error: 'No active board' });
} }
@ -257,6 +306,7 @@ app.post('/analyze', async (req, res) => {
// Engine move endpoint // Engine move endpoint
app.post('/enginemove', async (req, res) => { app.post('/enginemove', async (req, res) => {
lastResponse = new Date().getTime()
if (!board) { if (!board) {
return res.status(400).json({ error: 'No active 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) => { app.post('/shutdown', (req, res) => {
lastResponse = new Date().getTime()
res.json({ status: 'shutting_down' }); res.json({ status: 'shutting_down' });
// Give time for response to be sent // Give time for response to be sent
setTimeout(() => { setTimeout(() => {
if (board) board.delete(); closeServer()
if (engine) engine.quit();
process.exit(0);
}, 100); }, 100);
}); });
// 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);
}

View file

@ -114,12 +114,15 @@ async function testServer() {
console.log('Custom analysis:', customAnalysis.data); console.log('Custom analysis:', customAnalysis.data);
// Test 14: Final State Check // 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`); const finalHealth = await axios.get(`${baseURL}/health`);
console.log('Final server status:', { console.log('Final server status:', {
engineReady: finalHealth.data.engineReady, engineReady: finalHealth.data.engineReady,
status: finalHealth.data.status status: finalHealth.data.status
}); });
console.log('\nTest 15: SHUTDOWN');
await axios.post(`${baseURL}/shutdown`);
console.log('\nAll tests completed successfully!'); console.log('\nAll tests completed successfully!');

View file

@ -10,10 +10,13 @@ func _ready():
# Get the path to the server directory relative to the project # Get the path to the server directory relative to the project
server_path = ProjectSettings.globalize_path("res://Assets/ChessEngines/fairy-chess-server") server_path = ProjectSettings.globalize_path("res://Assets/ChessEngines/fairy-chess-server")
start_server() start_server()
get_tree().set_auto_accept_quit(false)
func _exit_tree(): func _exit_tree():
stop_server() stop_server()
func _notification(what):
if what == NOTIFICATION_WM_CLOSE_REQUEST:
stop_server()
func start_server() -> bool: func start_server() -> bool:
if running: if running:
return true return true
@ -44,25 +47,27 @@ func start_server() -> bool:
# printerr("Failed to start server: ", output) # printerr("Failed to start server: ", output)
# return false # return false
running = true
return true return true
func _on_init_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray): func _on_init_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray):
print("*****************_on_init_request_completed************")
var json = JSON.new() var json = JSON.new()
json.parse(body.get_string_from_utf8()) json.parse(body.get_string_from_utf8())
var response = json.get_data() var response = json.get_data()
# Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org). # Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org).
print(response) print(response)
if result != HTTPRequest.RESULT_SUCCESS: if response == null and result != HTTPRequest.RESULT_SUCCESS:
print("HTTP Request failed") print("HTTP Request failed")
server_process_id = OS.create_process("node", [server_path + "/index.js"]) server_process_id = OS.create_process("node", [server_path + "/index.js"])
if server_process_id <= 0: if server_process_id <= 0:
printerr("Failed to start server") printerr("Failed to start server")
return false return false
running = true
print("Chess server started") print("Chess server started")
return return
running = true
if response.status != "ok": if response.status != "ok":
print("Server error : ", response_code, json.parse(body.get_string_from_utf8()),) print("Server error : ", response_code, json.parse(body.get_string_from_utf8()),)
return return
@ -74,23 +79,13 @@ func stop_server():
print("Stopping chess server...") print("Stopping chess server...")
# Send a stop request to the server # Send a stop request to the server
var headers = ["Content-Type: application/json"]
var http = HTTPClient.new() var http = HTTPClient.new()
var err = http.connect_to_host("localhost", 27531) var data = JSON.stringify({"command": "shutdown"})
if err == OK: http.request(HTTPClient.METHOD_POST, "/shutdown", headers, data)
# 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)
running = false running = false
print("Chess server stopped") print("Chess server stopped")
func is_server_running() -> bool: func is_server_running() -> bool:
if not running: return 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

View file

@ -71,8 +71,8 @@ func load_fen(fen: String):
if not running: if not running:
return return
# var http_request = HTTPRequest.new() # var http_request = HTTPRequest.new()
# add_child(http_request) # add_child(http_request)
# http_request.request_completed.connect(self._on_request_completed) # http_request.request_completed.connect(self._on_request_completed)
var headers = ["Content-Type: application/json"] var headers = ["Content-Type: application/json"]
var body = JSON.new().stringify({ var body = JSON.new().stringify({
"fen": fen "fen": fen
@ -81,7 +81,7 @@ func load_fen(fen: String):
print(body) print(body)
http_request.request(server_url + "/position", headers, HTTPClient.METHOD_POST, body) http_request.request(server_url + "/position", headers, HTTPClient.METHOD_POST, body)
await http_request.request_completed
func start_board(): func start_board():
if not running: if not running:
return return
@ -92,11 +92,47 @@ func start_board():
print(server_url + "/new") print(server_url + "/new")
print(body) print(body)
http_request.request(server_url + "/new", headers, HTTPClient.METHOD_POST, 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): func update_position(fen: String):
load_fen(fen) 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: func generateMove(think_time_ms: int = 1000) -> void:
if not running: if not running:
return return
@ -203,13 +239,4 @@ func _on_request_completed(result: int, response_code: int, headers: PackedStrin
if response.status != "ok": if response.status != "ok":
print("Server error:", response_code, json.parse(body.get_string_from_utf8()),) print("Server error:", response_code, json.parse(body.get_string_from_utf8()),)
return 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

354
export_presets.cfg Normal file
View file

@ -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}\""

View file

@ -34,4 +34,6 @@ import/blender/enabled=false
[rendering] [rendering]
renderer/rendering_method="mobile" renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"
textures/vram_compression/import_etc2_astc=true