Dedicated xkore2 account char server

This section is created for developers and non-developers who think that he/she has a good (and realistic) idea that might contribute to the OpenKore community.

Moderator: Moderators

Message
Author
User avatar
lolzorbot
Noob
Noob
Posts: 18
Joined: 28 Apr 2010, 16:20
Noob?: No

Dedicated xkore2 account char server

#1 Post by lolzorbot »

first of all i am loving the fact that xkore2 is working again!
no more remembering all of the complicated passwords that all the bots have!

but i would like to have a dedicated account + character server (at-least per servertype)
so i can switch between bots very quickly just by clicking on "option" and selecting "Character Select"

EternalHarvest
Developers
Developers
Posts: 1798
Joined: 05 Dec 2008, 05:42
Noob?: Yes

Re: Dedicated xkore2 account char server

#2 Post by EternalHarvest »

Proof of concept for dedicated account (only) server exists: http://rofan.ru/viewtopic.php?t=4861

Character select isn't useful in this one, as there's no dedicated character server.

User avatar
lolzorbot
Noob
Noob
Posts: 18
Joined: 28 Apr 2010, 16:20
Noob?: No

Re: Dedicated xkore2 account char server

#3 Post by lolzorbot »

Thanks! will take a look at it
and maybe modify it to have a charater server :D

i took a look at it nice code but,
it now has a gaping security hole in that the charater server now accepts any session
you should have used the bus system to send the sessionid and register in the sessionstore
that way you dont have to modify the charserver.pm

i had to hack the trident.pl a bit to get it to load the stuff from the correct folder
but its still not working correctly T_T
the trident gets the info about the other openkore charater server
but either its send the wrong info about the charater server or its sending mangled packets

Code: Select all

#!/usr/bin/env perl
use strict;

use constant CONTROL_FOLDER => 'control/trident';
use constant TABLES_FOLDER => 'tables';
use constant BUS_AGENT => 'Trident';
use constant SLEEP_TIME => 0.01;
use constant CHECK_TIMEOUT => 5;
use constant CHECK_TIMEOUT_PLAY => 5;

use FindBin qw($RealBin);
use lib "$RealBin";
use lib "$RealBin/src";
use lib "$RealBin/src/deps";
use Time::HiRes qw(time sleep);
use Encode;

use Base::Ragnarok::SessionStore;
use Bus::Client;
use Bus::Handlers;
use FileParsers;
use Settings;
use Misc;

our (%sys, %config, %rpackets, %masterServers, $masterServer);
my ($accountServer, $sessionStore);
my ($bus, $busMessageHandler);

sub initialize {
	printLine("Starting Trident...");
   
	no encoding 'utf8';
	
    # load OpenKore settings
    Settings::setControlFolders(CONTROL_FOLDER);
    Settings::setTablesFolders(TABLES_FOLDER);
    Settings::addControlFile(Settings::getConfigFilename(), loader => [\&parseConfigFile, \%config], autoSearch => 0);
      
   	# Loading of Table files
	# Load Servers.txt first
	Settings::addTableFile('servers.txt',
		loader => [\&parseSectionedFile, \%masterServers],
		onLoaded => \&processServerSettings);
		
	# Load RecvPackets.txt second
 	Settings::addTableFile(Settings::getRecvPacketsFilename(),
 		loader => [\&parseDataFile2, \%rpackets]);   
   
   Settings::loadSysConfig();
   my $progressHandler = sub {
      printLine ("Loading ".(shift)."...");
   };
   Settings::loadAll($progressHandler);
   
   unless ($masterServer = $masterServers{$config{master}}) {
      printLine ("Check your masterServer!");
      die;
   }
      
   printLine ("Starting account server...");
   $sessionStore = new Base::Ragnarok::SessionStore ();
   $accountServer = new Trident::AccountServer (
      host => $config{trident_listenIp},
      port => $config{trident_listenPort} || 6900,
      serverType => $masterServer->{serverType},
      rpackets => \%rpackets,
      charServer => new Trident::DummyCharServer ({title => 'Dummy', dummy => 1}),
      sessionStore => $sessionStore
   );
   
   printLine ("Initializing bus...");
   my $busHost = $sys{bus_server_host};
   my $busPort = $sys{bus_server_port};
   $busHost = undef if $busHost eq '';
   $busPort = undef if $busPort eq '';
   $bus = new Bus::Client(host => $busHost, port => $busPort, userAgent => BUS_AGENT);
   $busMessageHandler = new Bus::Handlers ($bus);
   $bus->onMessageReceived->add (undef, \&onBusMessage);
   
   # generate xml file for Ragnarok client
   makeXml ();
   printLine ("Trident.xml generated in OpenKore folder.");
   printLine ("Copy it to RO client's data folder and run 'ragexe 1rag1 /account:Trident.xml'.");
   
   printLine ("-" x 79);
}

