Sasyia
Member
- Joined
- Mar 9, 2020
- Messages
- 42
- Solutions
- 3
- Reaction score
- 20
Hello,
Im getting error "Login failed. Tibia might be down for maintenance. Please try again later." when trying to connect to local server. Im using TFS 1.3
My ZNOTTE login.php:
Any help/ideas will be appreciated,
Thanks
Im getting error "Login failed. Tibia might be down for maintenance. Please try again later." when trying to connect to local server. Im using TFS 1.3
My ZNOTTE login.php:
PHP:
<?php
require_once 'engine/init.php';
// Client 11 loginWebService
// DEV: Uncomment all //error_log lines and tail error.log file to see communication from and to client.
// ...: Configure webserver to don't display PHP errors/warnings so the client can parse the json response.
if($_SERVER['HTTP_USER_AGENT'] == "Mozilla/5.0" && $config['ServerEngine'] === 'TFS_10' && $config['login_web_service'] == true) {
function sendError($message, $code = 3) {
$response = json_encode(array('errorCode' => $code, 'errorMessage' => $message));
error_log("\nServer = " . $response . "\n-");
die($response);
}
function sendMessage($message) {
$response = json_encode($message);
error_log("\nServer = " . $response . "\n\n-");
die($response);
}
header("Content-Type: application/json");
$input = file_get_contents("php://input");
error_log("\n\n\nClient = " . $input . "\n");
$client = json_decode($input);
if (!isset($client->type)) {
sendError("Type missing.");
}
switch($client->type) {
// {"count":0,"isreturner":true,"offset":0,"showrewardnews":false,"type":"news"}
case "cacheinfo":
// {"type":"cacheinfo"}
sendMessage(array(
'playersonline' => (int)user_count_online(),
'twitchstreams' => 0,
'twitchviewer' => 0,
'gamingyoutubestreams' => 0,
'gamingyoutubeviewer' => 0
));
break;
case 'eventschedule':
// {"type":"eventschedule"}
$eventlist = [];
$file_path = $config['server_path'] . 'data/XML/events.xml';
/* <?xml version="1.0" encoding="UTF-8"?>
<events>
<event name="Otservbr example 1" startdate="11/03/2020" enddate="11/30/2020" >
<ingame exprate="250" lootrate="200" spawnrate="100" skillrate="200" />
<description description="Otserver br example 1 description double exp and a half, double loot !chance!, regular spawn and double skill" />
<colors colordark="#235c00" colorlight="#2d7400" />
<details displaypriority="6" isseasonal="0" specialevent="0" />
</event>
<event name="Otservbr example 2" startdate="12/01/2020" enddate="12/26/2020" >
<ingame exprate="50" lootrate="300" spawnrate="150" skillrate="100" />
<description description="Otserver br example 2 description 50% less exp, triple loot !chance!, 50% faster spawn and regular skill" />
<colors colordark="#735D10" colorlight="#8B6D05" />
<details displaypriority="6" isseasonal="0" specialevent="0" />
</event>
</events>
*/
if (!file_exists($file_path)) {
sendMessage(array(
'eventlist' => array()
));
}
$xml = new DOMDocument;
$xml->load($file_path);
$tableevent = $xml->getElementsByTagName('event');
if (!function_exists("parseEvent")) {
function parseEvent($table1, $date, $table2) {
if ($table1) {
if ($date) {
if ($table2) {
$date = $table1->getAttribute('startdate');
return date_create("{$date}")->format('U');
} else {
$date = $table1->getAttribute('enddate');
return date_create("{$date}")->format('U');
}
} else {
foreach($table1 as $attr) {
if ($attr) {
return $attr->getAttribute($table2);
}
}
}
}
return;
}
}
foreach ($tableevent as $event) {
if ($event) {
$eventlist[] = array(
'colorlight' => parseEvent($event->getElementsByTagName('colors'), false, 'colorlight'),
'colordark' => parseEvent($event->getElementsByTagName('colors'), false, 'colordark'),
'description' => parseEvent($event->getElementsByTagName('description'), false, 'description'),
'displaypriority' => intval(parseEvent($event->getElementsByTagName('details'), false, 'displaypriority')),
'enddate' => intval(parseEvent($event, true, false)),
'isseasonal' => (intval(parseEvent($event->getElementsByTagName('details'), false, 'isseasonal')) == 1) ? true : false,
'name' => $event->getAttribute('name'),
'startdate' => intval(parseEvent($event, true, true)),
'specialevent' => intval(parseEvent($event->getElementsByTagName('details'), false, 'specialevent'))
);
}
}
sendMessage(array(
'eventlist' => $eventlist,
'lastupdatetimestamp' => time()
));
break;
case 'boostedcreature':
// {"type":"boostedcreature"}
sendMessage(array(
//'boostedcreature' => false,
'raceid' => 219
));
break;
case 'news':
// {"count":0,"isreturner":true,"offset":0,"showrewardnews":false,"type":"news"}
sendMessage(array(
'gamenews' => array(), // element structure?
'categorycounts' => array(
'support' => 1,
'game contents' => 2,
'useful info' => 3,
'major updates' => 4,
'client features' => 5
),
'maxeditdate' => 1590979202
));
break;
case "login":
/* {
'accountname' => 'username',
"email":"[email protected]",
'password' => 'superpass',
'stayloggedin' => true,
'token' => '123123', (or not set)
'type' => 'login',
} */
$email = (isset($client->email)) ? sanitize($client->email) : false;
$username = (isset($client->accountname)) ? sanitize($client->accountname) : false;
$password = SHA1($client->password);
$token = (isset($client->token)) ? sanitize($client->token) : false;
$fields = '`id`, `premdays`';
if ($config['twoFactorAuthenticator']) $fields .= ', `secret`';
$account = false;
if ($email !== false) {
$fields .= ', `name`';
$account = mysql_select_single("SELECT {$fields} FROM `accounts` WHERE `email`='{$email}' AND `password`='{$password}' LIMIT 1;");
if ($account !== false) {
$username = $account['name'];
}
} elseif ($username !== false) {
$account = mysql_select_single("SELECT {$fields} FROM `accounts` WHERE `name`='{$username}' AND `password`='{$password}' LIMIT 1;");
}
if ($account === false) {
sendError('Wrong username and/or password.');
}
if ($config['twoFactorAuthenticator'] === true && $account['secret'] !== null) {
if ($token === false) {
sendError('Submit a valid two-factor authentication token.', 6);
} else {
require_once("engine/function/rfc6238.php");
if (TokenAuth6238::verify($account['secret'], $token) !== true) {
sendError('Two-factor authentication failed, token is wrong.', 6);
}
}
}
$players = mysql_select_multi("SELECT `name`, `sex`, `level`, `vocation`, `lookbody`, `looktype`, `lookhead`, `looklegs`, `lookfeet`, `lookaddons`, `deletion` FROM `players` WHERE `account_id`='".$account['id']."';");
if ($players !== false) {
$gameserver = $config['gameserver'];
// Override $config['gameserver'] if server has installed Lua script for loginWebService
$sql_elements = mysql_select_multi("
SELECT
`key`,
`value`
FROM `znote_global_storage`
WHERE `key` IN('SERVER_NAME', 'IP', 'GAME_PORT')
");
if ($sql_elements !== false) {
foreach ($sql_elements AS $element) {
switch ($element['key']) {
case 'SERVER_NAME':
$gameserver['name'] = $element['value'];
break;
case 'IP':
$gameserver['ip'] = $element['value'];
break;
case 'GAME_PORT':
$gameserver['port'] = (int)$element['value'];
break;
}
}
}
$sessionKey = ($email !== false) ? $email."\n".$client->password : $username."\n".$client->password;
if (isset($account['secret']) && strlen($account['secret']) > 5) $sessionKey .= "\n".$token."\n".floor(time() / 30);
$response = array(
'session' => array(
'fpstracking' => false,
'optiontracking' => false,
'isreturner' => true,
'returnernotification' => false,
'showrewardnews' => false,
'tournamentticketpurchasestate' => 0,
'emailcoderequest' => false,
'sessionkey' => $sessionKey,
'lastlogintime' => 0,
'ispremium' => ($account['premdays'] > 0) ? true : false,
'premiumuntil' => time() + ($account['premdays'] * 86400),
'status' => 'active'
),
'playdata' => array(
'worlds' => array(
array(
'id' => 0,
'name' => $gameserver['name'],
'externaladdress' => $gameserver['ip'],
'externalport' => $gameserver['port'],
'previewstate' => 0,
'location' => 'ALL',
'pvptype' => 'pvp',
'externaladdressunprotected' => $gameserver['ip'],
'externaladdressprotected' => $gameserver['ip'],
'externalportunprotected' => $gameserver['port'],
'externalportprotected' => $gameserver['port'],
'istournamentworld' => false,
'restrictedstore' => false,
'currenttournamentphase' => 2,
'anticheatprotection' => false
)
),
'characters' => array(
//array( 'worldid' => ASD, 'name' => asd, 'ismale' => true, 'tutorial' => false ),
)
)
);
foreach ($players as $player) {
$response['playdata']['characters'][] = array(
'worldid' => 0,
'name' => $player['name'],
'ismale' => ($player['sex'] === 1) ? true : false,
'tutorial' => false,
'level' => intval($player['level']),
'vocation' => vocation_id_to_name($player['vocation']),
'outfitid' => intval($player['looktype']),
'headcolor' => intval($player['lookhead']),
'torsocolor' => intval($player['lookbody']),
'legscolor' => intval($player['looklegs']),
'detailcolor' => intval($player['lookfeet']),
'addonsflags' => intval($player['lookaddons']),
'ishidden' => intval($player['deletion']) === 1,
'istournamentparticipant' => false,
'remainingdailytournamentplaytime' => 0
);
}
sendMessage($response);
} else {
sendError("Character list is empty.");
}
break;
default:
sendError("Unsupported type: " . sanitize($client->type));
}
} // End client 11 loginWebService
logged_in_redirect();
include 'layout/overall/header.php';
if (empty($_POST) === false) {
if ($config['log_ip']) {
znote_visitor_insert_detailed_data(5);
}
$username = $_POST['username'];
$password = $_POST['password'];
if (empty($username) || empty($password)) {
$errors[] = 'You need to enter a username and password.';
} else if (strlen($username) > 32 || strlen($password) > 64) {
$errors[] = 'Username or password is too long.';
} else if (user_exist($username) === false) {
$errors[] = 'Failed to authorize your account, are the details correct, have you <a href=\'register.php\'>register</a>ed?';
} /*else if (user_activated($username) === false) {
$errors[] = 'You havent activated your account! Please check your email. <br>Note it may appear in your junk/spam box.';
} */else if ($config['use_token'] && !Token::isValid($_POST['token'])) {
Token::debug($_POST['token']);
$errors[] = 'Token is invalid.';
} else {
// Starting loging
if ($config['ServerEngine'] == 'TFS_02' || $config['ServerEngine'] == 'OTHIRE' || $config['ServerEngine'] == 'TFS_10') $login = user_login($username, $password);
else if ($config['ServerEngine'] == 'TFS_03') $login = user_login_03($username, $password);
else $login = false;
if ($login === false) {
$errors[] = 'Username and password combination is wrong.';
} else {
// Check if user have access to login
$status = false;
if ($config['mailserver']['register']) {
$authenticate = mysql_select_single("SELECT `id` FROM `znote_accounts` WHERE `account_id`='$login' AND `active`='1' LIMIT 1;");
if ($authenticate !== false) {
$status = true;
} else {
$errors[] = "Your account is not activated. An email should have been sent to you when you registered. Please find it and click the activation link to activate your account.";
}
} else $status = true;
if ($status) {
// Regular login success, now lets check authentication token code
if ($config['ServerEngine'] == 'TFS_10' && $config['twoFactorAuthenticator']) {
require_once("engine/function/rfc6238.php");
// Two factor authentication code / token
$authcode = (isset($_POST['authcode'])) ? getValue($_POST['authcode']) : false;
// Load secret values from db
$query = mysql_select_single("SELECT `a`.`secret` AS `secret`, `za`.`secret` AS `znote_secret` FROM `accounts` AS `a` INNER JOIN `znote_accounts` AS `za` ON `a`.`id` = `za`.`account_id` WHERE `a`.`id`='".(int)$login."' LIMIT 1;");
// If account table HAS a secret, we need to validate it
if ($query['secret'] !== NULL) {
// Validate the secret first to make sure all is good.
if (TokenAuth6238::verify($query['secret'], $authcode) !== true) {
$errors[] = "Submitted Two-Factor Authentication token is wrong.";
$errors[] = "Make sure to type the correct token from your mobile authenticator.";
$status = false;
}
} else {
// secret from accounts table is null/not set. Perhaps we can activate it:
if ($query['znote_secret'] !== NULL && $authcode !== false && !empty($authcode)) {
// Validate the secret first to make sure all is good.
if (TokenAuth6238::verify($query['znote_secret'], $authcode)) {
// Success, enable the 2FA system
mysql_update("UPDATE `accounts` SET `secret`= '".$query['znote_secret']."' WHERE `id`='$login';");
} else {
$errors[] = "Activating Two-Factor authentication failed.";
$errors[] = "Try to login without token and configure your app properly.";
$errors[] = "Submitted Two-Factor Authentication token is wrong.";
$errors[] = "Make sure to type the correct token from your mobile authenticator.";
$status = false;
}
}
}
} // End tfs 1.0+ with 2FA auth
if ($status) {
setSession('user_id', $login);
// if IP is not set (etc acc created before Znote AAC was in use)
$znote_data = user_znote_account_data($login, 'ip');
if ($znote_data['ip'] == 0) {
$update_data = array(
'ip' => getIPLong(),
);
user_update_znote_account($update_data);
}
// Send them to myaccount.php
header('Location: myaccount.php');
exit();
}
}
}
}
} else {
header('Location: index.php');
}
if (empty($errors) === false) {
?>
<h2>We tried to log you in, but...</h2>
<?php
header("HTTP/1.1 401 Not Found");
echo output_errors($errors);
}
include 'layout/overall/footer.php'; ?>
Config.lua:
Lua:
-- Combat settings
-- NOTE: valid values for worldType are: "pvp", "no-pvp" and "pvp-enforced"
worldType = "pvp"
hotkeyAimbotEnabled = true
protectionLevel = 1
killsToRedSkull = 3
killsToBlackSkull = 6
pzLocked = 60000
removeChargesFromRunes = true
removeChargesFromPotions = true
removeWeaponAmmunition = true
removeWeaponCharges = true
timeToDecreaseFrags = 24 * 60 * 60
whiteSkullTime = 15 * 60
stairJumpExhaustion = 2000
experienceByKillingPlayers = false
expFromPlayersLevelRange = 75
-- Connection Config
-- NOTE: maxPlayers set to 0 means no limit
-- NOTE: allowWalkthrough is only applicable to players
ip = "127.0.0.1"
bindOnlyGlobalAddress = false
loginProtocolPort = 7171
gameProtocolPort = 7172
statusProtocolPort = 7171
maxPlayers = 0
motd = "Welcome to The Forgotten Server!"
onePlayerOnlinePerAccount = true
allowClones = false
allowWalkthrough = true
serverName = "Forgotten"
statusTimeout = 5000
replaceKickOnLogin = true
maxPacketsPerSecond = 25
-- Deaths
-- NOTE: Leave deathLosePercent as -1 if you want to use the default
-- death penalty formula. For the old formula, set it to 10. For
-- no skill/experience loss, set it to 0.
deathLosePercent = -1
-- Houses
-- NOTE: set housePriceEachSQM to -1 to disable the ingame buy house functionality
-- NOTE: valid values for houseRentPeriod are: "daily", "weekly", "monthly", "yearly"
-- use any other value to disable the rent system
housePriceEachSQM = 1000
houseRentPeriod = "never"
houseOwnedByAccount = false
houseDoorShowPrice = true
onlyInvitedCanMoveHouseItems = true
-- Item Usage
timeBetweenActions = 200
timeBetweenExActions = 1000
-- Map
-- NOTE: set mapName WITHOUT .otbm at the end
mapName = "forgotten"
mapAuthor = "Komic"
-- Market
marketOfferDuration = 30 * 24 * 60 * 60
premiumToCreateMarketOffer = true
checkExpiredMarketOffersEachMinutes = 60
maxMarketOffersAtATimePerPlayer = 100
-- MySQL
mysqlHost = "127.0.0.1"
mysqlUser = "Sasyia"
mysqlPass = "zxc123"
mysqlDatabase = "forgottenserver"
mysqlPort = 3306
mysqlSock = ""
-- Misc.
-- NOTE: classicAttackSpeed set to true makes players constantly attack at regular
-- intervals regardless of other actions such as item (potion) use. This setting
-- may cause high CPU usage with many players and potentially affect performance!
-- NOTE: forceMonsterTypesOnLoad loads all monster types on startup to validate them.
-- You can disable it to save some memory if you don't see any errors at startup.
allowChangeOutfit = true
freePremium = false
kickIdlePlayerAfterMinutes = 15
maxMessageBuffer = 4
emoteSpells = false
classicEquipmentSlots = false
classicAttackSpeed = false
showScriptsLogInConsole = false
showOnlineStatusInCharlist = false
yellMinimumLevel = 2
yellAlwaysAllowPremium = false
forceMonsterTypesOnLoad = true
cleanProtectionZones = false
luaItemDesc = false
showPlayerLogInConsole = true
-- VIP and Depot limits
-- NOTE: you can set custom limits per group in data/XML/groups.xml
vipFreeLimit = 20
vipPremiumLimit = 100
depotFreeLimit = 2000
depotPremiumLimit = 10000
-- World Light
-- NOTE: if defaultWorldLight is set to true the world light algorithm will
-- be handled in the sources. set it to false to avoid conflicts if you wish
-- to make use of the function setWorldLight(level, color)
defaultWorldLight = true
-- Server Save
-- NOTE: serverSaveNotifyDuration in minutes
serverSaveNotifyMessage = true
serverSaveNotifyDuration = 5
serverSaveCleanMap = false
serverSaveClose = false
serverSaveShutdown = true
-- Experience stages
-- NOTE: to use a flat experience multiplier, set experienceStages to nil
-- minlevel and multiplier are MANDATORY
-- maxlevel is OPTIONAL, but is considered infinite by default
-- to disable stages, create a stage with minlevel 1 and no maxlevel
experienceStages = {
{ minlevel = 1, maxlevel = 8, multiplier = 7 },
{ minlevel = 9, maxlevel = 20, multiplier = 6 },
{ minlevel = 21, maxlevel = 50, multiplier = 5 },
{ minlevel = 51, maxlevel = 100, multiplier = 4 },
{ minlevel = 101, multiplier = 3 }
}
-- Rates
-- NOTE: rateExp is not used if you have enabled stages above
rateExp = 5
rateSkill = 3
rateLoot = 2
rateMagic = 3
rateSpawn = 1
-- Monster Despawn Config
-- despawnRange is the amount of floors a monster can be from its spawn position
-- despawnRadius is how many tiles away it can be from its spawn position
-- removeOnDespawn will remove the monster if true or teleport it back to its spawn position if false
deSpawnRange = 2
deSpawnRadius = 50
removeOnDespawn = true
-- Stamina
staminaSystem = true
-- Scripts
warnUnsafeScripts = true
convertUnsafeScripts = true
-- Startup
-- NOTE: defaultPriority only works on Windows and sets process
-- priority, valid values are: "normal", "above-normal", "high"
defaultPriority = "high"
startupDatabaseOptimization = false
-- Status Server Information
ownerName = ""
ownerEmail = ""
url = "https://otland.net/"
location = "Sweden"
Thanks