Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

return worldserver info to client

Status
Not open for further replies.
Newbie Spellweaver
Joined
Oct 4, 2022
Messages
38
Reaction score
54
Hello its me once again ..:D:
Im still working on my little teleporter system that i mentioned before to learn some stuff about the flyff source.
(Thanks to Fenris and Ketchup for giving me tips for the server/client sided security and explanations)

so the last feature that is missing in the teleporter is do display the drops in the interface by the mover id defined in the resource

And yeah i understand how it "should" work and that i need to call the items in the world server and return it back to the client since dropitems are server sided

but... after trying to understand it from looking at stuff like Drop log or drop info (DC files) im just left with confusion
(not the code itself for the drop items, the part where you get the info from the world back to the client)


it would help me alot if someone could break it down how to send data between world and client

Thanks in advance
 
Newbie Spellweaver
Joined
Dec 27, 2022
Messages
26
Reaction score
3
While I was checking resources folder on another flyff files, I noticed there was a Teleporter.txt
create one and list the items. Then merge. See if it works
 
Last edited:
Upvote 0
Newbie Spellweaver
Joined
Oct 4, 2022
Messages
38
Reaction score
54
That's not the issue i made my own resource file that hass the monster id of the boss
my goal is to send the monster id to the world server and return a array of item indexes

but that is not the part i need help with
 
Upvote 0
Newbie Spellweaver
Joined
Sep 8, 2011
Messages
67
Reaction score
252
So, Ill go over some options you have here after going over the communication between the worldserver and the user.

Every 200ms, a list of buffers stored of actions / responses is sent from the server to the client. This is found within CUser::process(). There is a function called, CUser::Notify.

Code:
int	CUser::Notify()
{
	if (!IsValid())
		return 0;

	if (m_dwDestroyTime)
		return 0;

	static unsigned int uOffset = sizeof(DPID) + sizeof(unsigned long) + sizeof(unsigned long) + sizeof(short);
	int nBufSize;
	if (m_Snapshot.cb > 0)
	{
		unsigned char* lpBuf = m_Snapshot.ar.GetBuffer(&nBufSize);
		*reinterpret_cast<__unaligned unsigned short*>(lpBuf + sizeof(DPID) + sizeof(unsigned long) + sizeof(unsigned long)) = m_Snapshot.cb;

		g_DPSrvr.Send(lpBuf, nBufSize, m_Snapshot.dpidCache);
		*reinterpret_cast<__unaligned unsigned long*>(lpBuf + sizeof(DPID)) = PACKETTYPE_SNAPSHOT;

		m_Snapshot.cb = 0;
		m_Snapshot.ar.ReelIn(uOffset);
		return nBufSize;
	}
	return 0;
}

Those snapshots are made by a lot of CUser function calls which continually serializes more and more data to a buffer till eventually it is sent out.

The following sends the buffer to the cacheserver with the users cache id:
Code:
g_DPSrvr.Send(lpBuf, nBufSize, m_Snapshot.dpidCache);

The worldserver is connected to the Cacheserver and the cacheserver is connected to the clients. Because the packet header isn't a system header it would be getting routed to the UserMessageHandler.
PHP:
CDPCacheSrvr::UserMessageHandler

A free fix from v21.2 is stored here as well:
PHP:
	CPlayer* pPlayer = CPlayerMng::Instance()->GetPlayer(idFrom);
	if (!pPlayer) 
		return;

	PACKET_HANDLER_FUNC pfn = GetHandler(dw);

but down below there is:
PHP:
			default:
				g_DPClientArray.SendToServer( idFrom, lpMsg, dwMsgSize );
				break;

So, if the function isn't found in the std::map of function pointers and it isn't a set of packets (for the coreserver), they get routed to the client.

Then sent to the clients UserMessageHandler and then to the OnSnapShot function. Where it will loop over the network buffer and apply the list of "snapshotted" network buffers.

PHP:
unsigned char g_hdr, g_Prev;
void CDPClient::OnSnapshot(CAr& ar)

Meaning, if there is one error within a 200ms network buffer, and the buffer for that specific individual snapshot isn't extracted fully, data can be mismatched for the next loops until that specific round of execution.



Now, you can send a packet from the client to request the drop information for a monster when required, and then the worldserver can respond. You can even change it to make it work faster too for that individual packet if you wanted. Another alternative is, you can send the drop list whenever from the server to the client. Lastly, there's the alternative of just loading the drop table locally but that will expose all the drops visually but most are already exposed, no?

My personal preference would either be the first or the last. If you're having a dynamic drop table where you're reloading the drops on the server without rebooting the server, (Ie: editing the drop system a bit) then the first. Otherwise, the last. If you're not changing the drops, might as well trade off a little load time compared to the other alternatives.
 
