• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Using Flash Client in Ots

Yamaken

Pro OpenTibia Developer
Joined
Jul 27, 2013
Messages
534
Solutions
4
Reaction score
431
As OX team have said to have a working Flash Client implementation/hack i'm quit curious how to do it and i do think the community can benefits from it(why it should only be used in only one server?).

I'm just posting to put foward this discussion.

Now, about my hypothesis about how to make flash client connect in tfs/opentibia:

The tibia flash page html give us some few hints about how can do it.
The full source can be found here: http://pastebin.com/yNTghQA7

Look at this piece of code(flash launch code):

HTML:
                        tutorial:           false,
                        sessionKey:         "mLtKzzoeA2y9CPMv2WSI0qmHqRoscm",
                        sessionRefreshURL:  "https://secure.tibia.com/account/?subtopic=refresh",
                        accountData:        "%3CaccountData%3E%3Cworld+id%3D%220%22+name%3D%22Eldera%22+address%3D%2266.150.54.94%22+port%3D%227171%22+previewstate%3D%220%22+%2F%3E%3Ccharacter+name%3D%22Sain+Galus%22+worldid%3D%220%22+selected%3D%22true%22+%2F%3E%3C%2FaccountData%3E",
                        backgroundColor:    0x051122,
                        backgroundImage:    "https://a248.e.akamai.net/cipsoft.download.akamai.com/118500/tibia/static.tibia.com/images/account/play-background_artwork.png",
                        closeClientURL:     ""

Almost all of these data are used in game world login/authentication. Check the session key(10.73+ authetication), the parameters in accountData: there is the world, game server ip, game server port, character name, and other parameters i haven't figured out.

So my hypothesis is that we can modify these parameters and make it connect in our servers. Of course there is maybe some flash client custom protocols and such(which will make it more difficult to use) but as usual we need to do reverse engineering.

Having a descompiled Flash Client would help us alot i doing this thing. I have tried to descompile the current Flash Client but i failed.


Just to mention that i have made it in such a hurry so it will surely have edits in the future.

Ps: I want to use this topic to join information on this subject, feel free to speculate and investigate it :)
 
I think for decompile the flash client is necessary only a swf decompiler.
https://www.free-decompiler.com/flash/
Also, i sure which OX Team only changed the login information like in C++ client and with this they use the same client as cipsoft but in a hosted server of them. Most of internet games created in flash have that problem where someone get the files, host it and use for your own purposes
 
Think this is a thing worth bumping.

