Register for your free account! | Forgot your password?

You last visited: Today at 17:03

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



Remap the "Create"-Button

Discussion on Remap the "Create"-Button within the SRO PServer Guides & Releases forum part of the SRO Private Server category.

Reply
 
Old   #1
 
elite*gold: 100
Join Date: Apr 2008
Posts: 860
Received Thanks: 1,487
Remap the "Create"-Button

Hello beloved, greedy, dead community,

it's time for another ( @ronz007 ). I've been asked quite often: "Can you change the 'Create Button' to lead directly to character creation?". I've had no viable solution for this, yet. But let's change that now.


Switching between states

Silkroad's internals is split into so different states. Joymax calls these states processes. Each process is represented by a single class. CPSCharacterSelect is the process showing all the characters. CPSCharacterCreateEurope is the process for creating an european character and CPSCharacterCreateChina is the equivalent for chinese characters.

The game will only run one process which is comprehensibly since the game can only have one state at a time. There are two different ways to change the state:

* Create a new process and replace the current one
* Create a child process and pause the current one

The character selection is made up of different states, too. We distinquish between transitional states and static states. Transitional states are run once, before entering or after leaving a static state. The transitional-state for leaving the character selection and entering the character creation looks like this:

Code:
if (m_cameraworking->float_F0 != m_cameraworking->float_E8 || m_pProcessChild)
  return;


if (g_selected_idol)
{
  if (g_selected_idol == 1)
  {
    current_state = 12;

    CIFWnd* loading_china = m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_LOADING_CHINA, 1);
    loading_china->SetVisibility(true);

    CIFWnd* frame = m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_LOADINGFRAME, 1);
    frame->SetVisibility(true);

    CIFWnd* loading_sta = m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_LOADING_STA, 1);
    loading_sta->SetVisibility(true);

    CIFGauge* gauge = m_ifbuilder.GetGUIObjectByID<CIFGauge>(PSCHARSEL_GDR_LOADINGG, 1);
    gauge->SetVisibility(true);
    gauge->progress_1 = 0;
    gauge->progress_2 = 0;

    loading_china->ApplyGlobalScale(1);
    frame->ApplyGlobalScale(0);
    loading_sta->ApplyGlobalScale(0); // guessed, one unknown call remained ...
    gauge->ApplyGlobalScale(0);

    //CGWnd::ApplyGlobalScale(a1, 0);

    theApp.sub_BA3FC0(0, 0);
    CreateAsChildProcess(GFX_RUNTIME_CLASS(CPSCharacterCreateChina), 1);
    theApp.RunProcessFromInstance(m_pProcessChild);
  }
  else
  {
    current_state = 12;

    CIFWnd* loading_china = m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_LOADING_CHINA, 1);
    loading_china->SetVisibility(true);

    CIFWnd* frame = m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_LOADINGFRAME, 1);
    frame->SetVisibility(true);

    CIFWnd* loading_sta = m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_LOADING_STA, 1);
    loading_sta->SetVisibility(true);

    CIFGauge* gauge = m_ifbuilder.GetGUIObjectByID<CIFGauge>(PSCHARSEL_GDR_LOADINGG, 1);
    gauge->SetVisibility(true);
    gauge->progress_1 = 0;
    gauge->progress_2 = 0;

    loading_china->ApplyGlobalScale(1);
    frame->ApplyGlobalScale(0);
    loading_sta->ApplyGlobalScale(0); // guessed, one unknown call remained ...
    gauge->ApplyGlobalScale(0);

    theApp.sub_BA3FC0(0, 0);
    CreateAsChildProcess(GFX_RUNTIME_CLASS(CPSCharacterCreateEurope), 1);
    theApp.RunProcessFromInstance(m_pProcessChild);
  }
}
The most interesting parts are these lines
Code:
current_state = 12;
// ...
CreateAsChildProcess(GFX_RUNTIME_CLASS(CPSCharacterCreateChina), 1);
theApp.RunProcessFromInstance(m_pProcessChild);
The two creation-processes are run as child processes. My best guess is, that completely switching over to either CPSCharacterCreateEurope or CPSCharacterCreateChina will litereally kill CPSCharacterSelect and therefore lose the network session and require a re-login. After creating a character, we will return to CPSCharacterSelect, so we need that process again, anyways.

