Forum Half-Life.ru
Показать все 7 Сообщений на одной странице

Forum Half-Life.ru (http://www.half-life.ru/forum/index.php)
- Мастерская (http://www.half-life.ru/forum/forumdisplay.php?forumid=5)
-- FMOD и спиритовский плеер mp3. (http://www.half-life.ru/forum/showthread.php?threadid=12248)


Отправлено sania_3 29-08-2007 в 06:44:

FMOD и спиритовский плеер mp3.

На днях заглянул в один из архивных дисков и обнаружил сорцы спирита (либо 1.4, либо 1.7). Ради разнообразия решил посмотреть, что в них, и ,найдя файлик mp3.cpp, открыл его. Посмотрел, что можно вбить в поиск и приступил к делу. Для начала надо взять из аттача "mp3.cpp", "mp3.h", "fmod.h" и "fmod_errors.h" . Они взяты из спирита без изменений, их кидаем в папку клиента. Куда нужно добавлять остальной код, я распишу.

Открываем клиентскую часть и в файлах "hud.cpp", "hud_msg.cpp" и "cdll_int.cpp" добавляем в самое начало к аналогичным конструкциям вот это:

Code:

#include "mp3.h" 
/// AJH - Killars MP3player


Изменения будут только в этих файлах. Для начала надо переделываем "cdll_int.cpp". Ищем
Code:

CHud gHUD
;

(около 40 строки)и под ним пишем
Code:

CMP3 gMP3
;

.
Теперь можно закрывать "cdll_int.cpp" и открыть "hud.cpp".
Где-то около 180 строки к аналогичным конструкциям добавляем
Code:

int __MsgFunc_PlayMP3
(const char *pszNameint iSizevoid *pbuf )
{
    return 
gHUD.MsgFunc_PlayMP3pszNameiSizepbuf );
}
void __CmdFunc_StopMP3void )
{
    
gMP3.StopMP3();
}

Ищем
Code:

void CHud 
:: Initvoid )

(в районе 290 строки) и в нём добавляем вот это:
Code:

//KILLAR: MP3    
    
if(gMP3.Initialize())
    {
        
HOOK_MESSAGEPlayMP3 );
        
HOOK_COMMAND"stopaudio"StopMP3 );
    }

Теперь ищем
Code:

CHud 
:: ~CHud()

в районе 380 строки и после
Code:

delete 
[] m_rgszSpriteNames;

пишем
Code:

gMP3
.Shutdown();

. Теперь надо открыть "hud.h" и найти
Code:

class CHud

(рядом со строкой 550) и в нем после
Code:

int  _cdecl MsgFunc_Concuss
( const char *pszNameint iSizevoid *pbuf );

(строка 660 примерно) пишем
Code:

int  _cdecl MsgFunc_PlayMP3
( const char *pszNameint iSizevoid *pbuf );


Так, на клиенте остался ещё и "hud_msg.cpp". Открываем, ищем
Code:

int CHud 
:: MsgFunc_Concuss( const char *pszNameint iSizevoid *pbuf )
{
    
BEGIN_READpbufiSize );
    
m_iConcussionEffect READ_BYTE();
    if (
m_iConcussionEffect)
        
this->m_StatusIcons.EnableIcon("dmg_concuss",0,160,0);
    else
        
this->m_StatusIcons.DisableIcon("dmg_concuss");
    return 
1;
}

Это самый конец (строка 120). Добавляем в ниже этот код:
Code:

int CHud 
:: MsgFunc_PlayMP3( const char *pszNameint iSizevoid *pbuf //AJH -Killar MP3
{
    
BEGIN_READpbufiSize );
    
gMP3.PlayMP3READ_STRING() );
    return 
1;
}

Клиентская часть готова. Теперь- в сервер (что вполне логично). Открываем "client.cpp" и где-то в районе 50 строки добавляем
Code:

extern int gmsgPlayMP3
///AJH - Killars MP3player

. Идём в район 400 строки и вставляем после этого кода:
Code:

else if ( FStrEq(pcmd"fullupdate" ) )
    {
        
GetClassPtr((CBasePlayer *)pev)->ForceClientDllUpdate(); 
    }

вот этот:
Code:

else if ( FStrEq(pcmd"playaudio" ) )  //AJH - MP3/OGG player (based on killars MP3)
    
{
        
MESSAGE_BEGINMSG_ONEgmsgPlayMP3NULLENT(pev) );
            
WRITE_STRING( (char *)CMD_ARGV(1) );
        
MESSAGE_END();
    }

Теперь надо открыть "player.cpp" и где-то в районе 170-180 строк добавляем
Code:

int gmsgPlayMP3 
0///Killar

Там целая колонка похожих описаний, так что ошибиться трудно. Теперь ищем
Code:

void LinkUserMessages
void )
{
    
// Already taken care of?
    
if ( gmsgSelAmmo )
    {
        return;
    }

Это где-то строка 200. Там тоже колонка, в которую надо вписать
Code:

gmsgPlayMP3 
REG_USER_MSG("PlayMP3", -1);    ///Killar

Ошибиться будет трудно, но если какой гений умудрится, напишите.
Теперь идём в "triggers.cpp" и тем в самом конце пишем код самого триггера плеера. Вот он :
Code:

// mp3 player, killar
#define SF_REMOVE_ON_FIRE 1

class CTargetFMODAudio : public CPointEntity
{
public:
     
void Spawnvoid );

     
void Use( CBaseEntity *pActivatorCBaseEntity *pCallerUSE_TYPE useTypefloat value );
     
BOOL m_bPlaying;
    
virtual int        SaveCSave &save );
    
virtual int        RestoreCRestore &restore );
    static    
TYPEDESCRIPTION m_SaveData[];
};

LINK_ENTITY_TO_CLASSambient_fmodstreamCTargetFMODAudio );
LINK_ENTITY_TO_CLASStrigger_mp3audioCTargetFMODAudio );

TYPEDESCRIPTION    CTargetFMODAudio::m_SaveData[] = 
{
    
DEFINE_FIELDCTargetFMODAudiom_bPlayingFIELD_BOOLEAN ),
};
IMPLEMENT_SAVERESTORECTargetFMODAudioCPointEntity );

void CTargetFMODAudio :: Spawnvoid )
{
     
pev->solid SOLID_NOT;
     
pev->movetype MOVETYPE_NONE;

     
m_bPlaying FALSE// start out not playing
}

void CTargetFMODAudio::Use( CBaseEntity *pActivatorCBaseEntity *pCaller,
     
USE_TYPE useTypefloat value )
{
     
char command[64];

     if (!
pActivator->IsPlayer()) // activator should be a player
          
return;

     if (!
m_bPlaying// if we're not playing, start playing!
          
m_bPlaying TRUE;
     else
     {     
// if we're already playing, stop the mp3
          
m_bPlaying FALSE;
          
CLIENT_COMMAND(pActivator->edict(), "stopaudio\n");
          return;
     }

     
// issue the play/loop command
     
sprintf(command"playaudio %s\n"STRING(pev->message));

     
CLIENT_COMMAND(pActivator->edict(), command);

     
// remove if set
     
if (FBitSet(pev->spawnflagsSF_REMOVE_ON_FIRE))
          
UTIL_Remove(this);
}



Теперь можно смело компилить и добавлять в fgd-файл вот это:
Code:

@PointClass base(Targetname) = ambient_fmodstream"FMOD Audio player (MP3/OGG/WMA)"
[
     
message(string) : "File Name"
     
spawnflags(flags) =
     [
          
1"Remove on fire" 0
     
]
]



Как пользоваться: кидаем музыку в формате mp3,wav,ogg,wma... в папку "media" своего мода. Ставим энтитю на карту и в "File Name" пишем название песни [color=red]с расширением (!!!)[color]. В названии не должно быть пробелов и русских букв, только латиница. Если нужны пробелы, используйте "_" - это FMOD ещё поймёт.
И ещё, не забудьте добавить в папку "cl_dlls" саму ДЛЛ "FMOD.dll" и переименовать её в "mp3dec.dll". Я взял спиритовский. FMOD можно скачать из интернета или из игр. FMOD можно найти и в "Героях V". Версия FMODа в спирите- 3.7.1.0 .
Если есть ошибки (что врядли, у меня работает ), пишите прямо здесь. Кстати, я не потрудился взять чистый исходник и повторить по своему же тутору.

Надеюсь, многим пригодится, а то я искал в инете- все только обещают тутор написать, а на деле -хрен.
Автор: sania_3...

__________________
B.C.Rich Warbeast standart USER; Behringer C-1U USER; Digitech RP70 USER; SansAmp GT2 USER; FL9 USER;
ZiD Pilot 50cm3 Cross USER, Хочу КТМ SX 250;
Mastech MS-200 USER; Luckey 701 USER; HTC HD mini USER;
Mozgi USER


Отправлено Дядя Миша 29-08-2007 в 08:14:

sania_3 этот код устарел хрензнаеткогда!
я уже давно написал для Xash mp3 плеер, который из пака умеет доставать музыку.


Отправлено sania_3 29-08-2007 в 09:56:

>>>sania_3 этот код устарел хрензнаеткогда!
Я и по такому тутора не нашёл.
Смотрел исходники ксаша. Меня глючит или на клиенте всё уместилось в один файл (не считая hud.h)?

__________________
B.C.Rich Warbeast standart USER; Behringer C-1U USER; Digitech RP70 USER; SansAmp GT2 USER; FL9 USER;
ZiD Pilot 50cm3 Cross USER, Хочу КТМ SX 250;
Mastech MS-200 USER; Luckey 701 USER; HTC HD mini USER;
Mozgi USER


Отправлено Дядя Миша 29-08-2007 в 16:28:

sania_3 да, все в одном файле. Этот код был написан мною для Xash-движка, а потом рипнут мной же для халфы.
Ты лучше по нему тутор напиши.


Отправлено Ku2zofff 18-11-2007 в 04:53:

Прошу прощения за поднятие старой темы, я просто не как не мог усидеть на месте не исправив этот mp3 плеер(за паузу спасиб Дяде Мише. Итак, приступим.

Представленный здесь mp3 плеер имеет ряд недостатков: не регулируется громкость,
нет паузы во время паузы игры, при выходе в меню(Disconnect) музыка продолжает играть.
Вот как можно решить эти проблемы:

Открываем mp3.h в cl_dll:

Code:

// mp3 support added by Killar

#ifndef MP3_H
#define MP3_H

#include "fmod.h"
#include "fmod_errors.h"
#include "windows.h"

class CMP3
{
private:
    
float            (_stdcall VER)    (void);//AJH get fmod dll version
    
signed char        (_stdcall SCL)    (FSOUND_STREAM *stream);
    
signed char        (_stdcall SOP)    (int outputtype);
    
signed char        (_stdcall SBS)    (int len_ms);
    
signed char        (_stdcall SDRV)    (int driver);
    
signed char        (_stdcall INIT)    (int mixrateint maxsoftwarechannelsunsigned int flags); 
    
FSOUND_STREAM*        (_stdcall SOF)    (const char *filenameunsigned int mode,int memlength);       //AJH old fmod
    
FSOUND_STREAM*        (_stdcall SO)    (const char *filenameunsigned int mode,int offsetint memlength);    //AJH use new fmod
    
int             (_stdcall SPLAY)    (int channelFSOUND_STREAM *stream);
    
void            (_stdcall CLOSE)    ( void );
    
signed char        (_stdcall SETVOLUME)    (int channelint vol );//регулятор громкости
        
signed char     (_stdcall PAUSE) (int channelsigned char paused);//установка паузы
    
    
FSOUND_STREAM  *m_Stream;
    
int        m_iIsPlaying;
    
HINSTANCE    m_hFMod;

public:
    
int        Initialize();
    
int        Shutdown();
    
int        PlayMP3( const char *pszSong );
    
int        StopMP3();
    
int        Volume();//функция отвечающая за громкость и паузу
};

extern CMP3 gMP3;
#endif



Затем открываем mp3.cpp, находим int CMP3::Initialize() и добавляем туда

Code:

if( m_hFMod != NULL )
    {
        
// fill in the function pointers
        
(FARPROC&)VER =     GetProcAddress(m_hFMod"_FSOUND_GetVersion@0");
        (
FARPROC&)SCL =     GetProcAddress(m_hFMod"_FSOUND_Stream_Close@4");
        (
FARPROC&)SOP =     GetProcAddress(m_hFMod"_FSOUND_SetOutput@4");
        (
FARPROC&)SBS =     GetProcAddress(m_hFMod"_FSOUND_SetBufferSize@4");
        (
FARPROC&)SDRV =     GetProcAddress(m_hFMod"_FSOUND_SetDriver@4");
        (
FARPROC&)INIT =     GetProcAddress(m_hFMod"_FSOUND_Init@12");
        (
FARPROC&)SOF =     GetProcAddress(m_hFMod"_FSOUND_Stream_OpenFile@12");
        
//(FARPROC&)LNGTH =     GetProcAddress(m_hFMod, "_FSOUND_Stream_GetLength@4");
        
(FARPROC&)SO =         GetProcAddress(m_hFMod"_FSOUND_Stream_Open@16");//AJH Use new version of fmod
        
(FARPROC&)SPLAY =     GetProcAddress(m_hFMod"_FSOUND_Stream_Play@8");
        (
FARPROC&)CLOSE =     GetProcAddress(m_hFMod"_FSOUND_Close@0");
        (
FARPROC&)SETVOLUME =   GetProcAddress(m_hFMod"_FSOUND_SetVolume@8");//адрес громкости
        
(FARPROC&)PAUSE     =   GetProcAddress(m_hFMod"_FSOUND_SetPaused@8");//адрес паузы



После этого в самом низу добавляем:

Code:

extern int Paused
;

int CMP3::Volumevoid )
{
    if ( 
m_iIsPlaying )
    {
           if ( 
Paused )
           {
           
PAUSE 0); 
           }
           else
           {
           
PAUSE 0); 
           }

      
SETVOLUME0CVAR_GET_FLOAT"MP3Volume" ) * 200 );
    return 
