Jump to content
  • Register Now

    Sign up and take advantage of the features of our community! Some forums are only accessible to our members!

[HOW-TO] Fix Duplication of Items through Channel Switcher (tired of seeing who gets paid for it)


Recommended Posts

Hello community,

 

I have always seen people go crazy for this problem which is solved with 2 lines of code, in particular with the various offlineshops (mine, or the free release great and ken) that are unfairly blamed for having duplication bugs. No!


I believe that if you warp a player on another core without performing any checks you can't blame those who made the other systems which are then used to take advantage of the vulnerability you caused.


If you implement something you need to make sure there are adequate checks to avoid causing vulnerabilities. In my opinion the cause of the duplication is not the various offlineshops, but the channel switcher which does not perform not even half checks before executing the warp.

 

Anyway, no more chatter.
I will explain here how to fix this problem.

 

The first thing to check is if the channel switcher is using CHARACTER :: CanWarp to check if the player can be connected on a new channel or not.

 

here i wanna paste a commonly seen function channel switcher to connect the player (char.cpp):
 


void CHARACTER::ChannelSwitch(int iNewChannel){
    long lAddr;
    long lMapIndex;
    WORD wPort;
    long x = this->GetX();
    long y = this->GetY();

    if (!CMapLocation::instance().Get(x, y, lMapIndex, lAddr, wPort))
    {
        return;
    }

    if(lMapIndex >= 10000){
        return;
    }

    std::map<WORD, int>ch;

    for(int i = 0; i < 4; i++){
        for(int i2 = 1; i2 < 9; i2++){
            ch[30*1000 + i*100 + i2] = i+1;
        }
    }
    int chan;
    if(ch.find(wPort) != ch.end()){
        chan = ch[wPort];
    }else{return;}
    Stop();
    Save();

    if(GetSectree()){
        GetSectree()->RemoveEntity(this);
        ViewCleanup();

        EncodeRemovePacket(this);
    }

    TPacketGCWarp p;
    p.bHeader    = HEADER_GC_WARP;
    p.lX    = x;
    p.lY    = y;
    p.lAddr    = lAddr;
    p.wPort    = (wPort - 100*(chan-1) + 100*(iNewChannel-1));

    GetDesc()->Packet(&p, sizeof(TPacketGCWarp));
}


How you can see, no checks are performed to check if the character are using any systems which may give problems.

So Here what we need is to add CanWarp check at the beginning of the method.

 

void CHARACTER::ChannelSwitch(int iNewChannel){
    //* START DUPLICATION FIX
    //* prevent problems about duplication of items
    //* using safebox/exchange/shop/acce
    if(!CanWarp()){
      return;
    }
    //* END DUPLICATION FIX

    long lAddr;
    long lMapIndex;
    WORD wPort;
    long x = this->GetX();
    long y = this->GetY();

    if (!CMapLocation::instance().Get(x, y, lMapIndex, lAddr, wPort))
    {
      return;
    }

    if(lMapIndex >= 10000){
      return;
    }

    std::map<WORD, int>ch;

    for(int i = 0; i < 4; i++){
      for(int i2 = 1; i2 < 9; i2++){
        ch[30*1000 + i*100 + i2] = i+1;
      }
    }
    int chan;
    if(ch.find(wPort) != ch.end()){
      chan = ch[wPort];
    }else{return;}
    Stop();
    Save();

    if(GetSectree()){
      GetSectree()->RemoveEntity(this);
      ViewCleanup();

      EncodeRemovePacket(this);
    }

    TPacketGCWarp p;
    p.bHeader    = HEADER_GC_WARP;
    p.lX    = x;
    p.lY    = y;
    p.lAddr    = lAddr;
    p.wPort    = (wPort - 100*(chan-1) + 100*(iNewChannel-1));

    GetDesc()->Packet(&p, sizeof(TPacketGCWarp));
}

 

This is enoght to solve 100% of the problems if your CanWarp is a complete check about all your system installed.

If not, you just need to adapt CanWarp with the systems you have installed.
I will make an example with my offlineshop so that the speech is clear to anyone.

 

 

Let's take a look to the Default CanWarp method.
The first thing to note is that its purpose is obviously to return true if the player is able to reconnect without any problems.

 