So thats how we change to the creation of a character: Use a child process!

Finding the button handler

Lets investigate a little on where to make a change. Silkroad's UI event handling is quite weird. The control-id plays a big role in this.

Since Joymax were just a bunch of thieves .. EH!? ... I mean they got inspired from using MFC!, we just can look up how message handlers work in the MFC ... (oh, you can't imagine how long I reversed the MFC without noticing it's the MFC, again!!!).

With a bit of magic and a snap with your finger, you'll end up with the OnCreateButton_Click-handler being at 0x0085DE50. Swing your wand and smack your head on the keyboard to extract the pseudocode for this function:
Code:
void CPSCharacterSelect::OnCreateButton_Click()
{
  if ( this->current_charcount < CHAR_MAX_COUNT )
  {
    this->is_char_view = 3;
    this->TriggerCameraPathToIdolBox();
  }
  else
  {
    ShowError("UIO_MSG_ERROR_CHARACTER_OVER_3");
  }
}
Believe it or not, that's part of my workflow. If you don't have your wand with you, you can also search for the text-string shown in the pseudocode.

Do it!

So we're done now. We know where things happen. We know how things happen. So lets actually do it.

Lets wrap things up. We need to change the button handler to:

* Set the global g_selected_idol to CHINA (1)
* Set the state of CPSCharacterSelect to *leave for character creation* (9)
* Hope we did everything right.

Put all the ingredients in your bubbling cauldron, add a spoon of oldschool-player-tears and two cups of pulverized silkroad money. Give it a pretty good stirr. Okay. Done.
Code:
void CPSCharacterSelect::OnCreateButton_Click()
{
  if ( this->current_charcount < CHAR_MAX_COUNT )
  {
    g_selected_idol = 1;
    this->current_state = 9;
  }
  else
  {
    ShowError("UIO_MSG_ERROR_CHARACTER_OVER_3");
  }
}
Since most of you got confused by using C++ code, I will switch back to good old assembly for this one, eventho C++ would have been way more fun.

Code:
// g_selected idol is at 00EC2D64
mov dword ptr [00EC2D64], 1

// current_state is a member of the current object at offset 0xE4
// usually, this is referenced as ECX, but if the function gets bigger and has nested calls, ECX is transfered to ESI for simplicity reasons.
mov dword ptr [esi+E4], 9
Now where to put it?


We just have one problem: The instructions are too large . Both instructions are 10 Byte-instructions :/. We need to pad the epilogue.

Before:


After:


x64dbg Patch File, also appended as file.
Code:
>sro_client.exe
0045DEC4:C6->C7
0045DEC5:86->05
0045DEC6:2F->64
0045DEC7:01->2D
0045DEC8:00->EC
0045DECA:03->01
0045DECB:E8->00
0045DECC:D0->00
0045DECD:E5->00
0045DECE:FF->C7
0045DECF:FF->86
0045DED0:8B->E4
0045DED1:8C->00
0045DED2:24->00
0045DED3:04->00
0045DED4:01->09
0045DED7:5E->00
0045DED8:33->8B
0045DED9:CC->8C
0045DEDA:E8->24
0045DEDB:8E->04
0045DEDC:4D->01
0045DEDD:2E->00
0045DEDF:81->5E
0045DEE0:C4->31
0045DEE1:04->E1
0045DEE2:01->E8
0045DEE3:00->86
0045DEE4:00->4D
0045DEE5:C3->2E
0045DEE6:CC->00
0045DEE7:CC->81
0045DEE8:CC->C4
0045DEE9:CC->04
0045DEEA:CC->01
0045DEEB:CC->00
0045DEEC:CC->00
0045DEED:CC->C3