Last edited:
Upvote 0
Newbie Spellweaver
Joined
Oct 4, 2022
Messages
38
Reaction score
54
Thanks again :)
This helped me alot even tho i used the last option kinda

i compared the mover id with my tpdata mover id and added the items id while loading the propmoverex.inc

Code:
[COLOR=#000000]            [COLOR=#0000ff]if[/COLOR]( script.Token == [COLOR=#a31515]"DropItem"[/COLOR] )
            {
                DROPITEM di;
                memset( &di, [COLOR=#098658]0[/COLOR], [COLOR=#0000ff]sizeof[/COLOR](DROPITEM) );
                di.dtType = DROPTYPE_NORMAL;
                script.GetToken();[COLOR=#008000]  // ([/COLOR]
                di.dwIndex  = script.GetNumber();[COLOR=#008000]   // specific item index[/COLOR]
                [COLOR=#0000ff]if[/COLOR]( di.dwIndex == [COLOR=#098658]0[/COLOR] )
                    Error( [COLOR=#a31515]"%s : %s�� defineItem.h�� ���ǵ��� �ʾ���"[/COLOR], szFileName, script.token );
                ASSERT( di.dwIndex != [COLOR=#098658]0[/COLOR] );
                script.GetToken();[COLOR=#008000]  // ,[/COLOR]
                di.dwProbability    = script.GetNumber();[COLOR=#008000]   // probability[/COLOR]
                script.GetToken();[COLOR=#008000]  // ,[/COLOR]
                di.dwLevel  = script.GetNumber();[COLOR=#008000]   // level[/COLOR]
                script.GetToken();[COLOR=#008000]  // ,[/COLOR]
                di.dwNumber = script.GetNumber();[COLOR=#008000]   // number[/COLOR]
                script.GetToken();[COLOR=#008000]  // )[/COLOR]
[COLOR=#0000ff]#ifdef __WORLDSERVER[/COLOR]
                pProp->m_DropItemGenerator.AddTail( di, pProp->szName );[COLOR=#008000]    // copy[/COLOR]
[COLOR=#0000ff]#endif[/COLOR]
                di.dwNumber2 = [COLOR=#098658]0[/COLOR];

[COLOR=#0000ff]#ifdef __SYS_TELE16[/COLOR]
[COLOR=#0000ff]#ifdef __CLIENT[/COLOR]
            [COLOR=#0000ff]for[/COLOR]([COLOR=#0000ff]int[/COLOR] i = [COLOR=#098658]0[/COLOR]; i < prj.TPData.size(); i++)
            {
                [COLOR=#0000ff]if[/COLOR](nVal == prj.TPData[i].dwBossID)
                {
                    [COLOR=#0000ff]if[/COLOR](ItemProp * pProp = prj.GetItemProp(di.dwIndex))
                    {
                        [COLOR=#0000ff]if[/COLOR](pProp->dwItemKind3 == IK3_EGG[COLOR=#008000] //eggers[/COLOR]
                        || pProp->dwItemKind3 == IK3_SMELT_GENERAL_MATERIAL[COLOR=#008000] //sunstone[/COLOR]
                        || pProp->dwItemKind3 == IK3_SMELT_ULTIMATE_MATERIAL[COLOR=#008000] //shini[/COLOR]
                        || pProp->dwItemKind3 == IK3_SMELT_ACCESSORY_MATERIAL[COLOR=#008000] //moonstone[/COLOR]
                        || pProp->dwItemKind3 == IK3_ULTIMATE[COLOR=#008000] //dias[/COLOR]
                        || pProp->dwItemKind3 == IK3_GEM[COLOR=#008000] //quest items[/COLOR]
                        )
                            [COLOR=#0000ff]continue[/COLOR];

                        [COLOR=#0000ff]if[/COLOR](pProp->dwItemKind1 == IK1_ARMOR && pProp->dwItemLV <= [COLOR=#098658]105[/COLOR])
                            [COLOR=#0000ff]continue[/COLOR];

                        [COLOR=#0000ff]if[/COLOR](pProp->dwItemKind1 == IK1_WEAPON )
                        {
                            [COLOR=#0000ff]bool[/COLOR] bValidWeapon = ( pProp->dwReferStat1 == WEAPON_UNIQUE || pProp->dwReferStat1 == WEAPON_ULTIMATE );

                            [COLOR=#0000ff]if[/COLOR](!bValidWeapon)
                                [COLOR=#0000ff]continue[/COLOR];
                        }
                        prj.TPData[i].vec_Drops.push_back(di.dwIndex);
                    }
                }
            }
[COLOR=#0000ff]#endif[/COLOR][COLOR=#008000] //__CLIENT[/COLOR]
[COLOR=#0000ff]#endif[/COLOR][COLOR=#008000] //__SYS_TELE16[/COLOR]
[/COLOR]

works like a charm
 
Upvote 0
Status
Not open for further replies.
Back
Top