sub processServerSettings {
###########
## TODO use the actual original function located in functions.pl
## NOTE: sub stolen from functions.pl
###########
	my $filename = shift;
	# Select Master server on Demand

	if ($config{master} eq "" || $config{master} =~ /^\d+$/ || !exists $masterServers{$config{master}}) {
		die("bad master server config");
	}

	# Parse server settings
	my $master = $masterServer = $masterServers{$config{master}};
	
	# Check for required options
	# TODO: add more besides serverType, if any exist
	if (my @missingOptions = grep { $master->{$_} eq '' } qw(serverType)) {
		die(TF("Required server options are not set: %s\n", "@missingOptions"));
		exit;
	}
	
	foreach my $serverOption ('serverType', 'chatLangCode', 'storageEncryptKey', 'gameGuard', 'charBlockSize',
				'paddedPackets', 'paddedPackets_attackID', 'paddedPackets_skillUseID',
				'mapServer_ip', 'mapServer_port') {
		if ($master->{$serverOption} ne '' && $config{$serverOption} ne $master->{$serverOption}) {
			# Delete Wite Space
			# why only one, if deleting any?
			$master->{$serverOption} =~ s/^\s//;
			# can't happen due to FileParsers::parseSectionedFile
			$master->{$serverOption} =~ s/\s$//;
			# Set config
			configModify($serverOption, $master->{$serverOption});
		}
	}

	if ($master->{serverEncoding} ne '' && $config{serverEncoding} ne $master->{serverEncoding}) {
		configModify('serverEncoding', $master->{serverEncoding});
	} elsif ($config{serverEncoding} eq '') {
		configModify('serverEncoding', 'Western');
	}
	
	# Process adding Custom Table folders
	if($masterServer->{addTableFolders}) {
		Settings::addTablesFolders($masterServer->{addTableFolders});
	}
	
	# Process setting custom recvpackets option
	Settings::setRecvPacketsName($masterServer->{recvpackets} && $masterServer->{recvpackets} ne '' ? $masterServer->{recvpackets} : Settings::getRecvPacketsFilename() );
}

sub iterate {
   my $i = 0;
   while ($i < scalar @{$accountServer->{charServers}}) {
      if (${$accountServer->{charServers}}[$i]{dummy}
      || ${$accountServer->{charServers}}[$i]{seen}
      + ${$accountServer->{charServers}}[$i]{timeout} + CHECK_TIMEOUT_PLAY < time) {
         unless (${$accountServer->{charServers}}[$i]{dummy}) {
            printLine("Gone: ${$accountServer->{charServers}[$i]}{title}");
         }
         splice(@{$accountServer->{charServers}}, $i, 1);
      } else {
         $i++;
      }
   }
}

sub makeXml {
   open my $f, '>Trident.xml';
   print $f '<?xml version="1.0" encoding="euc-kr" ?>

<clientinfo>
   <servicetype>korea</servicetype>
   <servertype>sakray</servertype>
   <hideaccountlist></hideaccountlist>
   <extendedslot></extendedslot>

   <connection>
      <display>Trident</display>
      <desc>None</desc>
      <address>'.$accountServer->getHost ().'</address>
      <port>'.$accountServer->getPort ().'</port>
      <version>'.$masterServer->{version}.'</version>
      <registrationweb>http://openkore.com/</registrationweb>
   </connection>
</clientinfo>';
   
   close $f;
}

sub onBusMessage {
   my (undef, undef, $msg) = @_;
   if ($msg->{messageID} eq 'Trident/Presence') {
      # client's server selection screen doesn't display utf8?
      $msg->{args}{title} = encode('cp1251', $msg->{args}{title});
	  
      for (my $i = 0; $i < scalar @{$accountServer->{charServers}}; $i++) {
         if (${$accountServer->{charServers}}[$i]{id} eq $msg->{args}{id}) {
            printLine("Still alive: $msg->{args}{title}\@$msg->{args}{host}:$msg->{args}{port} ($i)");
            copyProperties(${$accountServer->{charServers}}[$i], $msg->{args});
            ${$accountServer->{charServers}}[$i]{seen} = time;
            return;
         }
      }
      
      printLine("New client: $msg->{args}{title}\@$msg->{args}{host}:$msg->{args}{port} (".scalar @{$accountServer->{charServers}}.")");
      push @{$accountServer->{charServers}}, new Trident::DummyCharServer ($msg->{args});
   }
}

sub copyProperties {
   my ($target, $source) = @_;
   foreach (keys %$source) {
      $target->{$_} = $source->{$_};
   }
}

sub printLine() {
   no warnings;
   print shift . "\n";
}

sub __start {
   initialize ();
   while (1) {
      iterate();
      $bus->iterate() if $bus;
      $accountServer->iterate() if $accountServer;
      
      sleep SLEEP_TIME;
   }
}

__start() unless defined $ENV{INTERPRETER};

{
   package Trident::DummyCharServer;
   use strict;
   
   sub new {
      my ($class, $self) = @_;
	  $self->{seen} = time;
	  return bless $self => $class;
   }
   
   sub getHost { return shift->{host} }
   sub getPort { return shift->{port} }
   sub getName { return shift->{title} }
   sub getPlayersCount {return shift->{online} }
}

{
   package Trident::AccountServer;
   use strict;
   use Base::Ragnarok::AccountServer;
   use base qw(Base::Ragnarok::AccountServer);
   
   sub login {
      my ($self, $session, $username, $password) = @_;
      
	  $session->{accountID} = pack("V", 123456);
	  $session->{sex} = 0;
	  $session->{dummy} = 1;
      #$session->{sex} = $username =~ /female/i ? 0 : 1;
      
      if ($main::config{trident_password} and $main::config{trident_password} ne $password) {
         return Base::Ragnarok::AccountServer::PASSWORD_INCORRECT;
      } else {
         return Base::Ragnarok::AccountServer::LOGIN_SUCCESS;
      }
   }
}
also the login hack on the charater server (src/Base/Ragnarok/CharServer.pm)
needed some work

find this

Code: Select all

	# maybe sessionstore should store sessionID as bytes?
	my $session = $self->{sessionStore}->get(unpack('V', $args->{sessionID}));
replace with this

Code: Select all

	# evil hack to accept any session as a valid one!
	my $session = {accountID => $args->{accountID}, sessionID => unpack('V', $args->{sessionID}), sessionID2 => unpack('V', $args->{sessionID}), sex => $args->{accountSex}};
	$self->{sessionStore}->add($session);
	$session->{state} = 'About to select character';

Post Reply