Перейти к содержимому
  • Объявления

    • st1nc

      Жалобы на плохой пинг

      Жалобы принимаются по шаблону ниже в этой теме.   Город
      Провайдер
      Трассировка до серверов simhost.org

Рекомендованные сообщения

Так. Решил я дублировать на нашем форуме свои статьи.

Ибо мало ли, кф.ру накроется - обидно будет их потерять

Да и тем из вас, кто решил изучать unrealscript возможно будет удобнее это делать у нас тут)

Изменено пользователем Flame
  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Статья 1

Минимальный шаблон мутатора

 

Рассмотрим минимальный шаблон любого мутатора:

 

Class TestMut extends Mutator;

defaultproperties
{
	GroupName="KF-TestMut"
	FriendlyName="TestMut"
	Description="Тестовый мутатор. Базовый шаблон"
}
Всегда ленился поглядеть, что за GroupName и FriendlyName

Вот и повод изучить

 

GroupName:

 

 

Итак,

В общем то уже из комментария к описанию переменной в классе Engine.Mutator

var() cache string   GroupName; // Will only allow one mutator with this tag to be selected.
становится ясно, что данная переменная используется, чтобы дать возможность заблокировать добавление мутаторов одной и той же группы.

При желании можно посмотреть и реализацию этого механизма в Engine.GameInfo.AddMutator - не буду копировать сюда код, любознательные сами глянут, остальным это и не надо)

Использование:

1. Страховка от добавления мутаторов реализующих одно и то же (или идейно близкие вещи)

2. Страховка от добавления конфликтующих мутаторов

3. Я особо этим никогда не пользовался - жду от вас идеи, как это можно использовать

 

Важное замечание:

В KF есть страничка добавления мутаторов в игру - KFGui.KFMutatorPage

И если мы внимательно поглядим на функцию SetCurrentGame, то мы увидим такой вот код:

...
for (i=0;i<MutatorList.Length;i++)
{
	if ( Left(MutatorList[i].GroupName,2)== "KF")
		lb_Avail.List.Add(MutatorList[i].FriendlyName,,MutatorList[i].Description);
}
...
Который означает, что в списке доступных мутаторов будут отображаться только мутаторы GroupName которых начинается на "KF"

Поэтому не забывайте писать GroupName="KFчтототам", если хотите, чтобы ваш мутатор был доступен в этой менюшке

Общепринятый подход: GroupName = "KF-НазваниеМутатора"

 

 

FriendlyName:

 

 

Ну тут вроде всё просто - это название мутатора, которое отображается в окошке выбора мутаторов.

Название переменной намекает нам на дружелюбие. Вот есть понятие дружелюбного пользовательского интерфейса.

Так и тут - сам класс мутатора может называться как угодно неудобоваримо, а в этой переменной стоит написать лаконичное и понятное название, в идеале, чтобы даже описание Description не понадобилось для среднестатистического игрока.

 

Вы можете писать название мутатора и кириллицей (только не забывайте переключиться в кодировку Little Endian), например,

FriendlyName="Тестовый мутатор"
Более того, вы можете раскрасить название мутатора, если вам уж совсем нехрен делать)

Общепринятый для анриала способ "окраски" описан тут, например.

Сделаем слово "Тестовый" красного цвета, а "мутатор" зелёного:

 

 

Вы можете воспользоваться программкой ServerColor, я же воспользуюсь HEX редактором (я люблю редактор Hex Editor Neo).

Итак, я возьму не чистые цвета, а просто те, что мне приглянулись.

Префикс для красного цвета получится 1B D1 60 60

Префикс для зелёного цвета получится 1B 3D B7 74

Загоним эти значения в HEX редактор и получим С`` для красного цвета и =·t для зелёного.

Получим FriendlyName="С``Тестовый =·tмутатор"

 

 

 

 

Description:

 

 

Ну с этим то в общем всё понятно)

Это описание мутатора. Опять же можно сделать на русском и цветное.

Сделаем его синим

Префикс: X“П

Description="X“ПТестовый мутатор. Базовый шаблон"

 

 

В итоге получили такой вот мутатор:

Class TestMut extends Mutator;

defaultproperties
{
	GroupName="KF-TestMut"
	FriendlyName="С``Тестовый =·tмутатор"
	Description="X“ПТестовый мутатор. Базовый шаблон"
}
И такой вот результат:

 

 

Bs4cx3u.png

 

 

Изменено пользователем Flame

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Статья 2

Типы мутаторов

 

1. Мутатор, который работает только на сервере (потом добавлю сюда ссылку на статью "модель клиент-сервер для unreal движка").

 

