bool	CLevel::net_start_client4				()
{
	if(connected_to_server){
		// Begin spawn
		g_pGamePersistent->LoadTitle		("st_client_spawning");

		// Send physics to single or multithreaded mode
		LoadPhysicsGameParams				();
		ph_world							= xr_new<CPHWorld>();
		ph_world->Create					();

		// Send network to single or multithreaded mode
		// *note: release version always has "mt_*" enabled
		Device.seqFrameMT.Remove			(g_pNetProcessor);
		Device.seqFrame.Remove				(g_pNetProcessor);
		if (psDeviceFlags.test(mtNetwork))	Device.seqFrameMT.Add	(g_pNetProcessor,REG_PRIORITY_HIGH	+ 2);
		else								Device.seqFrame.Add		(g_pNetProcessor,REG_PRIORITY_LOW	- 2);

		if(!psNET_direct_connect)
		{
			// Waiting for connection/configuration completition
			CTimer	timer_sync	;	timer_sync.Start	();
			while	(!net_isCompleted_Connect())	Sleep	(5);
			Msg		("* connection sync: %d ms", timer_sync.GetElapsed_ms());
			while	(!net_isCompleted_Sync())	{ ClientReceive(); Sleep(5); }
		}

		while(!game_configured)			
		{ 
			ClientReceive(); 
			if(Server)
				Server->Update()	;
			Sleep(5); 
		}
/*
		if(psNET_direct_connect)
		{
			ClientReceive(); 
			if(Server)
					Server->Update()	;
			Sleep(5);
		}else

			while(!game_configured)			
			{ 
				ClientReceive(); 
				if(Server)
					Server->Update()	;
				Sleep(5); 
			}
*/
		}
	return true;
}
BOOL			CLevel::Connect2Server				(LPCSTR options)
{
	NET_Packet					P;
	m_bConnectResultReceived	= false	;
	m_bConnectResult			= true	;
	if (!Connect(options))		return	FALSE;
	//---------------------------------------------------------------------------
	if(psNET_direct_connect) m_bConnectResultReceived = true;
	u32 EndTime = GetTickCount() + ConnectionTimeOut;
	while	(!m_bConnectResultReceived)		{ 
		ClientReceive	();
		Sleep			(5); 
		if(Server)
			Server->Update()	;
		//-----------------------------------------
		u32 CurTime = GetTickCount();
		if (CurTime > EndTime)
		{
			NET_Packet	P;
			P.B.count = 0;
			P.r_pos = 0;

			P.w_u8(0);
			P.w_u8(0);
			P.w_stringZ("Data verification failed. Cheater? [1]");

			OnConnectResult(&P);			
		}
		if (net_isFails_Connect())
		{
			OnConnectRejected	();	
			Disconnect		()	;
			return	FALSE;
		}
		//-----------------------------------------
	}
	Msg							("%c client : connection %s - <%s>", m_bConnectResult ?'*':'!', m_bConnectResult ? "accepted" : "rejected", m_sConnectResult.c_str());
	if		(!m_bConnectResult) 
	{
		OnConnectRejected	();	
		Disconnect		()	;
		return FALSE		;
	};

	
	if(psNET_direct_connect)
		net_Syncronised = TRUE;
	else
		net_Syncronize	();

	while (!net_IsSyncronised()) {
	};

	//---------------------------------------------------------------------------
	P.w_begin	(M_CLIENT_REQUEST_CONNECTION_DATA);
	Send		(P, net_flags(TRUE, TRUE, TRUE, TRUE));
	//---------------------------------------------------------------------------
	return TRUE;
};
Beispiel #3
0
BOOL			CLevel::Connect2Server				(LPCSTR options)
{
	NET_Packet					P;
	m_bConnectResultReceived	= false	;
	m_bConnectResult			= true	;
	if (!Connect(options))		return	FALSE;
	//---------------------------------------------------------------------------
	if(psNET_direct_connect) m_bConnectResultReceived = true;
	while	(!m_bConnectResultReceived)		{ 
		ClientReceive	();
		Sleep			(5); 
		if(Server)
			Server->Update()	;
	}
	Msg							("%c client : connection %s - <%s>", m_bConnectResult ?'*':'!', m_bConnectResult ? "accepted" : "rejected", m_sConnectResult.c_str());
	if		(!m_bConnectResult) 
	{
		OnConnectRejected	();	
		Disconnect		()	;
		return FALSE		;
	};

	
	if(psNET_direct_connect)
		net_Syncronised = TRUE;
	else
		net_Syncronize	();

	while (!net_IsSyncronised()) {
	};

	//---------------------------------------------------------------------------
	P.w_begin	(M_CLIENT_REQUEST_CONNECTION_DATA);
	Send		(P);
	//---------------------------------------------------------------------------
	return TRUE;
};
Beispiel #4
0
void CLevel::OnFrame	()
{
#ifdef DEBUG_MEMORY_MANAGER
	debug_memory_guard					__guard__;
#endif // DEBUG_MEMORY_MANAGER

#ifdef DEBUG
	 DBG_RenderUpdate( );
#endif // #ifdef DEBUG

	Fvector	temp_vector;
	m_feel_deny.feel_touch_update		(temp_vector, 0.f);

	if (GameID()!=eGameIDSingle)		psDeviceFlags.set(rsDisableObjectsAsCrows,true);
	else								psDeviceFlags.set(rsDisableObjectsAsCrows,false);

	// commit events from bullet manager from prev-frame
	Device.Statistic->TEST0.Begin		();
	BulletManager().CommitEvents		();
	Device.Statistic->TEST0.End			();

	// Client receive
	if (net_isDisconnected())	
	{
		if (OnClient() && GameID() != eGameIDSingle)
		{
#ifdef DEBUG
			Msg("* I'm disconnected, so clear all objects...");
#endif // #ifdef DEBUG
			ClearAllObjects();
		}

		Engine.Event.Defer				("kernel:disconnect");
		return;
	} else {

		Device.Statistic->netClient1.Begin();

		ClientReceive					();

		Device.Statistic->netClient1.End	();
	}

	ProcessGameEvents	();


	if (m_bNeed_CrPr)					make_NetCorrectionPrediction();

	if(!g_dedicated_server )
	{
		if (g_mt_config.test(mtMap)) 
			Device.seqParallel.push_back	(fastdelegate::FastDelegate0<>(m_map_manager,&CMapManager::Update));
		else								
			MapManager().Update		();

		if( IsGameTypeSingle() && Device.dwPrecacheFrame==0 )
		{
			if (g_mt_config.test(mtMap)) 
				Device.seqParallel.push_back	(fastdelegate::FastDelegate0<>(m_game_task_manager,&CGameTaskManager::UpdateTasks));
			else								
				GameTaskManager().UpdateTasks();
		}
	}
	// Inherited update
	inherited::OnFrame		();

	// Draw client/server stats
	if ( !g_dedicated_server && psDeviceFlags.test(rsStatistic))
	{
		CGameFont* F = HUD().Font().pFontDI;
		if (!psNET_direct_connect) 
		{
			if ( IsServer() )
			{
				const IServerStatistic* S = Server->GetStatistic();
				F->SetHeightI	(0.015f);
				F->OutSetI	(0.0f,0.5f);
				F->SetColor	(D3DCOLOR_XRGB(0,255,0));
				F->OutNext	("IN:  %4d/%4d (%2.1f%%)",	S->bytes_in_real,	S->bytes_in,	100.f*float(S->bytes_in_real)/float(S->bytes_in));
				F->OutNext	("OUT: %4d/%4d (%2.1f%%)",	S->bytes_out_real,	S->bytes_out,	100.f*float(S->bytes_out_real)/float(S->bytes_out));
				F->OutNext	("client_2_sever ping: %d",	net_Statistic.getPing());
				F->OutNext	("SPS/Sended : %4d/%4d", S->dwBytesPerSec, S->dwBytesSended);
				F->OutNext	("sv_urate/cl_urate : %4d/%4d", psNET_ServerUpdate, psNET_ClientUpdate);

				F->SetColor	(D3DCOLOR_XRGB(255,255,255));

				struct net_stats_functor
				{
					xrServer* m_server;
					CGameFont* F;
					void operator()(IClient* C)
					{
						m_server->UpdateClientStatistic(C);
						F->OutNext("%10s: P(%d), BPS(%2.1fK), MRR(%2d), MSR(%2d), Retried(%2d), Blocked(%2d)",
							//Server->game->get_option_s(*C->Name,"name",*C->Name),
							C->name.c_str(),
							C->stats.getPing(),
							float(C->stats.getBPS()),// /1024,
							C->stats.getMPS_Receive	(),
							C->stats.getMPS_Send	(),
							C->stats.getRetriedCount(),
							C->stats.dwTimesBlocked
						);
					}
				};
				net_stats_functor tmp_functor;
				tmp_functor.m_server = Server;
				tmp_functor.F = F;
				Server->ForEachClientDo(tmp_functor);
			}
			if (IsClient())
			{
				IPureClient::UpdateStatistic();

				F->SetHeightI(0.015f);
				F->OutSetI	(0.0f,0.5f);
				F->SetColor	(D3DCOLOR_XRGB(0,255,0));
				F->OutNext	("client_2_sever ping: %d",	net_Statistic.getPing());
				F->OutNext	("sv_urate/cl_urate : %4d/%4d", psNET_ServerUpdate, psNET_ClientUpdate);

				F->SetColor	(D3DCOLOR_XRGB(255,255,255));
				F->OutNext("P(%d), BPS(%2.1fK), MRR(%2d), MSR(%2d), Retried(%2d), Blocked(%2d), Sended(%2d), SPS(%2d)",
					//Server->game->get_option_s(C->Name,"name",C->Name),
					//					C->Name,
					net_Statistic.getPing(),
					float(net_Statistic.getBPS()),// /1024,
					net_Statistic.getMPS_Receive	(),
					net_Statistic.getMPS_Send	(),
					net_Statistic.getRetriedCount(),
					net_Statistic.dwTimesBlocked,
					net_Statistic.dwBytesSended,
					net_Statistic.dwBytesPerSec
					);
#ifdef DEBUG
				if (!pStatGraphR)
				{
					pStatGraphR = new CStatGraph();
					pStatGraphR->SetRect(50, 700, 300, 68, 0xff000000, 0xff000000);
					//m_stat_graph->SetGrid(0, 0.0f, 10, 1.0f, 0xff808080, 0xffffffff);
					pStatGraphR->SetMinMax(0.0f, 65536.0f, 1000);
					pStatGraphR->SetStyle(CStatGraph::stBarLine);
					pStatGraphR->AppendSubGraph(CStatGraph::stBarLine);
				}
				pStatGraphR->AppendItem(float(net_Statistic.getBPS()), 0xff00ff00, 0);
				F->OutSet(20.f, 700.f);
				F->OutNext("64 KBS");

#endif
			}
		}
	} else
	{
#ifdef DEBUG
		if (pStatGraphR)
			xr_delete(pStatGraphR);
#endif
	}
	
//	g_pGamePersistent->Environment().SetGameTime	(GetGameDayTimeSec(),GetGameTimeFactor());
	g_pGamePersistent->Environment().SetGameTime	(GetEnvironmentGameDayTimeSec(),game->GetEnvironmentGameTimeFactor());

	//Device.Statistic->cripting.Begin	();
	if (!g_dedicated_server)
		ai().script_engine().script_process	(ScriptEngine::eScriptProcessorLevel)->update();
	//Device.Statistic->Scripting.End	();
	m_ph_commander->update				();
	m_ph_commander_scripts->update		();
//	autosave_manager().update			();

	//просчитать полет пуль
	Device.Statistic->TEST0.Begin		();
	BulletManager().CommitRenderSet		();
	Device.Statistic->TEST0.End			();

	// update static sounds
	if(!g_dedicated_server)
	{
		if (g_mt_config.test(mtLevelSounds)) 
			Device.seqParallel.push_back	(fastdelegate::FastDelegate0<>(m_level_sound_manager,&CLevelSoundManager::Update));
		else								
			m_level_sound_manager->Update	();
	}
	// deffer LUA-GC-STEP
	if (!g_dedicated_server)
	{
		if (g_mt_config.test(mtLUA_GC))	Device.seqParallel.push_back	(fastdelegate::FastDelegate0<>(this,&CLevel::script_gc));
		else							script_gc	()	;
	}
	//-----------------------------------------------------
	if (pStatGraphR)
	{	
		static	float fRPC_Mult = 10.0f;
		static	float fRPS_Mult = 1.0f;

		pStatGraphR->AppendItem(float(m_dwRPC)*fRPC_Mult, 0xffff0000, 1);
		pStatGraphR->AppendItem(float(m_dwRPS)*fRPS_Mult, 0xff00ff00, 0);
	};
}
void CSocketClient::runSMSSocketReceive(int nSocketFD)
{
	int result = 0;
	char szTmp[16];
	int nTotalLen = 0;
	int nBodyLen = 0;
	int nCommand = generic_nack;
	int nSequence = 0;

	CMP_PACKET cmpPacket;
	void* pHeader = &cmpPacket.cmpHeader;
	void* pBody = &cmpPacket.cmpBody;

	CMP_HEADER cmpHeader;
	void *pHeaderResp = &cmpHeader;
	int nCommandResp;

	struct sockaddr_in *clientSockaddr;
	clientSockaddr = new struct sockaddr_in;

	while ( 1 )
	{
		memset( &cmpPacket, 0, sizeof(CMP_PACKET) );
		result = socketrecv( nSocketFD, sizeof(CMP_HEADER), &pHeader, clientSockaddr );

		if ( sizeof(CMP_HEADER) == result )
		{
			nTotalLen = ntohl( cmpPacket.cmpHeader.command_length );
	/*		nCommand = ntohl( cmpPacket.cmpHeader.command_id );
			nSequence = ntohl( cmpPacket.cmpHeader.sequence_number );
			if ( enquire_link_request == nCommand )
			{
				_DBG( "[Socket Server] Receive Enquir Link Request Sequence:%d Socket FD:%d", nSequence, nSocketFD );
				memset( &cmpHeader, 0, sizeof(CMP_HEADER) );
				nCommandResp = generic_nack | nCommand;
				cmpHeader.command_id = htonl( nCommandResp );
				cmpHeader.command_status = htonl( STATUS_ROK );
				cmpHeader.sequence_number = htonl( nSequence );
				cmpHeader.command_length = htonl( sizeof(CMP_HEADER) );
				socketSend( nSocketFD, &cmpHeader, sizeof(CMP_HEADER) );
				_DBG( "[Socket Server] Send Enquir Link Response Sequence:%d Socket FD:%d", nSequence, nSocketFD );
				continue;
			}
	*/
			nBodyLen = nTotalLen - sizeof(CMP_HEADER);

			if ( 0 < nBodyLen )
			{
				result = socketrecv( nSocketFD, nBodyLen, &pBody, 0 );
				if ( result != nBodyLen )
				{
					if ( externalEvent.isValid() && -1 != externalEvent.m_nEventDisconnect )
					{
						sendMessage( externalEvent.m_nEventFilter, externalEvent.m_nEventDisconnect, nSocketFD, 0, 0 );
					}
					socketClose( nSocketFD );
					_DBG( "[Socket Client] socket client close : %d , packet length error: %d != %d", nSocketFD, nBodyLen, result );
					break;
				}
			}
		}
		else
		{
			if ( externalEvent.isValid() && -1 != externalEvent.m_nEventDisconnect )
			{
				sendMessage( externalEvent.m_nEventFilter, externalEvent.m_nEventDisconnect, nSocketFD, 0, 0 );
			}
			socketClose( nSocketFD );
			_DBG( "[Socket Client] socket client close : %d , packet header length error: %d", nSocketFD, result );
			break;
		}

		if ( 0 >= result )
		{
			if ( externalEvent.isValid() && -1 != externalEvent.m_nEventDisconnect )
			{
				sendMessage( externalEvent.m_nEventFilter, externalEvent.m_nEventDisconnect, nSocketFD, 0, 0 );
			}
			socketClose( nSocketFD );
			_DBG( "[Socket Client] socket client close: %d", nSocketFD );
			break;
		}

		if ( externalEvent.isValid() )
		{
			//	_DBG("[Socket Server] Send Message : FD=%d len=%d", nFD, result);
			ClientReceive( nSocketFD, nTotalLen, &cmpPacket );
			//sendMessage( externalEvent.m_nEventFilter, externalEvent.m_nEventRecvCommand, nSocketFD, nTotalLen, &cmpPacket );
		}
		else
		{
			sendMessage( m_nInternalFilter, EVENT_COMMAND_SOCKET_RECEIVE, nSocketFD, nTotalLen, &cmpPacket );
		}
	} // while

	sendMessage( m_nInternalFilter, EVENT_COMMAND_THREAD_EXIT, threadHandler->getThreadID(), 0, NULL );

	threadHandler->threadSleep( 1 );
	threadHandler->threadExit();
}
void CLevel::remove_objects	()
{
	if (!IsGameTypeSingle()) Msg("CLevel::remove_objects - Start");
	BOOL						b_stored = psDeviceFlags.test(rsDisableObjectsAsCrows);

	Game().reset_ui				();

	if (OnServer()) {
		VERIFY					(Server);
		Server->SLS_Clear		();
	}
	
	snd_Events.clear			();
	for (int i=0; i<6; ++i) {
		psNET_Flags.set			(NETFLAG_MINIMIZEUPDATES,FALSE);
		// ugly hack for checks that update is twice on frame
		// we need it since we do updates for checking network messages
		++(Device.dwFrame);
		psDeviceFlags.set		(rsDisableObjectsAsCrows,TRUE);
		ClientReceive			();
		ProcessGameEvents		();
		Objects.Update			(true);
		Sleep					(100);
	}

	if (OnClient())
		ClearAllObjects			();

	BulletManager().Clear		();
	ph_commander().clear		();
	ph_commander_scripts().clear();

	if(!g_dedicated_server)
		space_restriction_manager().clear	();

	psDeviceFlags.set			(rsDisableObjectsAsCrows, b_stored);
	g_b_ClearGameCaptions		= true;

	if (!g_dedicated_server)
		ai().script_engine().collect_all_garbage	();

	stalker_animation_data_storage().clear		();
	
	VERIFY										(Render);
	Render->models_Clear						(FALSE);
	Render->clear_static_wallmarks				();

#ifdef DEBUG
	if(!g_dedicated_server)
		if (!client_spawn_manager().registry().empty())
			client_spawn_manager().dump				();
#endif // DEBUG
	if(!g_dedicated_server)
	{
		VERIFY										(client_spawn_manager().registry().empty());
		client_spawn_manager().clear			();
	}

	for (int i=0; i<6; i++)
	{
		++(Device.dwFrame);
		Objects.Update(true);
	}

	g_pGamePersistent->destroy_particles		(false);

//.	xr_delete									(m_seniority_hierarchy_holder);
//.	m_seniority_hierarchy_holder				= xr_new<CSeniorityHierarchyHolder>();
	if (!IsGameTypeSingle()) Msg("CLevel::remove_objects - End");
}
Beispiel #7
0
void CLevel::OnFrame	()
{
#ifdef DEBUG_MEMORY_MANAGER
	debug_memory_guard					__guard__;
#endif // DEBUG_MEMORY_MANAGER

	m_feel_deny.update					();

	if (GameID()!=GAME_SINGLE)			psDeviceFlags.set(rsDisableObjectsAsCrows,true);
	else								psDeviceFlags.set(rsDisableObjectsAsCrows,false);

	// commit events from bullet manager from prev-frame
	Device.Statistic->TEST0.Begin		();
	BulletManager().CommitEvents		();
	Device.Statistic->TEST0.End			();

	// Client receive
	if (net_isDisconnected())	
	{
		if (OnClient() && GameID() != GAME_SINGLE) 
			ClearAllObjects();

		Engine.Event.Defer				("kernel:disconnect");
		return;
	} else {

		Device.Statistic->netClient1.Begin();

		ClientReceive					();

		Device.Statistic->netClient1.End	();
	}

	ProcessGameEvents	();


	if (m_bNeed_CrPr)					make_NetCorrectionPrediction();

	if(!g_dedicated_server)
		MapManager().Update		();
	// Inherited update
	inherited::OnFrame		();

	// Draw client/server stats
	if ( !g_dedicated_server && psDeviceFlags.test(rsStatistic))
	{
		CGameFont* F = HUD().Font().pFontDI;
		if (!psNET_direct_connect) 
		{
			if ( IsServer() )
			{
				const IServerStatistic* S = Server->GetStatistic();
				F->SetHeightI	(0.015f);
				F->OutSetI	(0.0f,0.5f);
				F->SetColor	(D3DCOLOR_XRGB(0,255,0));
				F->OutNext	("IN:  %4d/%4d (%2.1f%%)",	S->bytes_in_real,	S->bytes_in,	100.f*float(S->bytes_in_real)/float(S->bytes_in));
				F->OutNext	("OUT: %4d/%4d (%2.1f%%)",	S->bytes_out_real,	S->bytes_out,	100.f*float(S->bytes_out_real)/float(S->bytes_out));
				F->OutNext	("client_2_sever ping: %d",	net_Statistic.getPing());
				F->OutNext	("SPS/Sended : %4d/%4d", S->dwBytesPerSec, S->dwBytesSended);
				F->OutNext	("sv_urate/cl_urate : %4d/%4d", psNET_ServerUpdate, psNET_ClientUpdate);

				F->SetColor	(D3DCOLOR_XRGB(255,255,255));
				for (u32 I=0; I<Server->client_Count(); ++I)	
				{
					IClient*	C = Server->client_Get(I);
					Server->UpdateClientStatistic(C);
					F->OutNext("P(%d), BPS(%2.1fK), MRR(%2d), MSR(%2d), Retried(%2d), Blocked(%2d)",
						//Server->game->get_option_s(*C->Name,"name",*C->Name),
						//					C->Name,
						C->stats.getPing(),
						float(C->stats.getBPS()),// /1024,
						C->stats.getMPS_Receive	(),
						C->stats.getMPS_Send	(),
						C->stats.getRetriedCount(),
						C->stats.dwTimesBlocked
						);
				}
			}
			if (IsClient())
			{
				IPureClient::UpdateStatistic();

				F->SetHeightI(0.015f);
				F->OutSetI	(0.0f,0.5f);
				F->SetColor	(D3DCOLOR_XRGB(0,255,0));
				F->OutNext	("client_2_sever ping: %d",	net_Statistic.getPing());
				F->OutNext	("sv_urate/cl_urate : %4d/%4d", psNET_ServerUpdate, psNET_ClientUpdate);

				F->SetColor	(D3DCOLOR_XRGB(255,255,255));
				F->OutNext("P(%d), BPS(%2.1fK), MRR(%2d), MSR(%2d), Retried(%2d), Blocked(%2d), Sended(%2d), SPS(%2d)",
					//Server->game->get_option_s(C->Name,"name",C->Name),
					//					C->Name,
					net_Statistic.getPing(),
					float(net_Statistic.getBPS()),// /1024,
					net_Statistic.getMPS_Receive	(),
					net_Statistic.getMPS_Send	(),
					net_Statistic.getRetriedCount(),
					net_Statistic.dwTimesBlocked,
					net_Statistic.dwBytesSended,
					net_Statistic.dwBytesPerSec
					);
			}
		}
	}
	
//	g_pGamePersistent->Environment().SetGameTime	(GetGameDayTimeSec(),GetGameTimeFactor());
	g_pGamePersistent->Environment().SetGameTime	(GetEnvironmentGameDayTimeSec(),GetGameTimeFactor());

	//Device.Statistic->cripting.Begin	();
	if (!g_dedicated_server)
		ai().script_engine().script_process	(ScriptEngine::eScriptProcessorLevel)->update();
	//Device.Statistic->Scripting.End	();
	m_ph_commander->update				();
	m_ph_commander_scripts->update		();
//	autosave_manager().update			();

	//просчитать полет пуль
	Device.Statistic->TEST0.Begin		();
	BulletManager().CommitRenderSet		();
	Device.Statistic->TEST0.End			();

	// update static sounds
	if(!g_dedicated_server)
	{
		if (g_mt_config.test(mtLevelSounds)) 
			Device.seqParallel.push_back	(fastdelegate::FastDelegate0<>(m_level_sound_manager,&CLevelSoundManager::Update));
		else								
			m_level_sound_manager->Update	();
	}
	// deffer LUA-GC-STEP
	if (!g_dedicated_server)
	{
		if (g_mt_config.test(mtLUA_GC))	Device.seqParallel.push_back	(fastdelegate::FastDelegate0<>(this,&CLevel::script_gc));
		else							script_gc	()	;
	}
	//-----------------------------------------------------
	if (pStatGraphR)
	{	
		static	float fRPC_Mult = 10.0f;
		static	float fRPS_Mult = 1.0f;

		pStatGraphR->AppendItem(float(m_dwRPC)*fRPC_Mult, 0xffff0000, 1);
		pStatGraphR->AppendItem(float(m_dwRPS)*fRPS_Mult, 0xff00ff00, 0);
	};
}