bool CHARACTER::CanWarp() const
{
	const int iPulse = thecore_pulse();
	const int limit_time = PASSES_PER_SEC(g_nPortalLimitTime);

	if ((iPulse - GetSafeboxLoadTime()) < limit_time)
		return false;

	if ((iPulse - GetExchangeTime()) < limit_time)
		return false;

	if ((iPulse - GetMyShopTime()) < limit_time)
		return false;

	if ((iPulse - GetRefineTime()) < limit_time)
		return false;

	if (GetExchange() || GetMyShop() || GetShopOwner() || IsOpenSafebox() || IsCubeOpen())
		return false;
	return true;
}

 

How you can see here you can find a lot of checks which they are checking the last time of every auction may be used to take exploit the warp.
What we need to do here is to add new checks, to cover all the systems installed and fix all vulnerabilities.

 

An example about an offlineshop would be:
 

bool CHARACTER::CanWarp() const
{
	const int iPulse = thecore_pulse();
	const int limit_time = PASSES_PER_SEC(g_nPortalLimitTime);

	if ((iPulse - GetSafeboxLoadTime()) < limit_time)
		return false;

	if ((iPulse - GetExchangeTime()) < limit_time)
		return false;

	if ((iPulse - GetMyShopTime()) < limit_time)
		return false;

	if ((iPulse - GetRefineTime()) < limit_time)
		return false;

	if (GetExchange() || GetMyShop() || GetShopOwner() || IsOpenSafebox() || IsCubeOpen())
		return false;

#ifdef __ENABLE_NEW_OFFLINESHOP__
	if (iPulse - GetOfflineShopUseTime() < limit_time)
		return false;

	if (GetOfflineShopGuest() || GetAuctionGuest())
		return false;
#endif

	return true;
}

 

 

Note: I m using GetOfflineShopGuest and GetAuctionGuest which are methods used on my shop to get the pointer to the opened offlineshop/auction but if you are using another offlineshop system you need to find the equivalent way to check if the player is guest into a offline shop.

The method GetOfflineShopUseTime is a new method which i m implementing to check the last use time of the system.

Let's see how to implement it (char.cpp)

 

//SEARCH 
		void			ResetStopTime();
		DWORD			GetStopTime() const;

//ADD UNDER 

#ifdef __ENABLE_NEW_OFFLINESHOP__
  public:
		int			GetOfflineShopUseTime() const {return m_iOfflineShopUseTime;}
		void			SetOfflineShopUseTime(){m_iOfflineShopUseTime = thecore_pulse();}

  private:
		int			m_iOfflineShopUseTime = 0;
#endif

 

Here we are instantiating a new int where we can store the current time when player use the systemUsing SetOfflineShopUseTime the method will update the value of m_iOfflineShopUseTime and using GetOfflineShopUseTime we can check the last time player used the system (as done into CanWarp).

 

What's missing to do?
We need to use SetOfflineShopUseTime where the player is using our offlineshop (buy item, open shop, edit shop, close shop, ecc.) , so that the last use time is actually updated when needed, making the check in can warp effective.

A similar check can be done for other systems (eg acce system) to make our CanWarp safer and more effective.


I hope it's usefull.
Bye ;)

Edited by Ikarus_ (see edit history)
  • Love 17
  • Lucky 1
  • Rainbow 1

My youtube channel  on which you can see my works here

Link to post
  • 2 weeks later...
char.cpp: In member function 'bool CHARACTER::CanWarp() const':
char.cpp:8692:26: error: passing 'const CHARACTER' as 'this' argument discards qualifiers [-fpermissive]
  if (GetOfflineShopGuest() || GetAuctionGuest())
                          ^
In file included from char.cpp:4:0:
char.h:1348:24: note:   in call to 'offlineshop::CShop* CHARACTER::GetOfflineShopGuest()'
   offlineshop::CShop*  GetOfflineShopGuest() {return m_pkOfflineShopGuest;}
                        ^~~~~~~~~~~~~~~~~~~
char.cpp:8692:47: error: passing 'const CHARACTER' as 'this' argument discards qualifiers [-fpermissive]
  if (GetOfflineShopGuest() || GetAuctionGuest())
                                               ^
In file included from char.cpp:4:0:

any idea?

Link to post
22 hours ago, Ikarus_ said:

Set GetAutionGuest and GetOfflineShopGuest as const method

thanks, worked!

 

can you also maybe post where we have to add these time function when we used your offlineshop?

Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.