2. Мутатор, который работает на сервере и клиенте (при этом возможно действия выполняются только для клиентов, для сервера никакого полезного кода не выполняется).

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

 

3. Мутатор, который работает на сервере, но при этом требует, чтобы некоторые ресурсы закачивались на клиент (ибо туда идёт неявная репликация).

 

Итак,

ТИП №1

Мутатор, который работает только на сервере

 

 

Примером такого мутатора являются пожалуй большинство мутаторов на форуме.

Характерной особенностью является полная независимость от того, что происходит на клиенте.

Так как такой мутатор выполняется только на сервере, нам нет необходимости закачивать его на клиент, и нет никакой необходимости добавлять bAddToServerPackages=true в defaultproperties, вызывать где-то функцию AddToPackageMap() или писать в KillingFloor.ini ServerPackages=ПакетМутатора.

 

Замечание:

Можно создать файл "НазваниеПакета.upkg" в папке мутатора. И в нём прописать флаги AllowDownload, ClientOptional, ServerSideOnly. Этот текстовый файл используется компилятором.

Написав AllowDownload=false, мы запретим закачивать наш пакет на клиент, независимо от того, прописал админ этот наш пакет в ServerPackages или нет.

У Марко в ServerPerksMut такой набор флагов:

 

 

[Flags]
AllowDownload=False
ClientOptional=False
ServerSideOnly=True
Я раньше особо не парился по этому поводу и во все мутаторы добавлял bAddToServerPackages=true

Новичкам стоит, пожалуй, так и делать, чтобы не ломать лишний раз голову.

 

И ещё замечание:

Данный тип мутатора можно запускать не как мутатор, а как ServerActor. Данную тему я потом покопаю, ибо не очень понимаю плюсы и минусы данного шага. Напоминаю, ServerActor - это объект, который создаётся на сервере при загрузке карты.

 

 

 

ТИП №2

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

 

 

Ниже приведены некоторые из случаев, когда они нужны:

- изменение HUD (обычно с помощью Interaction)

пример: Полоска жизни патрика ссылка

- обработка нажатия кнопок клавиатуры/мыши

пример: Прерывание перезарядки ссылка

- вызов спецэффектов на клиенте

- необходимость поменять свойства объектов, используемых только на клиенте. Например: отображение веса пушки в магазине

- потом ещё дополним список

 

Вообще клиентские мутаторы тема непростая. Она требует понимания того, как происходит создание объектов на сервере и клиенте. Это будет потихоньку раскрываться в других статьях. Пока просто опишу основные характерные особенности кода.

 

1. Чтобы мутатор работал на клиенте в defaultproperties необходимо добавить 2 строчки:

	bAlwaysRelevant=True
	RemoteRole=ROLE_SimulatedProxy
2. Мутатор должен быть закачен на клиент, поэтому нужна либо строчка

	bAddToServerPackages=True
либо другое альтернативное добавление мутатора в список пакетов.

 

3. Используемые на клиенте функции должны иметь префикс simulated

 

4. Проверку того, на клиенте выполняется данный экземляр мутатора или на сервере, можно сделать такую:

 

 

Вариант 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. Чем больше я пишу, тем больше вспоминаю разных мелочей. Пока хорош тогда с особенностями - тут не на одну статью материала.

 

Напишем для закрепления простенький мутатор и хватит для начала :smile:

 

 

Пусть мутатор пишет игроку приветствие в начале волны (первой волны, которую он играет).

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"
}
В первом случае у каждого клиента есть мутатор, который лично для него пишет сообщение. Во втором случае мы на сервере просто пробегаем по всем игрокам и каждому из них пишем сообщение.

Полезно сравнить эти два мутатора и чётко понять как каждый из них работает.

 

 

 

 

ТИП №3

Мутатор, который работает на сервере, но при этом требует, чтобы некоторые ресурсы закачивались на клиент.

 

 

Он, вроде, как серверный, но вот беда - если его не закачать клиенту, то он не будет полноценно работать.

Например, мутатор, который на сервере вызывает функцию запускающую проигрывание звука ClientPlaySound.

Если не прописать закачку ресурсов на клиент, звук проигрываться не будет.

Поэтому, если для работы мутатора на клиенте нужны ресурсы какого-либо пакета, необходимо скачивать этот мутатор на клиент.

То есть добавить bAddToServerPackages=True в defaultproperties.

 

 

 

Статья получилась сумбурная. Потом у нас есть намерение её переписать после написания статьи про взаимодействие сервера и клиентов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Гость
Эта тема закрыта для публикации сообщений.

×