Note: All servers that appear in examples or images are for the sole purpose of testing. I'm not affiliated with any of these servers in any way.
Attached Files
File Type: zip patch_char_select.zip (382 Bytes, 247 views)
florian0 is offline  
Thanks
30 Users
Old 07/02/2018, 22:37   #2

 
XxGhostSpiriTxX's Avatar
 
elite*gold: 53
Join Date: Jul 2012
Posts: 542
Received Thanks: 191
Ahhhhh
XxGhostSpiriTxX is online now  
Old 07/03/2018, 12:33   #3
 
Isoline*'s Avatar
 
elite*gold: 0
Join Date: May 2006
Posts: 667
Received Thanks: 348
@florian0

i wouldnt say "useless" you can learn alot about the client infrastructure even while accomplishing this kind of a task.
nevertheless, i do think there might be something else to it, if you will.

Back in the days of iSRO (cap 60~80), when you would click "restart" when you are spawned in the worldserver already, you would be redirected to the char selection screen instead of the gatewayserver (login credentials screen), they did so for about quite a bit of a time (mby a few months), then they patched it back to the original one which is as it is now (looking back they reversed this change because it allowed people to be still connected to the worldserver, may i remind that back then without a premium gaining access to the server is a bit like teaching poetry to fish), knowing so, i tried to replicate the feature using my filter, with success but it had some problems due to the obvious limitation, it worked, but not perfectly for all of the users.

if you could think of a way to accomplish that old school feeling that would be great
hit me up on skype @ , if you want.
Isoline* is offline  
Thanks
2 Users
Old 07/03/2018, 13:31   #4
 
legendarynacar's Avatar
 
elite*gold: 0
Join Date: Jan 2015
Posts: 110
Received Thanks: 32
@eitai123 ; next time use mention rather than quoting a long thread.

Usage:
Quote:
Usage `[`mention=ID]value[/mention`]`
Example Usage `[`MENTION=687427]florian0[/MENTION`]`
Example Output @florian0;
Remove ` character
EDIT: IT seems ID parameter is a must.
EDIT2 : I confirmed from a mod in discord that we can use mentioning just with typing @Username. forum will parse it correctly.

Sorry for late reply.
legendarynacar is offline  
Old 07/03/2018, 13:42   #5
dotCom
 
Devsome's Avatar
 
elite*gold: 9842
The Black Market: 107/0/0
Join Date: Mar 2009
Posts: 16,856
Received Thanks: 4,683
Quote:
Originally Posted by florian0 View Post
Hello[...]
@florian0 , mention does not work in the sro section.

Gucci work as always.
Devsome is offline  
Thanks
1 User
Old 07/03/2018, 14:03   #6
 
elite*gold: 100
Join Date: Apr 2008
Posts: 860
Received Thanks: 1,487
Quote:
Originally Posted by eitai123 View Post
Back in the days of iSRO (cap 60~80), when you would click "restart" when you are spawned in the worldserver already, you would be redirected to the char selection screen instead of the gatewayserver [...]
I think I can "simulate" that with CPSQuickStart. CPSRestart could lead to CPSQuickStart instead of CPSTitle. You just need to grab the login credentials somehow ... It shouldn't need serverside modifications as long as the server is not "Crowded". Then you'll need some kind of privileged login for this char ...
florian0 is offline  
Old 07/03/2018, 14:40   #7
 
Isoline*'s Avatar
 
elite*gold: 0
Join Date: May 2006
Posts: 667
Received Thanks: 348
Quote:
Originally Posted by florian0 View Post
I think I can "simulate" that with CPSQuickStart. CPSRestart could lead to CPSQuickStart instead of CPSTitle. You just need to grab the login credentials somehow ... It shouldn't need serverside modifications as long as the server is not "Crowded". Then you'll need some kind of privileged login for this char ... maybe keep the session open in the filter and just reattach it ...
any way to contact you ? skype / discord ?
Isoline* is offline  
Old 07/04/2018, 12:50   #8

 
TrashBag's Avatar
 
elite*gold: 0
Join Date: May 2016
Posts: 319
Received Thanks: 85
can you skip the intro as well and we can Prelog to the launcher and keep it logged on so when we press start it show loading pic then my Char
TrashBag is offline  
Old 07/04/2018, 20:46   #9
 
elite*gold: 100
Join Date: Apr 2008
Posts: 860
Received Thanks: 1,487
I just figured something out: Those lazy devs at Joymax actually left the old behaviour of the button in the client. Its not even disabled, just skipped.
Code:
void CPSCharacterSelect::TriggerAnimation_ToIdolBox()
{
	// Fade Buttons and Text for idol selection
	m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_STA_TITLE, 1)->Fade(0, 5.0, 0.0, 1);
	m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_STA_REGIONTITLE, 1)->Fade(255, 5.0, 0.0, 1);
	m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_BTN_CREATE, 1)->Fade(0, 0.5, 0.0, 1);
	m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_BTN_BACK, 1)->Fade(0, 0.5, 0.0, 1);
	m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_BTN_CANCEL, 1)->Fade(255, 0.5, 0.0, 1);
	m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_BTN_NEXT, 1)->Fade(0, 0.5, 0.0, 1);
	m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_BTN_PREV, 1)->Fade(0, 0.5, 0.0, 1);

	// Fade name-change stuff
	for (int i = 0; i < ARRAY_SIZE(namechange_ids); ++i)
	{
		m_ifbuilder.GetGUIObjectByID(namechange_ids[i], 1)->Fade(0, 0.5, 0.0, 1);
	}

	// Preselect Idol
	g_selected_idol = 1;

	// Set state to leave for character creation
	current_state = 9;

	// Clear keyframes
	m_cameraworking->sub_4E6630();

	// Add keyframes to camera path.
	// Note: These are the same keyframes as you would
	//       have pressed the "Cancel" Button and leave
	Keyframe* current_frame = &frames_intro[0];
	for (int i = ARRAY_SIZE(frames_intro) - 1; i >= 0; --i, ++current_frame)
	{
		m_cameraworking->AddKeyframe(i * 2, current_frame->translation, current_frame->rotation);
	}

	theApp.camera.character = m_cameraworking->location;
	theApp.camera.rotation_to_world = m_cameraworking->rotation;
	theApp.camera.zoom = m_cameraworking->zoom;

	m_cameraworking->float_F0 = 2.0;

	// Fade to black
	m_ifbuilder.GetGUIObjectByID(PSCHARSEL_GDR_FADE, 1)->sub_6526E0(0, 255, 0.5, 0.0, 1);

	// Clear keyframes (RIP animation :/ )
	m_cameraworking->sub_4E6630();

	// Add keyframes to camera path.
	// Note: These keyframes lead to the box
	for (int i = 0; i < ARRAY_SIZE(frames_box); ++i)
	{
		m_cameraworking->AddKeyframe(i * 5.0 / 3.0, frames_box[i].translation, frames_box[i].rotation);
	}

	theApp.camera.character = m_cameraworking->location;
	theApp.camera.rotation_to_world = m_cameraworking->rotation;
	theApp.camera.zoom = m_cameraworking->zoom;

	m_cameraworking->float_F0 = 5.0;

	// Assign state for viewing the box
	current_state = 7;

	// Confirm state-change
	sub_862410(1);
}
As you can see, it's preparing to leave for Character Creation, but then just overrides everything and goes straight to the box.



Community challenge?
Task: Place the correct JMP to skip the second animation
Reward: Glory and honor
florian0 is offline  
Old 07/05/2018, 14:23   #10


 
MeGaMaX's Avatar
 
elite*gold: 50232
Join Date: Sep 2006
Posts: 1,089
Received Thanks: 2,606

Hey buddy, why don't you set the value to one of either cases like 0 or 1 that's represents the type of region you want to create character for.

for example in

PHP Code:
void  CPSCharacterSelect::OnCreateCharacter()
{
    if(
m_btCharacterCnt>= 8)
    {
        
wchar_t strErrCreateUpperToMax[128];
        
swprintf_s(strErrCreateUpperToMax_countof(strErrCreateUpperToMax) ,
            
TSM_GETTEXTPTR(L"UIO_MSG_ERROR_CHARACTER_OVER_3"), );
        
ErrorMessageIndirectstrErrCreateUpperToMax );
        return;
    }
    
m_btCurState 3// create character state.

/*
#ifdef MAX_CODE
    int regionType = 0
    switch(regionType)
    {
    case COUNTRY_CHINA: //0x00
            g_SelectedRegion = CHINA; //1
            m_pGfxMainFrame->SetProgressPos(0);
            CreateProcess(GFX_RUNTIME_CLASS(CPSCharacterCreateChina));
            m_pGfxMainFrame->SetProcess(GetChildProcess());
            break;
    case COUNTRY_EUROPE: ///0x01
        g_SelectedRegion = EUROPE;    //0
        m_pGfxMainFrame->SetProgressPos(0);
        CreateProcess(GFX_RUNTIME_CLASS(CPSCharacterCreateEurope));
        m_pGfxMainFrame->SetProcess(GetChildProcess());
        break;
    default:
        OnRegionMovein();
        break;
#else
    // before the client call the this hook it up and pass one of the cases either 0x00 for china or 0x01 for europe
    // g_nSelectedRegion
    OnRegionMovein();
#endif
*/

Greetings
MeGaMaX is offline  
Old 07/05/2018, 15:41   #11
 
elite*gold: 100
Join Date: Apr 2008
Posts: 860
Received Thanks: 1,487
Quote:
Originally Posted by MeGaMaX. View Post
Hey buddy, why don't you set the value to one of either cases like 0 or 1 that's represents the type of region you want to create character for.
I wanted to do that. I even had that solution prepared. But people told me they have a hard time finding Visual Studio 2005 (+DirectX SDK) for compiling, so I decided to do a "mini-edit" with assembly this time.

Setting g_SelectedRegion (g_selected_idol @ 0x00EC2D64) to china (1) and changing the state to "after clicking on an idol" seemed to be the easiest way. Isn't that similar to what you're suggesting?
florian0 is offline  
Old 07/05/2018, 17:07   #12


 
MeGaMaX's Avatar
 
elite*gold: 50232
Join Date: Sep 2006
Posts: 1,089
Received Thanks: 2,606
Quote:
Originally Posted by florian0 View Post
I wanted to do that. I even had that solution prepared. But people told me they have a hard time finding Visual Studio 2005 (+DirectX SDK) for compiling, so I decided to do a "mini-edit" with assembly this time.

Setting g_SelectedRegion (g_selected_idol @ 0x00EC2D64) to china (1) and changing the state to "after clicking on an idol" seemed to be the easiest way. Isn't that similar to what you're suggesting?
that's exactly what i meant
MeGaMaX is offline  
Old 07/06/2018, 21:01   #13
 
#HB's Avatar
 
elite*gold: 100
Join Date: Sep 2017
Posts: 1,110
Received Thanks: 907
Awesome as always.
#HB is offline  
Old 12/03/2018, 17:57   #14
 
elite*gold: 0
Join Date: Feb 2013
Posts: 79
Received Thanks: 10
i'm actually interested in doing it in C++
i'm trying to write some parts of the code the way you did
ZeonNETWORK is offline  
Old 04/08/2019, 18:31   #15
 
therock2007e's Avatar
 
elite*gold: 0
Join Date: Jul 2013
Posts: 516
Received Thanks: 376
any one can edit this and shere
therock2007e is online now  
Reply


Similar Threads Similar Threads
[Buying] """""PUBG Key""""""""
09/28/2017 - PlayerUnknown's Battlegrounds Trading - 5 Replies
Moin, ich suche noch einen Key von PUBG. Bezahle per PP.(kein Family& Friends) Nur mit RAT! mfg :mofo:
WEAPONSCRIPT!!!!!!!!!!!!!!!!!!!!!!!!!HOT"""""""""" """""""""""""""""""""
08/06/2011 - WarRock Hacks, Bots, Cheats & Exploits - 7 Replies
detetected



All times are GMT +1. The time now is 17:04.


Powered by vBulletin®
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2026 elitepvpers All Rights Reserved.