Автоматоны Pawn

В языке Pawn есть механизм состояний(автоматон) — это такая система, которая позволяет определить несколько копий одной функции для использования в различных условиях. Я начну объяснять с примера, ибо так получится более наглядно, а ниже подробно опишу эту систему.

Пример

Допустим нам нужно сохранить данные игрока и данные гонок, а также сообщить об этом игрокам и гонщикам соответственно. При обычной реализации код выглядит грязновато:

#include <a_samp>
 
forward data_Save(type);
forward message_Save(type);
 
enum {
	players,
	races
}
 
main() {
	data_Save(players);
	message_Save(players);
}
 
public data_Save(type)
{
	switch (type) {
		case players: {
			// saving
		}
		case races: {
			// saving
		}
	}
}
public message_Save(type)
{
	switch (type) {
		case players: {
			// send message to player
		}
		case races: {
			// send message to racers
		}
	}
}

А реализация с помощью автоматонов выглядит очень элегантно:

#include <a_samp>
 
forward data_Save();
forward message_Save();
 
main() {
	state dataType:players;
	data_Save();
	message_Save();
}
 
public data_Save() <dataType:players>
{
	// saving
}
 
public data_Save() <dataType:races>
{
	// saving
}
 
public message_Save() <dataType:players>
{
	// send message to players
}
 
public message_Save() <dataType:races>
{
	// send message to racers
}

Плюсы этого метода

А если понадобится добавить в список выше что-нибудь ещё? Код без автоматонов превратиться в огромный switch! А если вы, например, захотите перенести код сохранения данных гонки в файл race/data.inc? Тогда вам придётся создавать дополнительную функцию и заносить её туда! Но с автоматонами это делается гораздо проще.

Ещё можно отметить то, что конструкция, выполненная с помощью автоматонов, работает немного быстрее, чем функция с большим switch.

Теория

state

Этим кодом мы устанавливаем для dataType состояние players

state dataType:players;

Для проверок, связанных с автоматонами, есть сокращённое написание, например этот код:

state (var == 1) dataType:races;

эквивалентен этому:

if (var == 1) {
	state dataType:races;
}
entry()

Для автоматонов зарезервирована специальная функция entry(), которая вызывается при установке состояния.

Пример:

#include <a_samp>
 
main() {
	printf("Hello");
	state entryTest:message;
	printf("World!");
}
 
entry() <entryTest:message>
{
	printf("Test");
}

Результатом выполнения этого кода будет:

Hello
Test
World
Функции

Вы можете объявлять функции с одним состоянием:

stock echo(msg[]) <exType:one>
{
	print(msg);
}

С несколькими:

stock echo(msg[]) <exType:one,exType:two>
{
	print(msg);
}

(эта функция будет вызвана при состоянии one или two).

И с любым другим состоянием:

stock echo(msg[]) <>
{
	print(msg);
}

(эта функция будет вызвана если не было вызвано ни одной функции со своим состоянием).

  • Сколько модов не редактировал, не разу не видел этого приёма

  • Vagrant

    Собираюсь писать РП мод. Так вот хочу узнать. Например если использовать его вот так:
    public OnPlayerCommandText(playerid, cmdtext[])
    // Написаны все команды без ввода параметров
    public OnPlayerCommandText(playerid, cmdtext[])
    // Написаны все команды с параметрами

    Будит ли разница в скорости и вообще есть ли смысл использовать так для того что бы миновать кучу проверок и что бы как можно быстрее без проверок подобраться к нужной команде? Но единственное чего я не понял (возможно из-за этого могу ошибаться). Если в общем, что сложилось у меня в уме. Есть переключатель: state dataType:players; после этой строки будет читаться паблик только с переключателем: players? То есть строка выше является общим переключателем или паблики с обоими переключателями могут работать независимо друг от друга? Когда оба режима к примеру активированы?

    • Для OnPlayerCommandText это неприменимо.

      > Есть переключатель: state dataType:players; после этой строки будет читаться паблик только с переключателем: players?
      Да.

      • Vagrant

        Спасибо!

  • a3om

    Здравствуйте :) Хотелось бы также упомянуть про «безтеговые» или «безымянные» состояния автоматонов. То есть:


    stock Name()
    {
    prinft("State 1");
    }

    stock Name()
    {
    prinft("State 2");
    }

    main()
    {
    state state1;
    Name();
    state state2;
    Name();
    }

    Выведет: State1 и State2 :)

    • a3om

      Не прорисовались состояния на функциях, видимо не так написал, простите :)

Перейти к верхней панели