Request GG Problem Poseidon

All resolved question will be found here. It is recommended that you browse / search through this section first and see if your question has been answered before

Moderators: Moderators, Documentation Writers

Message
Author
Break
Noob
Noob
Posts: 10
Joined: 01 Apr 2015, 16:41
Noob?: Yes

Request GG Problem Poseidon

#1 Post by Break »

[EN]
I have a problem for this period.
Has week that responds regular week has not answered the request gg.
I have tried ways of trying to solve it did not get more success and I do not have knowledge at the time to understand why answers some weeks and not others.
What I noticed and that during the week answers I can log in poseidon apprentice and select the character and change trainee.
In the week that no answers I can not change char, simply does not return the selection screen characters.
Sending the prints this week that he is not responding as you can see the Poseidon is usually linked to openkore only can not send back a response this week.
I'll put the weekly update files and also my RagnarokServer, QueryServer files.
For me that for the operation are needed to add more 09D0 package I is not seeing something.
So who can give me a light on the way forward would be grateful.

[PT-BR]
Estou com um problema por periodo.
Tem semana que responde normal tem semana que não responde o request gg.
Eu já procurei formas de tentar resolver isso mais não obtive exito e não possuo conhecimento no momento para entender por que responde algumas semanas e outras não.
O que percebi e que durante a semana que responde eu posso logar no aprendiz do poseidon e selecionar o char e trocar de aprendiz.
Já na semana que não responde eu não consigo trocar de char, simplismente não volta a tela de selecão de personagens.
Mandando as prints dessa semana que não está respondendo como pode perceber o poseidon está ligado normalmente ao openkore só que não consegue enviar de volta a resposta nessa semana.
Vou colocar os arquivos da atualização semanal também e meus arquivos RagnarokServer, QueryServer.
Para mim que para o funcionamento so precisava adicionar o pacote 09D0 mais devo não está percebendo algo. Então quem puder me dar uma luz no caminho a seguir ficaria grato.

Image
Image
Image
Attachments
recvpackets08-03.txt
(15.83 KiB) Downloaded 563 times

[The extension pm has been deactivated and can no longer be displayed.]

[The extension pm has been deactivated and can no longer be displayed.]

Last edited by Break on 09 Mar 2016, 12:56, edited 2 times in total.

Break
Noob
Noob
Posts: 10
Joined: 01 Apr 2015, 16:41
Noob?: Yes

Re: Request GG Problem Poseidon

#2 Post by Break »

QueryServer

Code: Select all

###########################################################
# Poseidon server - OpenKore communication channel
#
# This program is free software; you can redistribute it and/or 
# modify it under the terms of the GNU General Public License 
# as published by the Free Software Foundation; either version 2 
# of the License, or (at your option) any later version.
#
# Copyright (c) 2005-2006 OpenKore Development Team
###########################################################
package Poseidon::QueryServer;

use strict;
use Scalar::Util;
use Base::Server;
use Bus::MessageParser;
use Bus::Messages qw(serialize);
use Poseidon::RagnarokServer;
use base qw(Base::Server);
use Plugins;

my $CLASS = "Poseidon::QueryServer";


# struct Request {
#     Bytes packet;
#     Base::Server::Client client;
# }

##
# Poseidon::QueryServer->new(String port, String host, Poseidon::RagnarokServer ROServer)
# port: The port to start this server on.
# host: The host to bind this server to.
# ROServer: The RagnarokServer object to send GameGuard queries to.
# Require: defined($port) && defined($ROServer)
#
# Create a new Poseidon::QueryServer object.
sub new {
	my ($class, $port, $host, $roServer) = @_;
	my $self = $class->SUPER::new($port, $host);

	# Invariant: server isa 'Poseidon::RagnarokServer'
	$self->{"$CLASS server"} = $roServer;

	# Array<Request> queue
	#
	# The GameGuard query packets queue.
	#
	# Invariant: defined(queue)
	$self->{"$CLASS queue"} = [];

	return $self;
}

##
# void $QueryServer->process(Base::Server::Client client, String ID, Hash* args)
#
# Push an OpenKore GameGuard query to the queue.
sub process {
	my ($self, $client, $ID, $args) = @_;

	if ($ID ne "Poseidon Query") {
		$client->close();
		return;
	}
	
	print "[PoseidonServer]-> Received query from bot client " . $client->getIndex() . "\n";

	my %request = (
		packet => $args->{packet},
		client => $client
	);

	# perform client authentication here
	Plugins::callHook('Poseidon/server_authenticate', {
		args_hash => $args,
	});

	# note: the authentication plugin must set auth_failed to true if it doesn't
	# want the Poseidon server to respond to the query
	return if ($args->{auth_failed});

	Scalar::Util::weaken($request{client});
	push @{$self->{"$CLASS queue"}}, \%request;
#	my $packet = substr($ipcArgs->{packet}, 0, 18);
}


##################################################


sub onClientNew {
	my ($self, $client, $index) = @_;
	$client->{"$CLASS parser"} = new Bus::MessageParser();
	print "[PoseidonServer]-> New Bot Client Connected : " . $client->getIndex() . "\n";
}

sub onClientExit {
	my ($self, $client, $index) = @_;
	print "[PoseidonServer]-> Bot Client Disconnected : " . $client->getIndex() . "\n";
}

sub onClientData
{
	my ($self, $client, $msg) = @_;
	my ($ID, $args);

	my $parser = $client->{"$CLASS parser"};
	
	$parser->add($msg);
	
	while ($args = $parser->readNext(\$ID))
	{
		$self->process($client, $ID, $args);
	}
}

sub iterate {
	my ($self) = @_;
	my ($server, $queue);

	$self->SUPER::iterate();
	$server = $self->{"$CLASS server"};
	$queue = $self->{"$CLASS queue"};

	if ($server->getState() eq 'requested') 
	{
		# Send the response to the client.
		if (@{$queue} > 0 && $queue->[0]{client}) {
			my ($data, %args);

			$args{packet} = $server->readResponse();
			$data = serialize("Poseidon Reply", \%args);
			$queue->[0]{client}->send($data);
			$queue->[0]{client}->close();
			print "[PoseidonServer]-> Sent result to client : " . $queue->[0]{client}->getIndex() . "\n";
		}
		shift @{$queue};

	} elsif (@{$queue} > 0 && $server->getState() eq 'ready') {
		print "[PoseidonServer]-> Querying Ragnarok Online client [" . time . "]...\n";
		$server->query($queue->[0]{packet});
	}
}

1;

RagnarokServer

Code: Select all

###########################################################
# Poseidon server - Ragnarok Online server emulator
#
# This program is free software; you can redistribute it and/or 
# modify it under the terms of the GNU General Public License 
# as published by the Free Software Foundation; either version 2 
# of the License, or (at your option) any later version.
#
# Copyright (c) 2005-2006 OpenKore Development Team
###########################################################
# This class emulates a Ragnarok Online server.
# The RO client connects to this server. This server
# periodically sends a GameGuard query to the RO client,
# and saves the RO client's response.
###########################################################

# TODO:
# 1) make use of unpack strings to pack our packets depending on serverType
# 2) make plugin like connection algorithms for each serverType or 1 main algo on which serverTypes have hooks

package Poseidon::RagnarokServer;

use strict;
use Base::Server;
use base qw(Base::Server);
use Misc;
use Utils qw(binSize getCoordString timeOut getHex getTickCount);
use Poseidon::Config;
use FileParsers;
use Math::BigInt;

my %clientdata;

# Decryption Keys
my $enc_val1 = 0;
my $enc_val2 = 0;
my $enc_val3 = 0;
my $state    = 0;

sub new {
	my ($class, @args) = @_;
	my $self = $class->SUPER::new(@args);

	# int challengeNum
	#
	# The number of times that the RO client has sent a
	# GameGuard challenge packet.
	#
	# Invariant: challengeNum >= 0
	$self->{challengeNum} = 0;

	# Bytes response
	#
	# A response for the last GameGuard query.
	$self->{response} = undef;

	# Invariant: state ne ''
	$self->{state} = 'ready';
	
	# added servertypes support
	if (-e 'servertypes.txt') {
		parseSectionedFile('servertypes.txt', \%{$self->{type}});
	} else {
		parseSectionedFile('src/Poseidon/servertypes.txt', \%{$self->{type}});
	}
	
	if (!$self->{type}->{$config{server_type}}) {
		die "Invalid serverType specified. Please check your poseidon config file.\n";
	} else {
		print "Building RagnarokServer with serverType $config{server_type}...\n";
	}

	return $self;
}

##
# $RagnarokServer->query(Bytes packet)
# packet: The raw GameGuard query packet.
# Require: defined($packet) && $self->getState() eq 'ready'
# Ensure: $self->getState() eq 'requesting'
#
# Send a GameGuard query to the RO client.
sub query 
{
	my ($self, $packet) = @_;
	my $clients = $self->clients();

	for (my $i = 0; $i < @{$clients}; $i++) {
		if ($clients->[$i]) {
			if ($clients->[$i]{connectedToMap}) {
                		$clients->[$i]->send($packet);
                		$self->{state} = 'requesting';
                		return;
			}
		}
	}
	
	print "[RagnarokServer]-> Error: no Ragnarok Online client connected.\n";
}

##
# String $RagnarokServer->getState()
#
# Get the state of this RagnarokServer object.
# The result can be one of:
# 'ready' - The RO client is ready to handle another GameGuard query.
# 'requesting' - The query has been sent to the RO client, but it hasn't responded yet.
# 'requested' - The RO client has responded to the last GameGuard query.
# 'not connected' - The RO client hasn't connected to this server yet.
sub getState {
	my ($self) = @_;
	my $clients = $self->clients();

	if ($self->{state} eq 'requested') {
		return 'requested';
	} elsif (binSize($clients) == 0) {
		return 'not connected';
	} else {
		return $self->{state};
	}
}

##
# Bytes $RagnarokServer->readResponse()
# Require: $self->getState() eq 'requested'
# Ensure: defined(result) && $self->getState() eq 'ready'
#
# Read the response for the last GameGuard query.
sub readResponse {
	my $resp = $_[0]->{response};
	$_[0]->{response} = undef;
	$_[0]->{state} = 'ready';
	return $resp;
}


#####################################################

sub onClientNew 
{
	my ($self, $client, $index) = @_;

	if ( $state == 0 )
	{
		# Initialize Decryption
		$enc_val1 = 0;
		$enc_val2 = 0;
		$enc_val3 = 0;
	} else { $state = 0; }
	
	$self->{challengeNum} = 0;
	
	print "[RagnarokServer]-> Ragnarok Online client ($index) connected.\n";	
}

sub onClientExit 
{
	my ($self, $client, $index) = @_;
	
	$self->{challengeNum} = 0;
	
	print "[RagnarokServer]-> Ragnarok Online client ($index) disconnected.\n";
}

## constants
my $accountID = pack("a4", "acct");
my $posX = 53;
my $posY = 113;

## Globals
my $charID = pack("a4", "char");
my $sessionID = pack("a4", "sess");
my $sessionID2 = pack("C4", 0xff);
my $npcID1 = pack("a4", "npc1");
my $npcID0 = pack("a4", "npc2");
my $monsterID = pack("a4", "mon1");
my $itemID = pack("a4", "itm1");

sub DecryptMessageID 
{
	my ($MID) = @_;
	
	# Checking if Decryption is Activated
	if ($enc_val1 != 0 && $enc_val2 != 0 && $enc_val3 != 0) 
	{
		# Saving Last Informations for Debug Log
		my $oldMID = $MID;
		my $oldKey = ($enc_val1 >> 16) & 0x7FFF;
		
		# Calculating the Next Decryption Key
		$enc_val1 = $enc_val1->bmul($enc_val3)->badd($enc_val2) & 0xFFFFFFFF;
	
		# Xoring the Message ID [657BE2h] [0x6E0A]
		$MID = ($MID ^ (($enc_val1 >> 16) & 0x7FFF));

		# Debug Log
		# print sprintf("Decrypted MID : [%04X]->[%04X] / KEY : [0x%04X]->[0x%04X]\n", $oldMID, $MID, $oldKey, ($enc_val1 >> 16) & 0x7FFF);
	}
	
	return $MID;
}

sub onClientData {
	my ($self, $client, $msg, $index) = @_;

	my $packet_id = DecryptMessageID(unpack("v",$msg));
	my $switch = sprintf("%04X", $packet_id);
	
	# Parsing Packet
	ParsePacket($self, $client, $msg, $index, $packet_id, $switch);
}

sub ParsePacket
{
	my ($self, $client, $msg, $index, $packet_id, $switch) = @_;

	#my $packed_switch = quotemeta substr($msg, 0, 2);
	my $packed_switch = $packet_id;
	
	### These variables control the account information ###
	my $host = $self->getHost();
	my $port = pack("v", $self->getPort());
	$host = '127.0.0.1' if ($host eq 'localhost');
	my @ipElements = split /\./, $host;
	
	# Note:
	# The switch packets are pRO specific and assumes the use of secureLogin 1. It may or may not work with other
	# countries' clients (except probably oRO). The best way to support other clients would be: use a barebones
	# eAthena or Freya as the emulator, or figure out the correct packet switches and include them in the
	# if..elsif..else blocks.

	if (($switch eq '01DB') || ($switch eq '0204')) { # client sends login packet 0204 packet thanks to elhazard

		# '01DC' => ['secure_login_key', 'x2 a*', [qw(secure_key)]],
		my $data = pack("C*", 0xdc, 0x01, 0x14) . pack("x17");
		$client->send($data);

		# save servers.txt info
		my $code = substr($msg, 2);
		if (length($msg) == 2) {
			$clientdata{$index}{secureLogin_type} = 0;
		} elsif (length($msg) == 20) {
			if ($code eq pack("C*", 0x04, 0x02, 0x7B, 0x8A, 0xA8, 0x90, 0x2F, 0xD8, 0xE8, 0x30, 0xF8, 0xA5, 0x25, 0x7A, 0x0D, 0x3B, 0xCE, 0x52)) {
				$clientdata{$index}{secureLogin_type} = 1;
			} elsif ($code eq pack("C*", 0x04, 0x02, 0x27, 0x6A, 0x2C, 0xCE, 0xAF, 0x88, 0x01, 0x87, 0xCB, 0xB1, 0xFC, 0xD5, 0x90, 0xC4, 0xED, 0xD2)) {
				$clientdata{$index}{secureLogin_type} = 2;
			} elsif ($code eq pack("C*", 0x04, 0x02, 0x42, 0x00, 0xB0, 0xCA, 0x10, 0x49, 0x3D, 0x89, 0x49, 0x42, 0x82, 0x57, 0xB1, 0x68, 0x5B, 0x85)) {
				$clientdata{$index}{secureLogin_type} = 3;
			} elsif ($code eq ("C*", 0x04, 0x02, 0x22, 0x37, 0xD7, 0xFC, 0x8E, 0x9B, 0x05, 0x79, 0x60, 0xAE, 0x02, 0x33, 0x6D, 0x0D, 0x82, 0xC6)) {
				$clientdata{$index}{secureLogin_type} = 4;
			} elsif ($code eq pack("C*", 0x04, 0x02, 0xc7, 0x0A, 0x94, 0xC2, 0x7A, 0xCC, 0x38, 0x9A, 0x47, 0xF5, 0x54, 0x39, 0x7C, 0xA4, 0xD0, 0x39)) {
				$clientdata{$index}{secureLogin_type} = 5;
			}
		} else {
			$clientdata{$index}{secureLogin_requestCode} = getHex($code);
		}

	} elsif (($switch eq '01DD') || ($switch eq '01FA') || ($switch eq '0064') || ($switch eq '0060') || ($switch eq '0277') || ($switch eq '02B0')) { # 0064 packet thanks to abt123

#		my $data = pack("C*", 0xAD, 0x02, 0x00, 0x00, 0x1E, 0x0A, 0x00, 0x00);
#		$client->send($data);
		my $sex = 1;
		my $serverName = pack("a20", "Poseidon server"); # server name should be less than or equal to 20 characters
		my $serverUsers = pack("V", @{$self->clients()} - 1);
		# '0069' => ['account_server_info', 'x2 a4 a4 a4 x30 C1 a*',
		# 			[qw(sessionID accountID sessionID2 accountSex serverInfo)]],
		my $data;
		if ($switch eq '01FA') {
			$data = pack("C*", 0x69, 0x00, 0x53, 0x00) . 
				$sessionID . $accountID . $sessionID2 . 
				pack("x30") . pack("C1", $sex) . pack("x4") .
				pack("C*", $ipElements[0], $ipElements[1], $ipElements[2], $ipElements[3]) .
				$port .	$serverName . $serverUsers . pack("x2");
		} else {
			$data = pack("C*", 0x69, 0x00, 0x4F, 0x00) . 
				$sessionID . $accountID . $sessionID2 . 
				pack("x30") . pack("C1", $sex) .
				pack("C*", $ipElements[0], $ipElements[1], $ipElements[2], $ipElements[3]) .
				$port .	$serverName . $serverUsers . pack("x2");
		}

		$client->send($data);

		# save servers.txt info
		$clientdata{$index}{version} = unpack("V", substr($msg, 2, 4));
		$clientdata{$index}{master_version} = unpack("C", substr($msg, length($msg) - 1, 1));
		if ($switch eq '01DD') {
			$clientdata{$index}{secureLogin} = 1;
			undef $clientdata{$index}{secureLogin_account};
		} elsif ($switch eq '01FA') {
			$clientdata{$index}{secureLogin} = 3;
			$clientdata{$index}{secureLogin_account} = unpack("C", substr($msg, 47, 1));
		} else {
			undef $clientdata{$index}{secureLogin};
			undef $clientdata{$index}{secureLogin_type};
			undef $clientdata{$index}{secureLogin_account};
			undef $clientdata{$index}{secureLogin_requestCode};
		}
		if (($switch ne '01DD') && ($switch ne '01FA') && ($switch ne '0064')) {
			$clientdata{$index}{masterLogin_packet} = $switch;
		} else {
			undef $clientdata{$index}{masterLogin_packet};
		}

		if($switch eq '02B0') {	# kRO uses 02B2 as masterLogin packet when we have <langtype>0</langtype> in the clientinfo.xml
								# if other servers do use this packet too that will be a problem.
			$clientdata{$index}{kRO} = 1;
		}

	} elsif (($switch eq '0065') || ($switch eq '0275') || ($msg =~ /^$packed_switch$accountID$sessionID$sessionID2\x0\x0.$/)) { # client sends server choice packet

		# Character List
		SendCharacterList($self, $client, $msg, $index);

		# save servers.txt info
		if ($switch ne '0065') {
			$clientdata{$index}{gameLogin_packet} = $switch;
		} else {
			undef $clientdata{$index}{gameLogin_packet};
		}

	} elsif ($switch eq '0066') { # client sends character choice packet

		# If Using Packet Encrypted Client
		if ( $self->{type}->{$config{server_type}}->{decrypt_mid_keys} )
		{
			# Enable Decryption
			my @enc_values = split(/\s+/, $self->{type}->{$config{server_type}}->{decrypt_mid_keys});
			($enc_val1, $enc_val2, $enc_val3) = (Math::BigInt->new(@enc_values[0]), Math::BigInt->new(@enc_values[1]), Math::BigInt->new(@enc_values[2]));
		}
		
		# State
		$state = 1;

		$clientdata{$index}{mode} = unpack('C1', substr($msg, 2, 1));

		# '0071' => ['received_character_ID_and_Map', 'a4 Z16 a4 v1', [qw(charID mapName mapIP mapPort)]],
		my $mapName = pack("a16", "moc_prydb1.gat");
		my $data = pack("C*", 0x71, 0x00) . $charID . $mapName . 
			pack("C*", $ipElements[0], $ipElements[1], $ipElements[2], $ipElements[3]) . $port;
		
		$client->send($data);
		
	} elsif ($switch eq  $self->{type}->{$config{server_type}}->{maploginPacket} &&
		(length($msg) == 19) &&
		(substr($msg, 2, 4) eq $accountID) &&
		(substr($msg, 6, 4) eq $charID) &&
		(substr($msg, 10, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 0;

	} elsif ($switch eq '0072' &&
		(length($msg) == 19) &&
		(substr($msg, 2, 4) eq $accountID) &&
		(substr($msg, 6, 4) eq $charID) &&
		(substr($msg, 10, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 0;

	} elsif ($switch eq '009B' &&
		(length($msg) == 32) &&
		(substr($msg, 3, 4) eq $accountID) &&
		(substr($msg, 12, 4) eq $charID) &&
		(substr($msg, 23, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 3;

	} elsif ($switch eq '00F5' &&
		(length($msg) == 29) &&
		(substr($msg, 5, 4) eq $accountID) &&
		(substr($msg, 14, 4) eq $charID) &&
		(substr($msg, 20, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 4;

	} elsif ($switch eq '009B' &&
		(length($msg) == 32) &&
		(substr($msg, 9, 4) eq $accountID) &&
		(substr($msg, 15, 4) eq $charID) &&
		(substr($msg, 23, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 5;

	} elsif ($switch eq '0072' &&
		(length($msg) == 29) &&
		(substr($msg, 3, 4) eq $accountID) &&
		(substr($msg, 10, 4) eq $charID) &&
		(substr($msg, 20, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 6;

	} elsif ($switch eq '0072' &&
		(length($msg) == 34) &&
		(substr($msg, 7, 4) eq $accountID) &&
		(substr($msg, 15, 4) eq $charID) &&
		(substr($msg, 25, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 7;

	} elsif ($switch eq '009B' &&
		(length($msg) == 26) &&
		(substr($msg, 4, 4) eq $accountID) &&
		(substr($msg, 9, 4) eq $charID) &&
		(substr($msg, 17, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 8;

	} elsif ($switch eq '009B' &&
		(length($msg) == 37) &&
		(substr($msg, 9, 4) eq $accountID) &&
		(substr($msg, 21, 4) eq $charID) &&
		(substr($msg, 28, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 9;

	} elsif ($switch eq '0072' &&
		(length($msg) == 26) &&
		(substr($msg, 4, 4) eq $accountID) &&
		(substr($msg, 9, 4) eq $charID) &&
		(substr($msg, 17, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 10;

	} elsif ($switch eq '0072' &&
		(length($msg) == 29) &&
		(substr($msg, 5, 4) eq $accountID) &&
		(substr($msg, 14, 4) eq $charID) &&
		(substr($msg, 20, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 11;

	} elsif ($switch eq '0094' &&
		(length($msg) == 30) &&
		(substr($msg, 12, 4) eq $accountID) &&
		(substr($msg, 2, 4) eq $charID) &&
		(substr($msg, 6, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = 12;

	} elsif ($switch eq '0072' &&
		(length($msg) == 29) &&
		(substr($msg, 5, 4) eq $accountID) &&
		(substr($msg, 14, 4) eq $charID) &&
		(substr($msg, 20, 4) eq $sessionID)
		) { # client sends the maplogin packet

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		$clientdata{$index}{serverType} = "1 or 2";

	} elsif (($switch eq '0436' || $switch eq '022D') &&
		(length($msg) == 19) &&
		(substr($msg, 2, 4) eq $accountID) &&
		(substr($msg, 6, 4) eq $charID) &&
		(substr($msg, 10, 4) eq $sessionID)
		) { # client sends the maplogin packet

		$client->send(pack("v a4", 0x0283, $accountID));
		# mapLogin packet
		$client->send(pack("H536", "eb0206ad09222b56c0050500000f012c010100000000000900000001004e565f42415349430000000000000000080000000f0000000030000000000000000000010054465f444f55424c4500000000000000090000000f0000000131000000000000000000010054465f4d495353000000000000000000070000000f0000000132000100000000000a00010054465f535445414c0000000000000000080000000f0000000133000400000000000a00010054465f484944494e4700000000000000090000000f0000000034000100000000000c00020054465f504f49534f4e00000000000000090000000f0000000135001000000000000a00090054465f4445544f5849465900000000000b0000000f000000008e00040000000100030001004e565f464952535441494400000000000b0000000f00000000d701df145a000200000000d701df145a0003000000003a010100d701df145a0002f13200003a010100b0001900d06b0000b0001800b2110000b102080000000000b202080000000000b0002a003f000000b0002b0000000000b0002e002d000000b000300000000000d9070039020000000000000000000000000000000000000000000000000000233000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"));
		$client->{connectedToMap} = 1;

	} elsif ($msg =~ /^$packed_switch/
		&& $msg =~ /$accountID/
		&& $msg =~ /$charID/
		&& $msg =~ /$sessionID/) { # client sends the maplogin packet (unknown)

		print "Received unsupported map login packet $switch.\n";
		visualDump($msg, "$switch");

		SendMapLogin($self, $client, $msg, $index);
		# save servers.txt info
		undef $clientdata{$index}{serverType};
		#$clientdata{$index}{sendMapLogin} = $msg;

	} elsif ($switch eq '007D') { # client sends the map loaded packet
		my $data;

		# Temporary Hack to Initialized Crypted Client
		if ( $self->{type}->{$config{server_type}}->{decrypt_mid_keys} )
		{
			for ( my $i = 0 ; $i < 64 ; $i++ ) 
			{
				$client->send(pack("C C", 0x70, 0x08));
				
				# Forcedly Calculating the Next Decryption Key
				$enc_val1 = $enc_val1->bmul($enc_val3)->badd($enc_val2) & 0xFFFFFFFF;	
			}
		}		
		
		PerformMapLoadedTasks($self, $client, $msg, $index);
	} elsif (
		( ( ($switch eq '007E') || ($switch eq '035F') ) && (($clientdata{$index}{serverType} == 0) || ($clientdata{$index}{serverType} == 1) || ($clientdata{$index}{serverType} == 2) || ($clientdata{$index}{serverType} == 6) || ($clientdata{$index}{serverType} == 7) || ($clientdata{$index}{serverType} == 10) || ($clientdata{$index}{serverType} == 11))) ||
		(($switch eq '0089') && (($clientdata{$index}{serverType} == 3) || ($clientdata{$index}{serverType} == 5) || ($clientdata{$index}{serverType} == 8) || ($clientdata{$index}{serverType} == 9))) ||
		(($switch eq '0116') && ($clientdata{$index}{serverType} == 4)) ||
		(($switch eq '00A7') && ($clientdata{$index}{serverType} == 12))
		) { # client sends sync packet
		my $data = pack("C*", 0x7F, 0x00) . pack("V", getTickCount);
		$client->send($data);

		### Check if packet 0228 got tangled up with the sync packet
		if (uc(unpack("H2", substr($msg, 7, 1))) . uc(unpack("H2", substr($msg, 6, 1))) eq '0228') {
			# queue the response (thanks abt123)
			$self->{response} = pack("v", $packet_id) . substr($msg, 8, length($msg)-2);
			$self->{state} = 'requested';
		}

	} elsif ($switch eq '00B2') { # quit to character select screen
			
		SendGoToCharSelection($self, $client, $msg, $index);
			
		# Disable Decryption
		$enc_val1 = 0;
		$enc_val2 = 0;
		$enc_val3 = 0;			
			
	} elsif ($switch eq '0187') { # accountid sync (what does this do anyway?)
		$client->send($msg);

	} elsif ($switch eq '018A') { # client sends quit packet
		
		SendQuitGame($self, $client, $msg, $index);

	} elsif ($switch eq '0228') { # client sends game guard sync
		# Queue the response
		# Don't allow other packet's (like Sync) to get to RO server.
		my $length = unpack("v",substr($msg,2,2));
		if ($length > 0) {
			$self->{response} = pack("v", $packet_id) . substr($msg,2,$length);
		} else {
			$self->{response} = pack("v", $packet_id);
		};
		$self->{state} = 'requested';
	
	} elsif ($switch eq '02A7') { # client sends hShield response
		# Queue the response
		$self->{response} = $msg;
		$self->{state} = 'requested';

	} elsif ($switch eq '0258') { # client sent gameguard's challenge request
		# Reply with "gameguard_grant" instead of a 0227 packet. Normally, the server would
		# send a 0227 gameguard challenge to the client, then the client will send the
		# proper 0228 response. Only after that will the server send 0259 to allow the
		# client to continue the login sequence. Since this is just a fake server,
		# there is no need to go through all that and we can do a shortcut.
		if ($self->{challengeNum} == 0) {
			print "Received GameGuard sync request. Client allowed to login account server.\n";
			$client->send(pack("C*", 0x59, 0x02, 0x01));
		} else {
			print "Received GameGuard sync request. Client allowed to login char/map server.\n";
			$client->send(pack("C*", 0x59, 0x02, 0x02));
		}
		$self->{challengeNum}++;
	} else {
		if ($switch eq '0090' || ($msg =~ /\x90\x0($npcID1|$npcID0)/)) { # npc talk
			undef $clientdata{$index}{npc_talk_code};
			if ($msg =~ /\x90\x0$npcID1/) {
				# Show the kafra image
				SendNpcImageShow($self, $client, $msg, $index, "kafra_04.bmp", 0x02);
				# Show the messages
				SendNPCTalk($self, $client, $msg, $index, $npcID1, "[Kafra]");
				SendNPCTalk($self, $client, $msg, $index, $npcID1, "Welcome to Kafra Corp. We will stay with you wherever you go.");
				SendNPCTalkContinue($self, $client, $msg, $index, $npcID1);
			} else {
				SendNPCTalk($self, $client, $msg, $index, $npcID0, "[Hakore]");
				SendNPCTalk($self, $client, $msg, $index, $npcID0, "Hello! I was examining your RO client's login packets while you were connecting to Poseidon.");
				SendNPCTalkContinue($self, $client, $msg, $index, $npcID0);
			}

		} elsif ($switch eq '00B8') { # npc talk response

			my $npcID = substr($msg, 2, 4);
			my $response = unpack("C1", substr($msg, 6, 1));
			if ($npcID eq $npcID0) {
				if ($response == 1) {
					# Check server info
					SendNPCTalk($self, $client, $msg, $index, $npcID, "[Hakore]");
					SendNPCTalk($self, $client, $msg, $index, $npcID, "Your RO client uses the following server details:");
					SendNPCTalk($self, $client, $msg, $index, $npcID, "^2222DDversion: $clientdata{$index}{version}");
					SendNPCTalk($self, $client, $msg, $index, $npcID, "master_version: $clientdata{$index}{master_version}");
					SendNPCTalk($self, $client, $msg, $index, "serverType: " . ((defined $clientdata{$index}{serverType}) ? $clientdata{$index}{serverType} : 'Unknown'));
					if ($clientdata{$index}{secureLogin}) {
						SendNPCTalk($self, $client, $msg, $index, $npcID, "secureLogin: $clientdata{$index}{secureLogin}");
						if ($clientdata{$index}{secureLogin_requestCode}) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, $npcID, "secureLogin_requestCode: $clientdata{$index}{secureLogin_requestCode}");
						} elsif (defined $clientdata{$index}{secureLogin_type}) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "secureLogin_type: $clientdata{$index}{secureLogin_type}");
						}
						if ($clientdata{$index}{secureLogin_account}) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "secureLogin_account: $clientdata{$index}{secureLogin_account}");
						}
					}
					if ($clientdata{$index}{masterLogin_packet}) {
						SendNPCTalk($self, $client, $msg, $index, $npcID, "masterLogin_packet: $clientdata{$index}{masterLogin_packet}");
					}
					if ($clientdata{$index}{gameLogin_packet}) {
						SendNPCTalk($self, $client, $msg, $index, $npcID, "gameLogin_packet: $clientdata{$index}{gameLogin_packet}");
					}
					SendNPCTalkContinue($self, $client, $msg, $index, $npcID);
					
					if (defined $clientdata{$index}{serverType}) {
						$clientdata{$index}{npc_talk_code} = 3;
					} else {
						$clientdata{$index}{npc_talk_code} = 2.5;
					}

				} elsif ($response == 2) {
					# Use storage
					SendNPCTalk($self, $client, $msg, $index, $npcID, "[Hakore]");
					SendNPCTalk($self, $client, $msg, $index, $npcID, "Thank you for the visit. Go and multiply!");
					SendNpcTalkClose($self, $client, $msg, $index, $npcID);
				}

			} elsif ($npcID eq $npcID1) {
				if ($response == 1) {
					# Use storage
					my $data;
					$data .= pack("C2 v1", 0xF0, 0x01, 40) .
						pack("v2 C2 v1 x10", 3, 501, 0, 1, 16) .
						pack("v2 C2 v1 x10", 4, 909, 3, 1, 144);
					$data .= pack("v3", 0xF2, 2, 300);
					SendNpcImageShow($self, $client, $msg, $index, "kafra_04.bmp", 0xFF);
					SendNpcTalkClose($self, $client, $msg, $index, $npcID);
					$client->send($data);

				} elsif ($response == 2) {
					# Use storage
					SendNPCTalk($self, $client, $msg, $index, $npcID, "[Kafra]");
					SendNPCTalk($self, $client, $msg, $index, $npcID, "We Kafra Corp. always try to serve you the best.");
					SendNPCTalk($self, $client, $msg, $index, $npcID, "Please come again.");
					SendNpcTalkClose($self, $client, $msg, $index, $npcID);
				}
			}

		} elsif ($switch eq '00B9') { # npc talk continue
			my $npcID = substr($msg, 2, 4);
			if ($npcID eq $npcID0) {
				if ($clientdata{$index}{npc_talk_code} == 2) {
					# Show NPC response list
					SendNpcTalkResponses($self, $client, $msg, $index, $npcID, "Yes, please:No, thanks:");
					$clientdata{$index}{npc_talk_code} = 3;

				} else {
					SendNPCTalk($self, $client, $msg, $index, $npcID, "[Hakore]");
					if (!$clientdata{$index}{npc_talk_code}) {
						if (!defined $clientdata{$index}{serverType}) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "However, I regret that Openkore may not currently support your server.");
						} elsif ($clientdata{$index}{serverType} == 7 || $clientdata{$index}{serverType} == 12) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "However, I regret that Openkore does not yet fully support your server this time.");
						} else {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Based on my examination, I think Openkore supports your server.");
							SendNPCTalk($self, $client, $msg, $index, $npcID, "I can tell you the possible server details you can use to make Openkore to connect to your server.");
						}
						SendNPCTalkContinue($self, $client, $msg, $index, $npcID);
						$clientdata{$index}{npc_talk_code} = 1;

					} elsif ($clientdata{$index}{npc_talk_code} == 1) {
						if ((!defined $clientdata{$index}{serverType}) || ($clientdata{$index}{serverType} == 7)) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Would you still like to hear the details?");
						} else {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Would you like to hear the details?");
						}
						SendNPCTalkContinue($self, $client, $msg, $index, $npcID);
						$clientdata{$index}{npc_talk_code} = 2;
				
					} elsif ($clientdata{$index}{npc_talk_code} == 2.5) {
						if (!defined $clientdata{$index}{serverType}) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "As you can see, I can't find a matching serverType for your server.");
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Please make a trial-and-error using all available serverTypes, one of them might be able to work.");
						} elsif ($clientdata{$index}{serverType} == 7 || $clientdata{$index}{serverType} == 12) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Like I said, your server is not yet fully supported by Openkore.");
							SendNPCTalk($self, $client, $msg, $index, $npcID, "You can login to the server and do most basic tasks, but you cannot attack, sit or stand, or use skills.");
						}
						SendNPCTalkContinue($self, $client, $msg, $index, $npcID);
						$clientdata{$index}{npc_talk_code} = 4;

					} elsif ($clientdata{$index}{npc_talk_code} == 3) {
						SendNPCTalk($self, $client, $msg, $index, $npcID, "The values of ^2222DDip^000000 and ^2222DDport^000000 can be found on your client's (s)clientinfo.xml.");
						SendNPCTalkContinue($self, $client, $msg, $index, $npcID);
						$clientdata{$index}{npc_talk_code} = 4;

					} elsif ($clientdata{$index}{npc_talk_code} == 4) {
						if (!defined $clientdata{$index}{serverType}) {
							SendNPCTalk($self, $client, $msg, $index, $npcID, "If none of the serverTypes work, please inform the developers about this so we can support your server in future releases of Openkore.");
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Please visit ^2222DDhttp://forums.openkore.com/^000000");
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Thank you.");
						} else {
							if (($clientdata{$index}{serverType} == 7)
								|| ($clientdata{$index}{serverType} == 8)
								|| ($clientdata{$index}{serverType} == 9)
								|| ($clientdata{$index}{serverType} == 10)
								|| ($clientdata{$index}{serverType} == 11)
								|| ($clientdata{$index}{serverType} == 12)
								|| ($clientdata{$index}{masterLogin_packet})
								|| ($clientdata{$index}{gameLogin_packet})
							) {
								SendNPCTalk($self, $client, $msg, $index, $npcID, "Please note that you can only connect to your server using Openkore SVN.");
							} else {
								SendNPCTalk($self, $client, $msg, $index, $npcID, "Openkore v.1.6.6 or later will work on your server.");
							}
							SendNPCTalk($self, $client, $msg, $index, $npcID, "For more info, please visit ^2222DDhttp://www.openkore.com/^000000");
							SendNPCTalk($self, $client, $msg, $index, $npcID, "Good luck!");
						}
						SendNpcTalkClose($self, $client, $msg, $index, $npcID);
					}
				}

			} elsif ($npcID eq $npcID1) {
				# Show kafra response list
				SendNpcTalkResponses($self, $client, $msg, $index, $npcID, "Use Storage:Cancel:");
			}

		} elsif ($switch eq '0146') { # talk cancel
			my $npcID = substr($msg, 2, 4);
			if ($npcID eq $npcID1) {
				SendNpcImageShow($self, $client, $msg, $index, "kafra_04.bmp", 0xFF);
			}

		} elsif ($clientdata{$index}{mode}) {

			if (($switch eq '00F7' || $switch eq '0193') && (length($msg) == 2)) { # storage close
				my $data = pack("v1", 0xF8);
				$client->send($data);

			} elsif ($switch eq '00BF') { # emoticon
				my ($client, $code) = @_;
				my $data = pack("v1 a4", 0xC0, $accountID) . substr($msg, 2, 1);
				$clientdata{$index}{emoticonTime} = time;
				$client->send($data);

			} else {
				print "\nReceived packet $switch:\n";
				visualDump($msg, "$switch");

				# Just provide feedback in the RO Client about the unhandled packet
				# '008E' => ['self_chat', 'x2 Z*', [qw(message)]],
				my $data = pack("v2 a31", 0x8E, 35, "Sent packet $switch (" . length($msg) . " bytes).");
				if (timeOut($clientdata{$index}{emoticonTime}, 1.8)) {
					$clientdata{$index}{emoticonTime} = time;
					$data .= pack("v1 a4 C1", 0xC0, $accountID, 1);
				}

				# These following packets should reset the item inventory.
				# If you drop something from your inventory and the server didn't respond,
				# you will not be able to drop the item for the second test
				# This, however, does not cover item_use. YOu would have to relog
				# to test another item_use packet.
				#$data .= pack("v3", 0xAF, 3, 0);
				#$data .= pack("v3", 0xAF, 4, 0);

				# There are no other send packet that contains NPC ids as the last four byte
				# other than the talk and sendGetPlayerInfo packets.
				# Since most possible talk packets are handled above, we can assume that this is
				# a sendGetPlayerInfo packet.
				# Note that we have an NPC that is not named initially to allow a
				# sendGetPlayerInfo packet to be captured.)
				# '0095' => ['actor_info', 'a4 Z24', [qw(ID name)]],
				my $ID = substr($msg, length($msg) - 4, 4);
				if ($ID eq $npcID0) {
					$data .= pack("v1 a4 a24", 0x95, $npcID0, "Server Details Guide");
				} elsif ($ID eq $npcID1) {
					$data .= pack("v1 a4 a24", 0x95, $npcID1, "Kafra");
				}

				$client->send($data);
			}
		}
	}
}

# PACKET SENDING S->C

sub SendCharacterList
{
	my ($self, $client, $msg, $index) = @_;
	
	# Log
	print "Requested Char List (Standard)\n";
	
	# Wanted Block Size
	my $blocksize = $self->{type}->{$config{server_type}}->{charBlockSize} || 116; #defaults to 116

	# Packet Len, Total Characters and Total Slots
	my $totalchars = 2;
	my $totalslots = 12;
	my $len = $blocksize * $totalchars;
	
	# Character Block Pack String
	my $packstring = '';

	$packstring = 'a4 V9 v V2 v14 Z24 C8 v Z16 V x4 x4 x4' if $blocksize == 144;
	$packstring = 'a4 V9 v V2 v14 Z24 C8 v Z16 x4 x4' if $blocksize == 136;
	$packstring = 'a4 V9 v V2 v14 Z24 C8 v Z16 x4' if $blocksize == 132;
	$packstring = 'a4 V9 v V2 v14 Z24 C8 v Z16' if $blocksize == 128;
	$packstring = 'a4 V9 v V2 v14 Z24 C6 v2 x4' if $blocksize == 116;
	$packstring = 'a4 V9 v V2 v14 Z24 C6 v2' if $blocksize == 112;
	$packstring = 'a4 V9 v17 Z24 C6 v2' if $blocksize == 108;
	$packstring = 'a4 V9 v17 Z24 C6 v' if $blocksize == 106;
	
	# Unknown CharBlockSize
	if ( length($packstring) == 0 ) { print "Unknown CharBlockSize : $blocksize\n"; return; }
	
	# Character Block Format
	my($cID,$exp,$zeny,$jobExp,$jobLevel,$opt1,$opt2,$option,$stance,$manner,$statpt,$hp,$maxHp,$sp,$maxSp,$walkspeed,$jobId,$hairstyle,$weapon,$level,$skillpt,$headLow,$shield,$headTop,$headMid,$hairColor,$clothesColor,$name,$str,$agi,$vit,$int,$dex,$luk,$slot,$rename) = 0;

	# Preparing Begin of Character List Packet
	my $data;
	if ($self->{type}->{$config{server_type}}->{charListPacket} eq '0x82d') {
		$data = $accountID . pack("v2 C5 a20", 0x82d, $len + 29,$totalchars,0,0,0,$totalchars,-0); # 29 = v2 C5 a20 size for bRO
	} else {
		$data = $accountID . pack("v v C3", 0x6b, $len + 7, $totalslots, -1, -1);
	}
	
	# Character Block
	my $block;
	
	# Filling Character 1 Block
	$cID = $charID;	$hp = 10000; $maxHp = 10000; $sp = 10000; $maxSp = 10000; $hairstyle = 1; $level = 99; $headTop = 0; $hairColor = 6;
	$name = "Poseidon"; $str = 1; $agi = 1; $vit = 1; $int = 1; $dex = 1; $luk = 1;	$exp = 1; $zeny = 1; $jobExp = 1; $jobLevel = 50; $slot = 0; $rename = 0;
	
	# Preparing Character 1 Block
	$block = pack($packstring,$cID,$exp,$zeny,$jobExp,$jobLevel,$opt1,$opt2,$option,$stance,$manner,$statpt,$hp,$maxHp,$sp,$maxSp,$walkspeed,$jobId,$hairstyle,$weapon,$level,$skillpt,$headLow,$shield,$headTop,$headMid,$hairColor,$clothesColor,$name,$str,$agi,$vit,$int,$dex,$luk,$slot,$rename);

	# Attaching Block
	$data .= $block;
	
	# Filling Character 2 Block
	$cID = $charID;	$hp = 10000; $maxHp = 10000; $sp = 10000; $maxSp = 10000; $hairstyle = 1; $level = 99; $headTop = 0; $hairColor = 6;
	$name = "Poseidon Dev"; $str = 1; $agi = 1; $vit = 1; $int = 1; $dex = 1; $luk = 1;	$exp = 1; $zeny = 1; $jobExp = 1; $jobLevel = 50; $slot = 1; $rename = 0;
	
	# Preparing Character 2 Block
	$block = pack($packstring,$cID,$exp,$zeny,$jobExp,$jobLevel,$opt1,$opt2,$option,$stance,$manner,$statpt,$hp,$maxHp,$sp,$maxSp,$walkspeed,$jobId,$hairstyle,$weapon,$level,$skillpt,$headLow,$shield,$headTop,$headMid,$hairColor,$clothesColor,$name,$str,$agi,$vit,$int,$dex,$luk,$slot,$rename);		
	
	# Attaching Block
	$data .= $block;		
	
	# Measuring Size of Block
	print "Wanted CharBlockSize : $blocksize\n";		
	print "Built CharBlockSize : " . length($block) . "\n";

	$client->send($data);
}

sub SendMapLogin {
	my ($self, $client, $msg, $index) = @_;

	# '0073' => ['map_loaded','x4 a3',[qw(coords)]]
	my $data;
	
	if ( $config{server_type} !~ /^bRO/ ) { $data .= $accountID; } #<- This is Server Type Based !!
	$data .= pack("C*", 0x73, 0x00) . pack("V", getTickCount) . getCoordString($posX, $posY, 1) . pack("C*", 0x05, 0x05);

	if ($clientdata{$index}{mode}) {
		$data .= pack("C2 v1", 0x0F, 0x01, 226) .
			# skillID targetType level sp range skillName
			pack("v2 x2 v3 a24 C1", 1, 0, 9, 0, 1, "NV_BASIC" . chr(0) . "GetMapInfo" . chr(0x0A), 0) .
			pack("v2 x2 v3 a24 C1", 24, 4, 1, 10, 10, "AL_RUWACH", 0) . # self skill test
			pack("v2 x2 v3 a24 C1", 25, 2, 1, 10, 9, "AL_PNEUMA", 0) . # location skill test
			pack("v2 x2 v3 a24 C1", 26, 4, 2, 9, 1, "AL_TELEPORT", 0) . # self skill test
			pack("v2 x2 v3 a24 C1", 27, 2, 4, 26, 9, "AL_WARP", 0) . # location skill test
			pack("v2 x2 v3 a24 C1", 28, 16, 10, 40, 9, "AL_HEAL", 0); # target skill test
	}
	
	$client->send($data);
	
	$client->{connectedToMap} = 1;	
}

sub SendGoToCharSelection
{
	my ($self, $client, $msg, $index) = @_;
	
	# Log	
	print "Requested Char Selection Screen\n";	
	
	$client->send(pack("v v", 0xB3, 1));
}

sub SendQuitGame
{
	my ($self, $client, $msg, $index) = @_;
	
	# Log
	print "Requested Quit Game...\n";
	
	$client->send(pack("v v", 0x18B, 0));	
}

sub SendLookTo
{
	my ($self, $client, $msg, $index, $ID, $to) = @_;
	
	# Make Poseidon look to front
	$client->send(pack('v1 a4 C1 x1 C1', 0x9C, $ID, 0, $to));
}

sub SendUnitInfo		
{
	my ($self, $client, $msg, $index, $ID, $name) = @_;
	
	# Let's not wait for the client to ask for the unit info
	# '0095' => ['actor_info', 'a4 Z24', [qw(ID name)]],
	$client->send(pack("v1 a4 a24", 0x95, $ID, $name));
}

sub SendSystemChatMessage
{
	my ($self, $client, $msg, $index, $message) = @_;
	
	# '009A' => ['system_chat', 'v Z*', [qw(len message)]],
	$client->send(pack("v2 a32", 0x9A, 36, $message));
}

sub SendShowNPC
{
	my ($self, $client, $msg, $index, $obj_type, $GID, $SpriteID, $X, $Y, $MobName) = @_;
	
	# Packet Structure
	my ($object_type,$NPCID,$walk_speed,$opt1,$opt2,$option,$type,$hair_style,$weapon,$lowhead,$shield,$tophead,$midhead,$hair_color,$clothes_color,$head_dir,$guildID,$emblemID,$manner,$opt3,$stance,$sex,$xSize,$ySize,$lv,$font,$name) = 0;

	# Building NPC Data
	$object_type = $obj_type;
	$NPCID = $GID;
	$walk_speed = 0x1BD;
	$type = $SpriteID;
	$lv = 1;
	$name = $MobName;
	
	# '0856' => ['actor_exists', 'v C a4 v3 V v11 a4 a2 v V C2 a3 C3 v2 Z*', [qw(len object_type ID walk_speed opt1 opt2 option type hair_style weapon shield lowhead tophead midhead hair_color clothes_color head_dir costume guildID emblemID manner opt3 stance sex coords xSize ySize lv font name)]], # -1 # spawning provided by try71023
	my $dbuf;
	if ( $config{server_type} !~ /^bRO/ ) { $dbuf .= pack("C", $object_type); } #<- This is Server Type Based !!
	$dbuf .= pack("a4 v3 V v11 a4 a2 v V C2",$NPCID,$walk_speed,$opt1,$opt2,$option,$type,$hair_style,$weapon,$lowhead,$shield,$tophead,$midhead,$hair_color,$clothes_color,$head_dir,$guildID,$emblemID,$manner,$opt3,$stance,$sex);
	$dbuf .= getCoordString($X, $Y, 1);
	$dbuf .= pack("C2 v2",$xSize,$ySize,$lv,$font);
	$dbuf .= pack("Z" . length($name),$name);
	my $opcode;
	if ( $config{server_type} !~ /^bRO/ ) { $opcode = 0x858; } #<- This is Server Type Based !!
	$client->send(pack("v v",$opcode,length($dbuf) + 4) . $dbuf);
}

sub SendShowItemOnGround
{
	my ($self, $client, $msg, $index, $ID, $SpriteID, $X, $Y) = @_;
	
	# '009D' => ['item_exists', 'a4 v1 x1 v3', [qw(ID type x y amount)]]
	$client->send(pack("v1 a4 v1 x1 v3 x2", 0x9D, $ID, $SpriteID, $posX + 1, $posY - 1, 1));	
}

sub SendNPCTalk
{
	my ($self, $client, $msg, $index, $npcID, $message) = @_;
	
	# '00B4' => ['npc_talk', 'v a4 Z*', [qw(len ID msg)]]
	my $dbuf = pack("a" . length($message), $message);
	$client->send(pack("v2 a4", 0xB4, (length($dbuf) + 8), $npcID) . $dbuf);
}

sub SendNPCTalkContinue
{
	my ($self, $client, $msg, $index, $npcID) = @_;
	
	# '00B5' => ['npc_talk_continue', 'a4', [qw(ID)]]
	$client->send(pack("v a4", 0xB5, $npcID));
}

sub SendNpcTalkClose
{
	my ($self, $client, $msg, $index, $npcID) = @_;
	
	# '00B6' => ['npc_talk_close', 'a4', [qw(ID)]]
	$client->send(pack("v a4", 0xB6, $npcID));	
}

sub SendNpcTalkResponses
{
	my ($self, $client, $msg, $index, $npcID, $message) = @_;
	
	# '00B7' => ['npc_talk', 'v a4 Z*', [qw(len ID msg)]]
	my $dbuf = pack("a" . length($message), $message);
	$client->send(pack("v2 a4", 0xB7, (length($dbuf) + 8), $npcID) . $dbuf);	
}

sub SendNpcImageShow
{
	my ($self, $client, $msg, $index, $image, $type) = @_;

	# Type = 0xFF = Hide Image
	# Type = 0x02 = Show Image
	# '01B3' => ['npc_image', 'Z64 C', [qw(npc_image type)]]
	$client->send(pack("v a64 C1", 0x1B3, $image, $type));
}

# SERVER TASKS

sub PerformMapLoadedTasks
{
	my ($self, $client, $msg, $index) = @_;
	
	# Looking to Front
	SendLookTo($self, $client, $msg, $index, $accountID, 4);
	
	# Let's not wait for the client to ask for the unit info
	SendUnitInfo($self, $client, $msg, $index, $accountID, 'Poseidon' . (($clientdata{$index}{mode} ? ' Dev' : '')));
	
	# Global Announce
	SendSystemChatMessage($self, $client, $msg, $index, "Welcome to the Poseidon Server !");

	# Show an NPC
	SendShowNPC($self, $client, $msg, $index, 1, $npcID0, 86, $posX + 3, $posY + 4, "Server Details Guide");
	SendLookTo($self, $client, $msg, $index, $npcID0, 3);
	SendUnitInfo($self, $client, $msg, $index, $npcID0, "Server Details Guide");

	# Dev Mode (Char Slot 1)
	if ($clientdata{$index}{mode}) 
	{
		# Show an NPC (Kafra)
		SendShowNPC($self, $client, $msg, $index, 1, $npcID1, 114, $posX + 5, $posY + 3, "Kafra NPC");
		SendLookTo($self, $client, $msg, $index, $npcID1, 4);
		SendUnitInfo($self, $client, $msg, $index, $npcID1, "Kafra NPC");			
		
		# Show a monster
		SendShowNPC($self, $client, $msg, $index, 5, $monsterID, 1002, $posX - 2, $posY - 1, "Poring");
		SendLookTo($self, $client, $msg, $index, $monsterID, 3);
		SendUnitInfo($self, $client, $msg, $index, $monsterID, "Poring");
		
		# Show an item on ground
		SendShowItemOnGround($self, $client, $msg, $index, $itemID, 512, $posX + 1, $posY - 1);
	}
}

1;



Last edited by Break on 08 Apr 2016, 13:20, edited 1 time in total.

said
Noob
Noob
Posts: 3
Joined: 07 Jun 2010, 17:47
Noob?: No

Re: Request GG Problem Poseidon

#3 Post by said »

Ola,
Tenta alterar as keys no servertype

decrypt_mid_keys 0x708a594d 0x24461949 0x5e660a4b # K M A

Voce esta conseguindo logar mais de um bot por poseidon??

said
Noob
Noob
Posts: 3
Joined: 07 Jun 2010, 17:47
Noob?: No

Re: Request GG Problem Poseidon

#4 Post by said »

Ola,

Modifica a key no servertype decrypt_mid_keys 0x708a594d 0x24461949 0x5e660a4b # K M A

Esta conseguindo rodar mais de um bot por poseidon?

Break
Noob
Noob
Posts: 10
Joined: 01 Apr 2015, 16:41
Noob?: Yes

Re: Request GG Problem Poseidon

#5 Post by Break »

Ja utilizo essas keys.
No momento não estou rodando nenhum pois o poseidon não responde. rsrs
Mais quando responde só rodo 1 kore tbm por poseidon.
Quero mais rodar para por lojinha devido a não tomar dcs.

said
Noob
Noob
Posts: 3
Joined: 07 Jun 2010, 17:47
Noob?: No

Re: Request GG Problem Poseidon

#6 Post by said »

Realmente ele é mais estável que o xKore 2.
Eu vou nao estou conseguindo obter resposta do GG tambem, a request nao volta pro openkore.

Tentei usar seu QueryServer.pm mas parece que precisa de alguns arquivos e pastas extras, certo?

Vou testar por aqui, se obtiver algo êxito, posto.

Parece que o pessoal do bRO deu uma abandonada no Poseidon, todo mundo usando xKore.

Clou
Noob
Noob
Posts: 6
Joined: 11 Mar 2016, 10:52
Noob?: No

Re: Request GG Problem Poseidon

#7 Post by Clou »

Eu tenho muito interesse em usar o poseidon, mas nao tenho os arquivos para fazer isso. Um de vocês dois poderia me mandar PM pra me ajudar ? Eu entendo bastante de redes, trabalho com isso, queria começar a usar pra ver se consigo concertar o problema de 1 poseidon por boy.

Abs.,

Break
Noob
Noob
Posts: 10
Joined: 01 Apr 2015, 16:41
Noob?: Yes

Re: Request GG Problem Poseidon

#8 Post by Break »

Os arquivos são esses o QueryServe e o RagnarokServer.
E add a key semanal no Serves.txt

Clou
Noob
Noob
Posts: 6
Joined: 11 Mar 2016, 10:52
Noob?: No

Re: Request GG Problem Poseidon

#9 Post by Clou »

Break wrote:Os arquivos são esses o QueryServe e o RagnarokServer.
E add a key semanal no Serves.txt
Peguei os 3 arquivos dessa ultima semana.
Agora como consigo achar a key pra atualizar o servertype.txt ?

Abs.,

Clou
Noob
Noob
Posts: 6
Joined: 11 Mar 2016, 10:52
Noob?: No

Re: Request GG Problem Poseidon

#10 Post by Clou »

Clou wrote:
Break wrote:Os arquivos são esses o QueryServe e o RagnarokServer.
E add a key semanal no Serves.txt
Peguei os 3 arquivos dessa ultima semana.
Agora como consigo achar a key pra atualizar o servertype.txt ?

Abs.,
Na verdade, alguem poderia me mandar o servertype.txt ??

Locked