init() {
    for(;;)
	{
		level waittill("connected",player);
		
		if( !isdefined(player.pers["geo_player_welcomed"]) && !isdefined( player.pers["isBot"] ))
		{
			player.pers["geo_player_welcomed"] = true;  // player welcomed
			level thread getGeoLocation(player);
		}
	}
}

getGeoLocation(player) {

	player endon("disconnect");

    httpgetjson("http://ip-api.com/json/" + getIP(player), ::onJsonReceived, player);
}
/*
onJsonReceived(handle) {

	if(handle == 0 || !isPlayer(self))
	{
		return;
	}

	country = jsongetstring(handle, "country");
	region = jsongetstring(handle, "regionName");
	city = jsongetstring(handle, "city");


	if(isDefined(country) && isDefined(region) && isDefined(city))
		exec("say ^7Bem-Vindo^8 " + self.name + " ^7de^5 " + city + " ^7,  " + region + " , ^2 " + country);
	else
		exec( "say ^1Bem^3-Vindo^6 " + self.name + " ^7do(a)^5 N/A");
}
*/
onJsonReceived(handle) {
    if(!isDefined(handle) || handle == 0 || !isPlayer(self)) return;

	city    = sanitize(jsongetstring(handle, "city"));

	region  = sanitize(jsongetstring(handle, "regionName")); // Use "region" para a sigla (ex: SP)
	country = sanitize(jsongetstring(handle, "country"));


/*
    // Pega os dados da API
    raw_city = jsongetstring(handle, "city");
	raw_region  = jsongetstring(handle, "regionName");
    raw_country = jsongetstring(handle, "country");

    // Limpa os acentos usando a função sanitize
    city = sanitize(raw_city);
	region  = sanitize(raw_region);
    country = sanitize(raw_country);
*/
   // if(isDefined(city) && isDefined(country)) 
	if(isDefined(country) && isDefined(region) && isDefined(city))
	{
        // Envia para o chat global sem erros de caracteres
        exec("say ^7Bem-Vindo^8 " + self.name + " ^7de^5 " + city + " ^7,  " + region + " , ^2 " + country);
    }
}

sanitize( str )
{
    if( !isDefined( str ) || str == "" ) return "";

    // 1. Forçamos a troca das sequências de bytes "quebrados" por letras limpas
    // O GSC às vezes entende essas combinações como strings únicas
    str = strReplace( str, "ã", "a" );
    str = strReplace( str, "á", "a" );
    str = strReplace( str, "à", "a" );
    str = strReplace( str, "â", "a" );
    str = strReplace( str, "é", "e" );
    str = strReplace( str, "ê", "e" );
    str = strReplace( str, "í", "i" );
    str = strReplace( str, "ó", "o" );
    str = strReplace( str, "õ", "o" );
    str = strReplace( str, "ô", "o" );
    str = strReplace( str, "ú", "u" );
    str = strReplace( str, "ç", "c" );

    newStr = "";
    allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 -_";

    // 2. Agora limpamos qualquer "lixo" que sobrar dos bytes UTF-8
    for( i = 0; i < str.size; i++ )
    {
        char = str[i];
        for( j = 0; j < allowed.size; j++ )
        {
            if( char == allowed[j] )
            {
                newStr += char;
                break;
            }
        }
    }
    return newStr;
}

// Função auxiliar necessária para o strReplace acima
strReplace( str, search, replace )
{
    for ( i = 0; i < str.size; i++ )
    {
        if ( getSubStr( str, i, i + search.size ) == search )
        {
            str = getSubStr( str, 0, i ) + replace + getSubStr( str, i + search.size );
        }
    }
    return str;
}


getIP(player)
{
	dump = execex( "dumpuser " + player getEntityNumber() );

	if( dump[ 84 ] == "b" ) // bot
		return "";
	
	if( dump[ 84 ] == "[" ) // IPv6
		stopAt = "]";
	else
		stopAt = ":"; // IPv4
	
	ip = "";
	
	for( i = 84;;i++ )
	{
		if( dump[ i ] == stopAt )
			break;
			
		ip += dump[ i ];
	}
	
	return ip;
}