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

iamdss

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

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

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

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

Reiko1231

AlexTheRegent
Сообщения
508
Реакции
1,335
1. https://sm.alliedmods.net/new-api/sdktools_sound/EmitSoundToAll
int entity - entity to emit from. Индекс, к которой будет прикреплен звук. По умолчанию это клиент, которому проигрывается звук. Если здесь задать самого клиента, который активировал jetpack или любую другую сущность, то звук пойдет именно от неё.
C-подобный:
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

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

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

PHP:
EmitSoundToAll(sound, client, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, SNDVOL_NORMAL, SNDPITCH_NORMAL, -1, NULL_VECTOR, NULL_VECTOR, true, 0.0);

Я был не прав? И ещё вопрос. Для остановки звука, проигрываемого для всех, я использовал EmitSoundToAll с флагом SND_STOPLOOPING, а именно:

EmitSoundToAll(sound, client, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_STOPLOOPING,
PHP:
SNDVOL_NORMAL, SNDPITCH_NORMAL, -1, NULL_VECTOR, NULL_VECTOR, true, 0.0);

Верно ли это?

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

Reiko1231

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

До этого я пытался использовать EmitSoundToAll, но я указывал вручную все параметры:
Параметры, которые написаны в прототипе функции со знаком равно и последующим значением указывать не обязательно. На сайте нового синтаксиса пока этого нет, но на старом есть - https://sm.alliedmods.net/api/index.php?fastload=show&id=682&.
C-подобный:
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 в порядке, указанном в прототипе функции, а идущие после параметры указывать опять же таки будет не обязательно.

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

iamdss

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

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

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

PHP:
public _PlaySoundToAll(const client, String:sound[256])
{
	EmitSoundToAll(sound, client);
}

public _PlaySound(const client, String:sound[256])
{
	EmitSoundToClient(client, sound);
}

public _StopSound(const client, String:sound[256])
{
	EmitSoundToAll(sound, client, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_STOPLOOPING);
}

Написал себе такие не хитрые функции. _StopSound работает как для звуков, инициированных EmitSoundToAll, так и EmitSoundToClient. Со звуком проблема решена. Остаётся решение проблемы трейла, я изучу плагин по ссылке, поэкспериментирую, о результате доложу.

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

White Wolf

🍉
Сообщения
2,382
Реакции
2,187
  • Команда форума
  • #6
iamdss, прочитай википедию sourcemod'a, сиди почаще на форумах и узнавай такие тонкости.
Так-же можно открыть сам include со звуками и узнать больше информации о каждом методе.
Старое API (Sourcemod < 1.7): https://sm.alliedmods.net/api/
Новое API (Sourcemod 1.7+): https://sm.alliedmods.net/new-api/
 

Reiko1231

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

1. Перегрузка (overload) на текущий момент отсутствует.
2. Вернуть массив нельзя. Но можно это реализовать через входные параметры, как это сделано во всех нативах см, работающих со строками. Например, IntToString - https://sm.alliedmods.net/new-api/string/IntToString. Дальнейший код - не такой, как в сурсмоде, а мой, чтобы показать, как возвращают массив:
C-подобный:
int IntToString(int num, char[] str, int maxlength)
{
 return FormatEx(str, maxlength, "%d", num);
}
Таким простым образом возможно получить массив (в данном случае это строка) из функции. В данном случае функция вернет число записанных символов в массив.
C-подобный:
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

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

C-подобный:
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 - отложенное уничтожение трейла, код взял чужой:
C-подобный:
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.
 
Последнее редактирование:

Reiko1231

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

iamdss

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

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

C-подобный:
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;

Что здесь не так?
 

Reiko1231

AlexTheRegent
Сообщения
508
Реакции
1,335
Потому что вы лишь телепортировали трейл, но не привязали к игроку. Нужно изменить TargetName игрока, затем привязать трейл к нему. См. подробнее плагин, вот нужные строчки из него.
C-подобный:
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);
C-подобный:
DispatchKeyValue(_iEntity, "parentname", _sTemp);
C-подобный:
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

Участник
Сообщения
126
Реакции
12
Да, ведь делал изначально, но потом убрал этот код и забыл за него. Спасибо, сейчас буду тестировать. Отпишу.

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

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

C-подобный:
new g_iGlowSprite = PrecacheModel("materials/sprites/glow01.vmt", true);

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

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

Reiko1231

AlexTheRegent
Сообщения
508
Реакции
1,335
можно ли к одному энтити привязывать 2, 3 трейла (TE_SetupBeamFollow)? Как количество трейлов повлияет на сервер - есть ли ограничения? К примеру, все 16 игроков одновременно полетели, каждый создаёт, к примеру, по 3 трейла разных конфигураций, нормально ли это?
Количество ентити ограничено, их число можно получить при помощи GetMaxEntities(), но это число достаточно большое, чтобы на простой карте достичь лимита. Так что можно прикреплять к одному игроку столько трейлов, сколько потянет сервер. Другой вопрос, а нужно ли это? И нельзя ли эти трейлы объединить в один и уже его прикреплять к игроку.
https://sm.alliedmods.net/new-api/entity/GetMaxEntities

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

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

iamdss

Участник
Сообщения
126
Реакции
12
Количество ентити ограничено, их число можно получить при помощи GetMaxEntities(), но это число достаточно большое, чтобы на простой карте достичь лимита. Так что можно прикреплять к одному игроку столько трейлов, сколько потянет сервер. Другой вопрос, а нужно ли это? И нельзя ли эти трейлы объединить в один и уже его прикреплять к игроку.

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

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

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

Reiko1231

AlexTheRegent
Сообщения
508
Реакции
1,335
Тут я имел в виду, считаются ли трейлы (TE_SetupBeamFollow) сущностями?
TE в начале функции расшифровывается как TempEnt. Так что она считается как сущность.

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

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

iamdss

Участник
Сообщения
126
Реакции
12
Спасибо. Вернусь к этому вопросу позже. Отпишу.

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

C-подобный:
new jpack = CreateEntityByName("prop_dynamic", -1);
DispatchKeyValue(jpack, "parentname", _sTemp);							
DispatchKeyValue(jpack, "model", "models/thrusters/jetpack.mdl");
DispatchSpawn(jpack);

И оно создаётся (jpack не пуста), но на мне висит огромная надпись "ERROR". Что не так и как узнать причину ошибки?
 
Последнее редактирование:

iamdss

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

Саша Шеин

Кому костылей?
Сообщения
1,697
Реакции
621
Как кешируешь и добовл. в загрузки? Модельки грузит?
 

iamdss

Участник
Сообщения
126
Реакции
12
В OnMapStart

C-подобный:
g_iModelJP = PrecacheModel("models/thrusters/jetpack.mdl", true);
AddFileToDownloadsTable("models/thrusters/jetpack.mdl");

Модельку загружает, да. На фаст дл лежат несколько файлов, вот они с относительными путями:

C-подобный:
/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 лишняя, сейчас попробую проверить.
 

Саша Шеин

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