1;
    }
    else
    return 
0
}



Потом открываем hud_redraw.cpp, добавляем туда заголовочный файл mp3.h и в void CHud::Think(void) вставляем:

Code:

void CHud
::Think(void)
{
    
int newfov;
    
HUDLIST *pList m_pHudList;

    
gMP3.Volume();//Отсюда вызывается функция 

    
while (pList)
    {
        if (
pList->p->m_iFlags HUD_ACTIVE)
            
pList->p->Think();
        
pList pList->pNext;
    }



Теперь осталась самая малость - указать условие, когда надо ставить музыку на паузу. Откроем view.cpp и спустимся к
void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ) :

Code:

int Paused
;
void DLLEXPORT V_CalcRefdefstruct ref_params_s *pparams )
{
         
Paused pparams->paused;//Если игра на паузе, fmod тоже на паузе

    // intermission / finale rendering
    
if ( pparams->intermission )
    {    
        
V_CalcIntermissionRefdef pparams );    
    }
    else if ( 
pparams->spectator || g_iUser1 )    // g_iUser true if in spectator mode
    
{
        
V_CalcSpectatorRefdef pparams );    
    }
    else if ( !
pparams->paused )
    {
        
V_CalcNormalRefdef pparams );
    }



Теперь осталось заставить музыку молчать при выходе в меню. Идём в dlls в client.cpp и внутрь функций
void ClientDisconnect( edict_t *pEntity ) и void SpectatorDisconnect( edict_t *pEntity ) вставляем
строчку SERVER_COMMAND( "stopaudio\n" ); //останавливаем mp3 если выходим в меню, но не переходим на следующую карту.

Для тех, кто хочет, чтобы музыка в сингле играла один раз, а в мультиплеере повторялась много раз
(вспомните Unreal Tournament, там все карты с музыкой) надо открыть mp3.cpp в cl_dll и заменить

Code:

if( SOF )
    {                                                    
        
m_Stream SOFsongFSOUND_NORMAL /*| FSOUND_LOOP_NORMAL*/);//G-Cont. kill loop sound
    
}
    else if (
SO)
    {
        
m_Stream SOsongFSOUND_NORMAL /*| FSOUND_LOOP_NORMAL*/,0);//G-Cont. kill loop sound
    
}



на вот это:

Code:

int multiplayer 
gEngfuncs.GetMaxClients() == 1;

    if( 
multiplayer )
    { 
           if( 
SOF )
           {                                                    
           
m_Stream SOFsongFSOUND_NORMAL FSOUND_LOOP_NORMAL);//Ku2zoff. loop sound if we're in multiplayer
           
}
           else if (
SO)
           {
           
m_Stream SOsongFSOUND_NORMAL FSOUND_LOOP_NORMAL,0);//Ku2zoff. loop sound if we're in multiplayer
           
}
    }
    else
    {
           if( 
SOF )
           {                                                    
           
m_Stream SOFsongFSOUND_NORMAL /*| FSOUND_LOOP_NORMAL*/);//G-Cont. kill loop sound
           
}
           else if (
SO)
           {
           
m_Stream SOsongFSOUND_NORMAL /*| FSOUND_LOOP_NORMAL*/,0);//G-Cont. kill loop sound
           
}
    }



Вот теперь действительно всё.


Отправлено XaeroX 18-11-2007 в 05:48:

За такие имена функций (SDS, SOF, SO) в приличном обществе дают пощечину

__________________
First, close your eyes and pretend that a WGL specification actually existed. Maybe if we all concentrate hard enough, one will magically appear. © NVidia
The fastest way to compute is to precompute. © Humus


Отправлено Ku2zofff 18-11-2007 в 12:55:

XaeroX не я их писал, какие были такие и указал.

Добавлено 21-12-2007 в 23:23:

Один недостаток - пауза правильно работает только в стим-версии халфы.


Время GMT. Текущее Время 07:39.
Показать все 7 Сообщений на одной странице

Powered by: vBulletin Version 2.2.8
Copyright © Jelsoft Enterprises Limited 2000, 2001.