Have been working on this aswell, you can decompile it online problem I noticed is that it takes forever to copy it(the one I found diden't have a "copy the text" button) and that you have to use a prettify tool to make it easier to read(you get a one line code).

Created a quick php script that fetches the link from the catalog-client.xml and then downloads the spirit images, keep getting a debug tho.
Code:
An internal error occurred (Code: -2.0).

Additional debug information:
Error: Error #2048
Someone posted some old files, all I did was create a new acc on tibia and downloaded the files to update it to 10.76.

Have no ide what the error is, but gonna try and find out :p
Would really like to see a thing like this released, not fully setup.
But a thing to help servers that have active owners etc as most people know by now I don't support download and run servers.

But unless you already have decompiled the file here it is:
http://paste.ots.me/562532

Its ugly as f..k but still something to start with :p
But there are also more files you need ofc then just that one, some are listed here: https://secure.tibia.com/flash-regular-bin/catalog-tutorial-client.xml
The 415 spirit images, the dat file etc etc.

Edit: Forgot to upload the tibia.swf file. It's to big to add to paste.ots.me, so I uploaded it to mega.
It's saved as .java, makes it abit easier to read in notepad++ etc.
https://mega.co.nz/#!0Iw1lCDT!E0KaPqLkrKflmMt1rPuL8jECnN3hFSfmjYO_AnOHkpo


@totolol123 There is no reason to do that, since if you look in the file I posted above(tibia.swf) the login parameters are taken from the play.php file.
Code:
        public function AccountCharacter(_arg1:String, _arg2:String, _arg3:String, _arg4:String, _arg5:int, _arg6:uint){
            this.m_SessionKey = _arg1;
            this.m_Name = _arg2;
            this.m_World = _arg3;
            this.m_Address = _arg4;
            this.m_Port = _arg5;
            this.m_WorldPreviewState = _arg6;
        }
 
Last edited:
Guys,
After examening the flash client, it works complete different then any thread i've read.

After a fast look at the function and decompiling more then 4.swf files and 6 .xml files. This is the "picture" that i have at the moment.

1. There are 2 different preloaders.swf
1.1 One is based on character login preperation (Session settings, wich character etc. see below this line)
HTML:
                        tutorial:           false,
                        sessionKey:         "mLtKzzoeA2y9CPMv2WSI0qmHqRoscm",
                        sessionRefreshURL:  "https://secure.tibia.com/account/?subtopic=refresh",
                        accountData:        "%3CaccountData%3E%3Cworld+id%3D%220%22+name%3D%22Eldera%22+address%3D%2266.150.54.94%22+port%3D%227171%22+previewstate%3D%220%22+%2F%3E%3Ccharacter+name%3D%22Sain+Galus%22+worldid%3D%220%22+selected%3D%22true%22+%2F%3E%3C%2FaccountData%3E",
                        backgroundColor:    0x051122,
                        backgroundImage:    "https://a248.e.akamai.net/cipsoft.download.akamai.com/118500/tibia/static.tibia.com/images/account/play-background_artwork.png",
                        closeClientURL:     ""

1.2 Second one gather's user's flash client options that has been set by player (if it dosen't exist it will use a default one -> http://static.tibia.com/flash-data/1349698790-default-options.xml)

2. System generates a new .swf file for account or character (not sure yet if account or character based)
2.1 There are many swf files with different number ********-tibia.swf (see line above) <-> the swf checks cach memory of browser if in anycase
something does not match it will dissconnect and reload .swf and loads in a new cach in your browser.
2.2 If a *****-tibia.swf already exist for your account or character the preloader "injects" a new session key into ***-tibia.swf
(Also occures when creating and /or deleting characters)
2.3There is a refresh function of 900000 (Miliseconds) of the url (https://secure.tibia.com/account?subtopic=refresh) It refreshes the session key (script that refreshes key into .swf file -> https://secure.tibia.com/common/client_options_serverscript.php.

So bassicly it goes like this:
Tibia website clicked "Play" -> Preloader loads things -> sends to another Preloader to finish it off -> Generates files (if first time logged in) -> Loads specified ****-tibia.swf -> Playing on Flash Client.

Please note that this is based on reverse engineering & Decompiling of several .swf files.

That's all i have for now.
 
Guys,
After examening the flash client, it works complete different then any thread i've read.

After a fast look at the function and decompiling more then 4.swf files and 6 .xml files. This is the "picture" that i have at the moment.

1. There are 2 different preloaders.swf
1.1 One is based on character login preperation (Session settings, wich character etc. see below this line)
HTML:
                        tutorial:           false,
                        sessionKey:         "mLtKzzoeA2y9CPMv2WSI0qmHqRoscm",
                        sessionRefreshURL:  "https://secure.tibia.com/account/?subtopic=refresh",
                        accountData:        "%3CaccountData%3E%3Cworld+id%3D%220%22+name%3D%22Eldera%22+address%3D%2266.150.54.94%22+port%3D%227171%22+previewstate%3D%220%22+%2F%3E%3Ccharacter+name%3D%22Sain+Galus%22+worldid%3D%220%22+selected%3D%22true%22+%2F%3E%3C%2FaccountData%3E",
                        backgroundColor:    0x051122,
                        backgroundImage:    "https://a248.e.akamai.net/cipsoft.download.akamai.com/118500/tibia/static.tibia.com/images/account/play-background_artwork.png",
                        closeClientURL:     ""

1.2 Second one gather's user's flash client options that has been set by player (if it dosen't exist it will use a default one -> http://static.tibia.com/flash-data/1349698790-default-options.xml)

2. System generates a new .swf file for account or character (not sure yet if account or character based)
2.1 There are many swf files with different number ********-tibia.swf (see line above) <-> the swf checks cach memory of browser if in anycase
something does not match it will dissconnect and reload .swf and loads in a new cach in your browser.
2.2 If a *****-tibia.swf already exist for your account or character the preloader "injects" a new session key into ***-tibia.swf
(Also occures when creating and /or deleting characters)
2.3There is a refresh function of 900000 (Miliseconds) of the url (https://secure.tibia.com/account?subtopic=refresh) It refreshes the session key (script that refreshes key into .swf file -> https://secure.tibia.com/common/client_options_serverscript.php.

So bassicly it goes like this:
Tibia website clicked "Play" -> Preloader loads things -> sends to another Preloader to finish it off -> Generates files (if first time logged in) -> Loads specified ****-tibia.swf -> Playing on Flash Client.

Please note that this is based on reverse engineering & Decompiling of several .swf files.

That's all i have for now.

Weird what 2 preloaders did you find?
I only found 2 swf files in total.
The tibia.swf and preloader.swf.

The preloader sends it to the tibia.swf file.
All the "custom things" are stored in files as, playerid?-default-options.xml.

Gotten pretty far (I hope).
CcIi9RzMF.png


Tried to read abit in the tibia.swf file(where the error is thrown from) to see what it could be.
And I think I did something wrong, since we have to give it a worldID argument it most likely has to be a valid one.
What I THINK OX did was to remove the worldID argument from the tibia.swf file to be able to load it.

Since they closed the server I can't try to use the swf file they use, what I know by know is that the server ip, port etc is 100% handled by the play.php file.
Atleast that is what I think, it's trying to connect with a worldID package to TFS and it gets denied because of that.
Tried using -1, 0, 1 as the worldID but I keep getting the same output.

Another thing that has to be fixed is as you said the refreash page, aswell as storing the session key.
And about the numbers on the files, I think they are the player id, must be..
But at the same time, woulden't they try to fix a better system then having lets say 40.000 files for 10.000 players who have atleast tried it?

Edit: @Mokerhamer
You are actually wrong.
Just checked it again;

They only use 1 preloader.swf file, but loads it 2 times.
The first time they load it it only has 1 argument, false.
The second time they load it they include everything, like session key etc.

And at the second time they include the "nocache" argument to load the "id" value via:
Code:
        public static function s_NoCache(_arg1:String):String{
            var _local2 = "0123456789abcdef";
            var _local3 = "";
            var _local4:int;
            while (_local4 < 32) {
                _local3 = (_local3 + _local2.charAt(int((Math.random() * _local2.length))));
                _local4++;
            };
            if (_arg1.indexOf("?") > 0){
                return (((_arg1 + "&nocache=") + _local3));
            };
            return (((_arg1 + "?nocache=") + _local3));
        }

The same "id" value is sent to, flashclienthelper.js.

The encrypted names:
flashclienthelper.js = most likely the player id, same is sent to preloader.swf, name = nocache.
preloader.swf = -||-
catalog-client.xml = unique value, name = nocache.
catalog-conent.xml = unique aswell, most likely a version value or smth like that, name = nocache.
client_options_serverscript.php = unique value, name = nocache.
default-options-number.xml = weirdly a unique value aswell, should be the same for all "nocache" if it was linked to the player.
What I think, most of these values are time stamps, like a token key.
 
Last edited:
flash client in ots? hmm if gesior or znote add this to acc maker but i dont know how to add this to acc maker
 
Maybe its easier to simply make the client to automatically be installed to some java folder. (like runescape did long time ago)
But the client output is on the webpage and not as .exe file in computer.
 
Maybe its easier to simply make the client to automatically be installed to some java folder. (like runescape did long time ago)
But the client output is on the webpage and not as .exe file in computer.

If you mean that we should download the files to the server that is done.
If you mean that the end user should download it - why? Its a flash game.
 
If you mean that we should download the files to the server that is done.
If you mean that the end user should download it - why? Its a flash game.
ye, we got the client but we are not playing trough website.
Has been done? where? who?
 
yes but this method is using the client from server, not actually downloading it to your java folder.
Not sure though. didn't care to see or try ox server. Didn't impress me.

Well there is no point in downloading the files since it is a flash software.
No need to download the files to the end-users computer.
 
Well there is no point in downloading the files since it is a flash software.
No need to download the files to the end-users computer.
Runescape did it and it worked out great.
Play button still only appeared on the Webpage and that client was not exe file.
and you didnt have to wait for "dowloading or loading" screen when you got that file in java folder.
and whenever there was update to client it just took only few seconds to update the existing one.
 
Runescape did it and it worked out great.
Play button still only appeared on the Webpage and that client was not exe file.
and you didnt have to wait for "dowloading or loading" screen when you got that file in java folder.
and whenever there was update to client it just took only few seconds to update the existing one.

Well the thing I am after is just to get the flash client working, as it is supposed to be.
If you want to do it in another way you are welcome to do so ofc.
 
seems like whitevo is confusing java with flash lol xD I may be wrong but Wibbenz is trying to make it works just like cipsoft do and I may be wrong too but seems like whitevo doesn't know how cipsoft flash clients works (there is no need to download nor exe file)
 
Found out that the default-options is linked to the accountid.
Problem is that we can't push the accountid to the swf file without changing out some code and then recompile it.
Code:
    default-options-(accountid).xml

All other values in the file names are just a random number, that the preloader.swf file gives from this function:
Code:
public function addAsset(_arg1:AssetBase):void{

We could most likely get it to work, the problem will be the client option, that we need a way to get the accountid that the account actually has and use it to load that file from the flash-data directory.
Have still not had any luck with the connection problem, tried it on my VPS if it was my router but had the same issue there.
What I do know about the connection issue is that the server is thrown from one of these functions(only they are able to throw that error)

Code:
protected function onSocketClose(_arg1:Event):void{
protected function onSocketError(_arg1:ErrorEvent):void{

When comparing the connection time to tibia, it takes alot longer. My guess is that its the:
Code:
        protected function onDelayComplete(_arg1:TimerEvent):void{
            var a_Event:* = _arg1;
            if (a_Event != null){
                try {
                    this.m_ConnectionDelay.removeEventListener(TimerEvent.TIMER_COMPLETE, this.onDelayComplete);
                    this.m_ConnectionDelay.stop();
                    this.m_ConnectionDelay = null;
                    this.m_LastEvent = getTimer();
                    this.m_Socket.connect(this.m_Address, this.m_Port);
                } catch(e:Error) {
                    handleConnectionError(ERR_COULD_NOT_CONNECT, 0, e);
                };
            };
        }

Function that throws the error. And in that case the function with the bug is:
Code:
this.m_Socket.connect(this.m_Address, this.m_Port);
Code:
        public function connect(_arg1:IConnectionData):void{
            var _local4:String;
            if (!(_arg1 is AccountCharacter)){
                throw (new Error("Connection.connect: Invalid connection data.", 2147483639));
            };
            var _local2:AccountCharacter = (_arg1 as AccountCharacter);
            this.m_CurrentConnectionData = _local2;
            if ((((_local2.sessionKey == null)) || ((_local2.sessionKey.length < 1)))){
                throw (new Error("Connection.connect: Invalid session key.", 2147483638));
            };
            if ((((_local2.name == null)) || ((_local2.name.length < 1)))){
                throw (new Error("Connection.connect: Invalid character name.", 2147483636));
            };
            if ((((_local2.address == null)) || ((_local2.address.length < 1)))){
                throw (new Error("Connection.connect: Invalid server address.", 2147483635));
            };
            if ((((_local2.port < 0)) || ((_local2.port > 0xFFFF)))){
                throw (new Error("Connection.connect: Invalid port number.", 2147483634));
            };
            if (this.m_ConnectionState != CONNECTION_STATE_DISCONNECTED){
                throw (new Error("Connection.connect: Invalid state.", 2147483633));
            };
            this.m_XTEA.generateKey();
            if (this.m_Socket != null){
                this.removeListeners(this.m_Socket);
                this.m_Socket = null;
            };
            this.m_Socket = new Socket();
            this.addListeners(this.m_Socket);
            if (this.m_InputBuffer == null){
                this.createNewInputBuffer();
            };
            this.m_InputBuffer.clear();
            this.m_PacketReader.xtea = null;
            this.m_MessageWriter.registerMessageFinishedCallback(this.onMessageWriterFinished);
            if (Security.sandboxType != Security.LOCAL_TRUSTED){
                _local4 = (("xmlsocket://" + _local2.address) + ":843");
                Security.loadPolicyFile(_local4);
            };
            this.m_SessionKey = _local2.sessionKey;
            this.m_CharacterName = _local2.name;
            this.m_Address = _local2.address;
            this.m_Port = _local2.port;
            this.m_ConnectedSince = 0;
            this.setConnectionState(CONNECTION_STATE_CONNECTING_STAGE1);
            this.m_PingEarliestTime = 0;
            this.m_PingLatestTime = 0;
            this.m_PingTimeout = 0;
            this.m_PingCount = 0;
            this.m_PingTimer = new Timer(1000, 0);
            this.m_PingTimer.addEventListener(TimerEvent.TIMER, this.onCheckAlive);
            this.m_PingTimer.start();
            this.m_PingSent = 0;
            this.m_PingLatency = 0;
            if (this.m_ConnectionDelay != null){
                this.m_ConnectionDelay.removeEventListener(TimerEvent.TIMER_COMPLETE, this.onDelayComplete);
                this.m_ConnectionDelay.stop();
                this.m_ConnectionDelay = null;
            };
            var _local3:int = Math.max(0, ((this.m_LastEvent + RECONNECT_DELAY) - getTimer()));
            this.m_ConnectionDelay = new Timer(_local3, 1);
            this.m_ConnectionDelay.addEventListener(TimerEvent.TIMER_COMPLETE, this.onDelayComplete);
            this.m_ConnectionDelay.start();
        }

I know that the script can get to the connect function, since if I enter a session key that is not 30 characters it will throw that error.
 
Last edited:
You Guys are starting to confuse me...

http://Fortissimum.net i'm getting pretty far, when u creat an account and push "Play" it starts to load but gets canceled because it cant download files.

//Still working on it tough.
 
You Guys are starting to confuse me...

http://Fortissimum.net i'm getting pretty far, when u creat an account and push "Play" it starts to load but gets canceled because it cant download files.

//Still working on it tough.

Ye I was at that stage mby a week ago haha.
A tip is that you use the console to see if it throws any errors.
In this case:
Code:
GET http://fortissimum.net/pages/catalog-client.xml?nocache=1439394e623284fb87362cf776c9a1b9 404 (Not Found)
catalog-content.xml:1 GET http://fortissimum.net/pages/catalog-content.xml?nocache=4aec19617fbdb0cc2c63e0df42cc48a0 404 (Not Found)

You don't fetch the account characters, so the characters will never load.
Code:
value="tutorial=false&sessionKey=Z0TfopM1Jt9qRkp3AKFYz9Rzl5E9p6&sessionRefreshURL=https://secure.tibia.com/account/?subtopic=refresh&accountData=%3CaccountData%3E%3Cworld+id%3D%220%22+name%3D%22Aurera%22+address%3D%2266.150.54.41%22+port%3D%227171%22+previewstate%3D%221%22+%2F%3E%3Cworld+id%3D%221%22+name%3D%22Aurora%22+address%3D%22193.200.156.61%22+port%3D%227171%22+previewstate%3D%221%22+%2F%3E%3Cworld+id%3D%222%22+name%3D%22Inferna%22+address%3D%22193.200.156.19%22+port%3D%227171%22+previewstate%3D%220%22+%2F%3E%3Cworld+id%3D%223%22+name%3D%22Secura%22+address%3D%22193.200.156.121%22+port%3D%227171%22+previewstate%3D%220%22+%2F%3E%3Ccharacter+name%3D%22Aticus+The+Dreadful%22+worldid%3D%223%22+%2F%3E%3Ccharacter+name%3D%22Captain+Flame%22+worldid%3D%221%22+%2F%3E%3Ccharacter+name%3D%22Captain+Teague%22+worldid%3D%223%22+selected%3D%22true%22+%2F%3E%3Ccharacter+name%3D%22Demiterios%22+worldid%3D%223%22+%2F%3E%3Ccharacter+name%3D%22Dylan+Van+Kerrebroeck%22+worldid%3D%222%22+%2F%3E%3Ccharacter+name%3D%22Elder+Charger%22+worldid%3D%223%22+%2F%3E%3Ccharacter+name%3D%22Elethernia%22+worldid%3D%222%22+%2F%3E%3Ccharacter+name%3D%22Ingentique%22+worldid%3D%223%22+%2F%3E%3Ccharacter+name%3D%22Intemerata%22+worldid%3D%223%22+%2F%3E%3Ccharacter+name%3D%22Rath+Neth%22+worldid%3D%223%22+%2F%3E%3Ccharacter+name%3D%22Sir+Teague%22+worldid%3D%220%22+%2F%3E%3Ccharacter+name%3D%22Teague+Junior%22+worldid%3D%223%22+%2F%3E%3C%2FaccountData%3E&backgroundColor=332066&backgroundImage=https://a248.e.akamai.net/cipsoft.download.akamai.com/118500/tibia/static.tibia.com/images/account/play-background_artwork.png&closeClientURL="


And I wounder how you think you got far, when you still are trying to connect to tibia's server ;)
Code:
193.200.156.61



Edit:
When the connection starts the following files are loaded:
client_options_sevrerscript.php
defaut-options.xml

But when the error "Could not connect to the game server. Please try again later." is thrown the file client_options_sevrerscript.php is loaded again.

The first time the file is loaded its a GET method, while the second time its a POST method.

My guess is now that the problem is with that file, that it can't load it.
 
Last edited:
Back
Top