Ниже приведены некоторые из случаев, когда они нужны:
- изменение HUD (обычно с помощью Interaction)
пример: Полоска жизни патрика ссылка
- обработка нажатия кнопок клавиатуры/мыши
пример: Прерывание перезарядки ссылка
- вызов спецэффектов на клиенте
- необходимость поменять свойства объектов, используемых только на клиенте. Например: отображение веса пушки в магазине
- потом ещё дополним список
Вообще клиентские мутаторы тема непростая. Она требует понимания того, как происходит создание объектов на сервере и клиенте. Это будет потихоньку раскрываться в других статьях. Пока просто опишу основные характерные особенности кода.
1. Чтобы мутатор работал на клиенте в defaultproperties необходимо добавить 2 строчки:
- Код:
-
bAlwaysRelevant=True
RemoteRole=ROLE_SimulatedProxy
2. Мутатор должен быть закачен на клиент, поэтому нужна либо строчка
- Код:
-
bAddToServerPackages=True
либо другое альтернативное добавление мутатора в список пакетов.
3. Используемые на клиенте функции должны иметь префикс
simulated4. Проверку того, на клиенте выполняется данный экземляр мутатора или на сервере, можно сделать такую:
- Спойлер:
Вариант 1:
- Код:
-
if(Role == ROLE_Authority)
{
//КодДляСервера
}
else
{
//КодДляКлиента
}
Вариант 2:
- Код:
-
local PlayerController PC;
PC=Level.GetLocalPlayerController();
if(PC!=none)
{
КодДляКлиента;
}
else
{
КодДляСервера;
}
Вариант 3:
- Код:
-
if(Level.NetMode==NM_DedicatedServer)
{
//КодДляВыделенногоСервера
}
else
{
//КодДляКлиента (при условии, что мутатор установлен на выделенном сервере)
}
5. Мутатор выполняется на стороне клиента, и есть возможность получить
PlayerController.
- Код:
-
Level.GetLocalPlayerController()
Соответственно для каждого экземпляра мутатора будет PlayerController его владельца.
Для сервера
Level.GetLocalPlayerController() вернёт
none. Именно на этом основана проверка в предыдущем пункте (вариант 2).
Очень полезная штука этот Level.GetLocalPlayerController()
6. На клиенте нельзя использовать
Level.GameЧто это значит? Это значит нельзя на клиенте так проверять идёт волна или нет:
- Код:
-
if(KFGameType(Level.Game).bWaveInProgress)
{
...
}
Надо использовать
KFGameReplicationInfo объект.
- Код:
-
local KFGameReplicationInfo KFGRI;
KFGRI = KFGameReplicationInfo(Level.GetLocalPlayerController().GameReplicationInfo);
if(KFGRI.bWaveInProgress)
{
...
}
7. Надо чётко понимать, что, если создать клиентский мутатор с чтением информации из ini файла, то клиентские версии
мутатора будут искать ini на клиенте, а серверный - на сервере. Впрочем, это тема более сложной статьи.
8. Чем больше я пишу, тем больше вспоминаю разных мелочей. Пока хорош тогда с особенностями - тут не на одну статью материала.
Напишем для закрепления простенький мутатор и хватит для начала
- Спойлер:
Пусть мутатор пишет игроку приветствие в начале волны (первой волны, которую он играет).
- Код:
-
class TestClientMut extends Mutator;
//Функция выполняется на клиенте и сервере благодаря пунктам 1 и 2
//Для сервера сразу зовётся Disable('Tick') и для севрера функция больше не вызывается
//Для клиента же мы ждём начала волны, постим сообщение и отключаем функцию
//В принципе можно было бы и мутатор удалить для сервера и клиента, а не только отключить Tick, ну да не суть важно
simulated function Tick(float dt)
{
local PlayerController PC;
local KFGameReplicationInfo KFGRI;
PC=Level.GetLocalPlayerController();
if(PC!=none)
{
KFGRI = KFGameReplicationInfo(PC.GameReplicationInfo);
if(KFGRI.bWaveInProgress)
{
PC.ClientMessage("Greetings Mortal, are you ready to die?");
Disable('Tick');
}
}
else
Disable('Tick');
}
defaultproperties
{
bAddToServerPackages=True
GroupName="KF-TestClientMut"
FriendlyName="TestClient"
Description="Testing base client mutator"
bAlwaysRelevant=True
RemoteRole=ROLE_SimulatedProxy
bNetNotify=True
}
А вот так выглядит серверный мутатор с аналогичным функционалом:
- Код:
-
class GreetingsMut extends Mutator;
function Tick(float dt)
{
local Controller C;
if(KFGameType(Level.Game).bWaveInProgress)
{
for( C = Level.ControllerList; C != None; C = C.nextController )
{
if(C.IsA('PlayerController') && C.PlayerReplicationInfo.PlayerID>0)
PlayerController(C).ClientMessage("Greetings Mortal, are you ready to die?");
}
Disable('Tick');
}
}
defaultproperties
{
GroupName="KF-GreetingsMut"
FriendlyName="Greetings"
Description="GreetingsMut"
}
В первом случае у каждого клиента есть мутатор, который лично для него пишет сообщение. Во втором случае мы на сервере просто пробегаем по всем игрокам и каждому из них пишем сообщение. Полезно сравнить эти два мутатора и чётко понять как каждый из них работает.