Вопрос по EmitSound* и TE_SetupBeamFollow

Тема в разделе "Программирование / Скриптинг", создана пользователем iamdss, 23 июн 2015.

  1. iamdss

    iamdss

    Сообщения:
    117
    Симпатии:
    0
    Доброго дня. Достался мне в руки плагин, реализующий джетпак в сурс играх, но какой-то кривой. Называется Crazy Jet, брал тут или на AlliedModders. Идея мне понравилась, но со звуков была беда, да и управление мне не понравилось, в общем, сел переделывать. Так как с SourcePawn я не знаком, то появилось несколько вопросов, ответов на которые я не нашёл. Да, я допиливаю плагин под HL2DM.

    Вопрос первый. Я заменил использованные в плагине Play/StopSoud на EmitSoundToClient, в целом, это работает, но появилась идея сделать так, чтобы звук включенного джетпака слышали не только клиенты по отдельности, но и находящиеся рядом игроки, при том, чтобы при удалении уровень звука постепенно ослабевал. Нашёл в доках функцию EmitAmbientSound, кажется, она подойдёт. Вопрос вот в чём - как реализовать изменение громкости при изменении расстояния между игроками? Я использую звук с лупом внутри, который запускаю при активации ранца и останавливаю при деактивации. Не имею понятия, как и где измерять расстояние и как заставить уже проигрываемый звук изменить громкость, а также положение (EmitAmbientSound pos). Дайте наводку, как правильно поступить?

    Второй вопрос. Джетпак в оригинале использует маяк для индикации работы. Может, в TF2 это и красиво, но не в HL2DM. Я изменил это на TE_SetupEnergySplash, но хотел бы добавить TE_SetupBeamFollow. Проблема вот в чём. Поскольку я передаю в TE_SetupBeamFollow индекс клиента, то трейл рисуется от рук игрока, а хотелось бы, чтобы от ног. Я полагаю, что решение в создании невидимого entity в ногах клиента, а уже от него надо рисовать трейл. Прав ли я и как сделать правильно?

    Заранее благодарен за помощь.
     
  2. Reiko1231

    Reiko1231 AlexTheRegent

    Сообщения:
    237
    Симпатии:
    569
    1. https://sm.alliedmods.net/new-api/sdktools_sound/EmitSoundToAll
    int entity - entity to emit from. Индекс, к которой будет прикреплен звук. По умолчанию это клиент, которому проигрывается звук. Если здесь задать самого клиента, который активировал jetpack или любую другую сущность, то звук пойдет именно от неё.
    Код:
    public Action:SomeCommand(iClient, iArgc) { EmitSoundToAll("somesound.wav", iClient); }
    Для данного кода звук somesound.wav будет распространяться для всех игроков от iClient, и если они будут достаточно далеки от него, то они не услышат ничего.

    2. TE_SetupBeamFollow имеет одну проблему - как только игрок остановится, трейл будет удален. Лучше создавать трейл вручную, прикрепив его к игроку, и установив его координаты к ногам. Для этого есть специальная entity "env_spritetrail". Вот плагин, который использует это https://forums.alliedmods.net/showthread.php?t=183131. Тогда же не будет необходимости создавать еще одну сущность под ногами игрока.
     
    iamdss нравится это.
  3. iamdss

    iamdss

    Сообщения:
    117
    Симпатии:
    0
    Спасибо за разъяснение. Сейчас я всю логику полёта собрал в OnPlayerRunCmd, первым аргументом которой является некий индекс игрока. Является ли этот индекс валидным entity, который можно использовать в данном случае в качестве второго аргумента EmitSoundToAll?

    До этого я пытался использовать EmitSoundToAll, но я указывал вручную все параметры:

    PHP:
    EmitSoundToAll(soundclientSNDCHAN_AUTOSNDLEVEL_NORMALSND_NOFLAGSSNDVOL_NORMALSNDPITCH_NORMAL, -1NULL_VECTORNULL_VECTORtrue0.0);
    Я был не прав? И ещё вопрос. Для остановки звука, проигрываемого для всех, я использовал EmitSoundToAll с флагом SND_STOPLOOPING, а именно:

    EmitSoundToAll(sound, client, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_STOPLOOPING,
    PHP:
    SNDVOL_NORMALSNDPITCH_NORMAL, -1NULL_VECTORNULL_VECTORtrue0.0);
    Верно ли это?

    Насчёт трейла буду смотреть позже, сейчас почитаю больше по звуковым функциям и попробую, что получится. О результате отпишу.
     
  4. Reiko1231

    Reiko1231 AlexTheRegent

    Сообщения:
    237
    Симпатии:
    569
    Игроки это такие же entity, как и любые другие. С одной лишь разницой - они расположены в диапазоне от 1 до MaxClients (такая переменная есть в SM, она показывает, сколько максимум игроков на сервере). Если игрока нет на сервере, то тогда эта сущность будет не валидной. Для всех остальных сущностей ( > MaxClients) можно использовать функцию IsValidEntity, которая вернет true в случае валидности. Так же есть третий тип сущности - это сам сервер, world_spawn. У него индекс 0. Индексы < 0 всегда инвалидные.
    Вкратце да, является. И проверять на валидность этот индекс именно в этом форварде нет смысла - игрок не может передавать нажития клавиш на сервер, находясь вне сервера.

    Параметры, которые написаны в прототипе функции со знаком равно и последующим значением указывать не обязательно. На сайте нового синтаксиса пока этого нет, но на старом есть - https://sm.alliedmods.net/api/index.php?fastload=show&id=682&.
    Код:
    stock EmitSoundToAll(const String:sample[],
                     entity = SOUND_FROM_PLAYER,
                     channel = SNDCHAN_AUTO,
                     level = SNDLEVEL_NORMAL,
                     flags = SND_NOFLAGS,
                     Float:volume = SNDVOL_NORMAL,
                     pitch = SNDPITCH_NORMAL,
                     speakerentity = -1,
                     const Float:origin[3] = NULL_VECTOR,
                     const Float:dir[3] = NULL_VECTOR,
                     bool:updatePos = true,
                     Float:soundtime = 0.0)
    Для данной функции, к примеру, необходимо лишь написать звук, остальное допишется само (если это не дописать, то компилятор впоследствии сам допишет). Но вот если вам понадобиться изменить volume, тогда придется заполнить entity,channel, level, flags в порядке, указанном в прототипе функции, а идущие после параметры указывать опять же таки будет не обязательно.

    Я не так много работал со звуком, так что не могу сказать, правильно это или нет. Зависит от случая и что этот флаг означает.
     
  5. iamdss

    iamdss

    Сообщения:
    117
    Симпатии:
    0
    Спасибо, твоя помощь бесценна. Подскажи, где я могу найти и прочесть все эти тонкости, о которых ты говоришь? На офсайте этого нет в помине, документация крайне скудна.

    Да, я проверил. Это действительно работает.

    PHP:
    public _PlaySoundToAll(const clientString:sound[256])
    {
        
    EmitSoundToAll(soundclient);
    }

    public 
    _PlaySound(const clientString:sound[256])
    {
        
    EmitSoundToClient(clientsound);
    }

    public 
    _StopSound(const clientString:sound[256])
    {
        
    EmitSoundToAll(soundclientSNDCHAN_AUTOSNDLEVEL_NORMALSND_STOPLOOPING);
    }
    Написал себе такие не хитрые функции. _StopSound работает как для звуков, инициированных EmitSoundToAll, так и EmitSoundToClient. Со звуком проблема решена. Остаётся решение проблемы трейла, я изучу плагин по ссылке, поэкспериментирую, о результате доложу.

    По ходу дела ещё два вопроса. Можно ли в SourcePawn перегружать функции и как объявить функцию, возвращающую строку? Я наблюдаю сообщение о том, что функция не может возвращать строку или массив...
     
  6. White Wolf

    White Wolf [] (int _n) -> double { return (_n % 2) == 0;}); Супер-модератор

    Сообщения:
    1.193
    Симпатии:
    424
    iamdss, прочитай википедию sourcemod'a, сиди почаще на форумах и узнавай такие тонкости.
    Так-же можно открыть сам include со звуками и узнать больше информации о каждом методе.
    Старое API (Sourcemod < 1.7): https://sm.alliedmods.net/api/
    Новое API (Sourcemod 1.7+): https://sm.alliedmods.net/new-api/
     
    iamdss нравится это.
  7. Reiko1231

    Reiko1231 AlexTheRegent

    Сообщения:
    237
    Симпатии:
    569
    1. Перегрузка (overload) на текущий момент отсутствует.
    2. Вернуть массив нельзя. Но можно это реализовать через входные параметры, как это сделано во всех нативах см, работающих со строками. Например, IntToString - https://sm.alliedmods.net/new-api/string/IntToString. Дальнейший код - не такой, как в сурсмоде, а мой, чтобы показать, как возвращают массив:
    Код:
    int IntToString(int num, char[] str, int maxlength)
    {
     return FormatEx(str, maxlength, "%d", num);
    }
    Таким простым образом возможно получить массив (в данном случае это строка) из функции. В данном случае функция вернет число записанных символов в массив.
    Код:
    decl String:s[8]; 
    new i = 10; 
    new c = IntToString(i, s, sizeof(s));
    PrintToServer("variable i as array: %s, bytes written: %d", s, c);
    
    Часть тонкостей описана в комментариям к функциям в документации (в старой), часть в википедии, часть на форуме hlmod\AM, но чаще всего с ними сталкиваешься сам.
     
    iamdss нравится это.
  8. iamdss

    iamdss

    Сообщения:
    117
    Симпатии:
    0
    Дошли руки снова до плагина. Пытаюсь прикрутить спрайт. Вот мой код, пока только создающий спрайт:

    Код:
    new trail = CreateEntityByName("env_spritetrail");
    if(trail > 0 && IsValidEntity(trail))
    {
    	DispatchKeyValue(trail, "spritename", "materials/sprites/glow.vmt");
    	DispatchKeyValue(trail, "lifetime", "5.0");
    	DispatchKeyValue(trail, "startwidth", "50");
    	DispatchKeyValue(trail, "endwidth", "1");
    	DispatchSpawn(trail);		
    	new Float:Origin[3];
    	GetClientAbsOrigin(client, Origin);
    	TeleportEntity(trail, Origin, NULL_VECTOR, NULL_VECTOR);
    	KillFxTrail(trail, 5.0); 
    
    }
    KillFxTrail - отложенное уничтожение трейла, код взял чужой:
    Код:
    public KillFxTrail(trail, Float:seconds)
    {
    	if(IsValidEdict(trail))
    	{
    		new String:buf[64];
    		Format(buf, sizeof(buf), "OnUser1 !self:kill::%f:1", seconds);
    		SetVariantString(buf);
    		AcceptEntityInput(trail, "AddOutput");
    		AcceptEntityInput(trail, "FireUser1");
    	}
    }

    Проблема с создающим кодом - при его исполнении клиент просто закрывается. При том, если не вызывать TeleportEntity, то, кажется, всё в порядке - создаётся и уничтожается. Что я сделал не правильно?

    Добавлено через 3 минуты
    PrecacheModel - присутствует, в OnMapStart.
     
    Последнее редактирование: 27 июн 2015
  9. Reiko1231

    Reiko1231 AlexTheRegent

    Сообщения:
    237
    Симпатии:
    569
    Ошибки, связанные с крашем клиента, а не сервера, при работе с моделями означают одно - указана неверная модель и клиент при попытке отобразить её крашится. Судя по содержимому .vpk файлов игры CSS, glow.vmt присутствует в папке с cstrike, а у вас игра hl2dm. Там такого спрайта нет, что, скорее всего, и является причиной падения клиента. Попробуйте заменить на glow01.vmt в PrecacheModel() и DispatchKeyValue().
    Так же эта ошибка должна оставаться в консоли сервера при запуске, т.к. PrecacheModel вызовет ошибку движка, которая выводится только в консоль.
    Именно поэтому, когда вы не телепортируете, всё работает, а как только переносите к игроку сразу получаете ошибку игры. мой сотый пост :D
     
    iamdss нравится это.
  10. iamdss

    iamdss

    Сообщения:
    117
    Симпатии:
    0
    В консоль сейчас нет возможности посмотреть, но, вероятно, это по причине отсутствия модели. Где можно увидеть доступные для моего клиента модели?

    После замены на glow01 клиент не рушится, но и трейла я не вижу...

    Код:
    CreateTrailEntity(client)
    {
    	new g_iGlowSprite = PrecacheModel("materials/sprites/glow01.vmt", true);
    	new trail = CreateEntityByName("env_sprite", -1);
    	DispatchKeyValue(trail, "classname", "env_spritetrail");
    	DispatchKeyValue(trail, "spawnflags", "1");
    	DispatchKeyValue(trail, "scale", "0.0");
    	DispatchKeyValue(trail, "rendermode", "10");
    	DispatchKeyValue(trail, "rendercolor", "255 255 255 0");
    	DispatchKeyValue(trail, "model", "materials/sprites/glow01.vmt");
    	DispatchSpawn(trail);
    	AttachTrail(trail, client);
    	KillFxTrail(trail, 5.0);
    	TE_SetupBeamFollow(trail, g_iGlowSprite, 0, 2.0, 20.0, 5.0, 10, {192,192,192,150});
    	// Время жизни ------------------------------^
    	// Ширина ----------------------------------------^
    	// Ширина конца хвоста ---------------------------------^
    	// Время затухания -----------------------------------------^
    	TE_SendToAll();
    	JetTrail[client] = trail;
    
    Что здесь не так?
     
  11. Reiko1231

    Reiko1231 AlexTheRegent

    Сообщения:
    237
    Симпатии:
    569
    Потому что вы лишь телепортировали трейл, но не привязали к игроку. Нужно изменить TargetName игрока, затем привязать трейл к нему. См. подробнее плагин, вот нужные строчки из него.
    Код:
    decl String:_sTemp[64], String:_sOriginal[64];
    GetEntPropString(client, Prop_Data, "m_iName", _sOriginal, sizeof(_sOriginal));
    Format(_sTemp, sizeof(_sTemp), "SupporterTrails_%d", GetClientUserId(client));
    DispatchKeyValue(client, "targetname", _sTemp);
    Код:
    DispatchKeyValue(_iEntity, "parentname", _sTemp);
    Код:
    SetVariantString(_sTemp);
    AcceptEntityInput(_iEntity, "SetParent", _iEntity, _iEntity);
    Трейл появляется при движении, а так как нет парента, нет движения.

    Согласно Valve Developer Community, env_spritetrail:
    The Hammer Entity Help section describes this entity as "a magical trail" you can parent to anything. In other words, it is a trail effect for parenting with other entities.
     
    iamdss и san911 нравится это.
  12. iamdss

    iamdss

    Сообщения:
    117
    Симпатии:
    0
    Да, ведь делал изначально, но потом убрал этот код и забыл за него. Спасибо, сейчас буду тестировать. Отпишу.

    Добавлено через 1 час 33 минуты
    Всё работает, спасибо большое за помощь! Вопросы - можно ли к одному энтити привязывать 2, 3 трейла (TE_SetupBeamFollow)? Как количество трейлов повлияет на сервер - есть ли ограничения? К примеру, все 16 игроков одновременно полетели, каждый создаёт, к примеру, по 3 трейла разных конфигураций, нормально ли это?

    Добавлено через 1 час 35 минут
    И ещё один немаловажный момент. Я использую

    Код:
    new g_iGlowSprite = PrecacheModel("materials/sprites/glow01.vmt", true);
    при каждом создании трейла. Могу ли я в целях оптимизации кода вынести это в функцию инициализации плагина? Или куда лучше его поместить?

    И где найти список доступных спрайтов, моделей для HL2DM? (Нашёл в хаммере)
     
    Последнее редактирование: 28 июн 2015
  13. Reiko1231

    Reiko1231 AlexTheRegent

    Сообщения:
    237
    Симпатии:
    569
    Количество ентити ограничено, их число можно получить при помощи GetMaxEntities(), но это число достаточно большое, чтобы на простой карте достичь лимита. Так что можно прикреплять к одному игроку столько трейлов, сколько потянет сервер. Другой вопрос, а нужно ли это? И нельзя ли эти трейлы объединить в один и уже его прикреплять к игроку.
    https://sm.alliedmods.net/new-api/entity/GetMaxEntities

    Да, как глобальную переменную. Только прехеш выполнять надо не раньше форварда OnMapStart() (в самом форварде OnMapStart можно и обычно там его и делают), иначе сервер может упасть на запуске.

    Я не знаю, как в hl2dm, но в ксс старых версий (до 34 включительно) их можно было найти в корне папки игры, а дальше их стали хранить в .vpk архивах, которые можно открыть с помощью программ, например, GCFScape. Только открывать нужно *_dir.vpk файл, а не архивы с цифрами. Внутри этих архивах всё как в путях, которые прописываются - есть папки materials, sounds, models. В них как раз все файлы, которые есть в данной игре\модификации.
     
  14. iamdss

    iamdss

    Сообщения:
    117
    Симпатии:
    0
    Тут я имел в виду, считаются ли трейлы (TE_SetupBeamFollow) сущностями? Я знаю про ограничение, вот и решил узнать, по сути, я создаю только энтити под ногами, а сам дым прикреплён к нему и не имеет своего идентификатора. Вот и возник вопрос. И ещё я не совсем понял, как именно объединить трейлы? Разве сейчас я делаю не так?

    Добавлено через 2 часа 12 минут
    И ещё никак не разберусь, как переместить энтити так, чтобы она постоянно была за спиной игрока? Надо постоянно обновлять её позицию? Или можно сделать это как-то автоматически? (нашёл здесь пример кода, вопрос снят)

    Добавлено через 6 часов 55 минут
    Ребята, осталось модельку джетпака прикрутить для полного счастья =) Как это можно сделать и где посмотреть на похожие реализации?
     
    Последнее редактирование: 28 июн 2015
  15. Reiko1231

    Reiko1231 AlexTheRegent

    Сообщения:
    237
    Симпатии:
    569
    TE в начале функции расшифровывается как TempEnt. Так что она считается как сущность.

    В любом графическом редакторе соединять рисунки трейлов. В принципе можно создавать и по три трейла на игрока, но есть ли в этом смысл?

    Похожая реализация - трейлы через env_spritetrail. Только для модели создавать надо prop_dynamic или prop_physics, а дальше так же прикреплять её как parent к игроку.
     
    iamdss нравится это.
  16. iamdss

    iamdss

    Сообщения:
    117
    Симпатии:
    0
    Спасибо. Вернусь к этому вопросу позже. Отпишу.

    Добавлено через 8 часов 30 минут
    Пробую. Снова ничего не получилось. Добавил модель в список на загрузку, а также прекешировал её. Создаю энтити таким минимальным кодом:

    Код:
    new jpack = CreateEntityByName("prop_dynamic", -1);
    DispatchKeyValue(jpack, "parentname", _sTemp);							
    DispatchKeyValue(jpack, "model", "models/thrusters/jetpack.mdl");
    DispatchSpawn(jpack);
    И оно создаётся (jpack не пуста), но на мне висит огромная надпись "ERROR". Что не так и как узнать причину ошибки?
     
    Последнее редактирование: 29 июн 2015
  17. iamdss

    iamdss

    Сообщения:
    117
    Симпатии:
    0
    Ребят, актуально. Помогите найти ошибку, в других плагинах это работает, у меня нет. Может ли быть это из-за того, что я кеширую только mdl, хотя с моделью также лежат рядом и другие файлы? Может, что-то ещё надо обозначить для загрузки и кеширования?
     
  18. Саша Шеин

    Саша Шеин

    Сообщения:
    1.259
    Симпатии:
    191
    Как кешируешь и добовл. в загрузки? Модельки грузит?
     
  19. iamdss

    iamdss

    Сообщения:
    117
    Симпатии:
    0
    В OnMapStart

    Код:
    g_iModelJP = PrecacheModel("models/thrusters/jetpack.mdl", true);
    AddFileToDownloadsTable("models/thrusters/jetpack.mdl");
    Модельку загружает, да. На фаст дл лежат несколько файлов, вот они с относительными путями:

    Код:
    /models/thrusters/jetpack.dx80.vtx
    /models/thrusters/jetpack.dx90.vtx
    /models/thrusters/jetpack.mdl
    /models/thrusters/jetpack.phy
    /models/thrusters/jetpack.vvd
    /materials/models/thrusters/jetpack.vmt
    /materials/models/thrusters/jetpack.vtf
    /materials/models/thrusters/jetpack_normal.vtf
    Мне их так дали, с такой структурой. Возможно, я уже думаю, что в путях от materials папка models лишняя, сейчас попробую проверить.
     
  20. Саша Шеин

    Саша Шеин

    Сообщения:
    1.259
    Симпатии:
    191
    А у тебя грузятся все эти файлы?
    Я бы для всех этих файлов сделал:
    AddFileToDownloadsTable("...");
    Или сделать файл для загагрузки этих файлов. (Есть готовый плагин SM Downloader туда просто в simple_download.ini поопиши все эти пути, а в своём плагине убери загрузку):boss: