Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
  • Need help?

    Create a topic in the appropriate section
    Don't write everything in the chat!
  • Take a look at the marketplace

    There you can buy
    everything related to game servers
  • Don't want a ban?

    Please read our rules
    Don't disturb the order!
  • Sell or buy?

    Use services of the guarantor
    We will make your deal safe
  • 0
BorizzK

Dayz Standalone 0.62/0.63 enscript. Изучение.

Предлагаю начать совместоное изучение enscript в этой теме. )))

 

Для начала типа документашка, хотя на смом деле наверное проще будет разбираться методом ковыряния

http://lystic.net/dayzwiki/index.html?page=classen5c__boxcerealcrunchin.html

 

Edited by BorizzK (see edit history)

Share this post


Link to post
Share on other sites

21 answers to this question

Recommended Posts

  • 0

BorizzK они ж вроде в 0.63 на новый движок хотели переходить. Не?

Share this post


Link to post
Share on other sites



  • 0

Могу сказать пока лишь одно, Enscript 0.63 stress test #1 отличается от enscript 0.62 по функциям, и отсутствием документации, потому основываться пока можем лишь на 0.62 версию

Share this post


Link to post
Share on other sites
  • 0

123new Именно ее сейчас начал изучать

В общем и целом, сравнивая файлы со скриптами, могу сказать одно - основная логика и синтаксис никак не изменились по сравнению с 0.62

А вот по отношению к 0.60/0.61 изменения очень сильные (ковырял от скуки как-то)

Например  по сравнению с 0.61 изменлась структура папочек, modulemeneger теперь pluginmanager итп

 

Сейчас занимаюсь изучением методом сравнения и эксперементируя с 0.62

По мере появления результатов буду их выкладывать сюда

+ может удастся разузнать у Виталия Мизева нюансы...

 

 

Edited by BorizzK (see edit history)

Share this post


Link to post
Share on other sites
  • 0

DrTauren На  новый движок они уже с 0.60  переехали

к 0.61 и далее к 0.62 они его дорабатывали и развивали, сохраняя совместимость по скриптингу со старой версией и плавно переводя ренедеринг и остальное на новый язык. Начиная с 0.62 вся гуя уже полностью управляется новым языком и функционал управления гуёй старым языком почти полностью вырезана (осталась возможность отправлять тексты в чат и тп, включая затемнения и тп экрана). Там же через вызовы процедур enscript из sqf (callMethod) можно делать и все остальное.

 

Share this post


Link to post
Share on other sites
  • 0

Первые результаты самостоятельных исследований 0.62 методом осмотра/досмотра (с понятыми в виде notepad++ и Beyond Compare 4). Возможно я где-то в чем-то не прав, ошибся и тп, но не поделиться инфой не могу.

 

Небольшое отступление

Процесс загрузки клиента/сервера 0.62

 

1 Сначала загружаются все конфиги из всех *.pbo в папке Addons в корне игры (в последствии при необходимости оттуда же подгружается все необходимое). Если в файле есть init.sqf он будет выполнен, это если я все верно понял.

Можно создать свой .pbo, содать в нем обьекты и конфиг и описанием, положить в Addons и при обращении к обьектам из этой pbo в скриптах они будут загружены в игру, понятно, что в случае оффлайн режима можно не париться соответствиями, тк сервер и клиент у нас по сути это одно и то же. В случае же клиент/серверного режима, pbo должы соответствовать хотя бы по структуре и названиям (более глубоко не изучал).

 

2 Затем загружаются все конфиги из *.pbo в папке dta в корне игры, там же расположен scripts.pbo с enscript скриптами для управления клиентом/сервером. Если вытащить содержимое scripts.pbo в папку scripts в корне клиента/сервера, файл scripts.pbo будет проигнорирован и игра будет использовать содержимое папки scripts (опять же по первым наблюдениям)

 

1. Сначала читается и обрабатывается (возможно что-то еще, но я пока не понял что именно)

scripts\5_Mission\someMission.c

Отсюда выбираются режимы работы клиента/сервера и в зависимости от выбора выполняется дальнейшая инициализация

 

Mission CreateMission(string path)
{
	SetDispatcher(new DispatcherCaller);
	
	g_Game.SetMissionPath(path);

	if (g_Game.IsMultiplayer() && g_Game.IsServer())
	{
		return new MissionServer;
	}

#ifdef NO_GUI
	return new MissionDummy;
#endif
	MissionMainMenu m;
	if (path.Contains("NoCutscene"))
	{
		m = new MissionMainMenu();
		m.m_NoCutscene = true;
		return m;
	}
	
	if (path.Contains("intro"))
	{
		m = new MissionMainMenu();
		m.m_NoCutscene = false;
		return m;
	}
	else
	{
#ifndef NO_GUI_INGAME
		return new MissionGameplay;
#else
		return new MissionDummy;
#endif
	}
}

void DestroyMission(Mission mission)
{
	delete mission;
}

 

2. Для сервера это scripts\5_Mission\mission\missionServer.c

по сути это как init.sqf в корне миссии

в нем же включение  scripts\5_Mission\mission\missionBase.c

 

Для оффлайн клиента (локальная эмуляция) это scripts\5_Mission\missionGameplay.c

Когда запускается стандартный клиент он обрабатывает missionGameplay.c и готовится к работе с сервером откуда в последствии и берет все необходимые параметры

 

Однако путем некоторых манипуляций мы создаем ему режим оффлайн и клиент работает с локальными скриптами (движок-то тот же самый, в нем нет только серверной части обрабатывающей мультиплей/внешние подключения/функционал мира и итд итп серверные вещи, впрочем зомбаков и тп можно смело наспавнить через sqf/enscript в 062 и только через enscript в 063).

 

убираем в someMission.c все что не касается missionGameplay.c

 

Mission CreateMission(string path)
{
	SetDispatcher(new DispatcherCaller);
	
	g_Game.SetMissionPath(path);



	return new MissionGameplay;

}

void DestroyMission(Mission mission)
{
	delete mission;
}

 

теперь у нас игра оффлайн (эмуляция)

 

Но

нам же надо создать персонажа и навесить на него лут и тп, а так же поместить его в мир, который еще надо проинициализировать - такого функционала штатно в клиенте нет

 

Есть 2 варианта

1 Сделать это в enscript как эт осделано в 0.63 клиенте (оффлайн), но мы пока не знаем как (пока не знаем)

2 Сделать это через SQF, но это надо создавать/править pbo как это сделано у Fidov/Kolobov

Сейчас разбираюсь как это сделано у них

 

 

 

 

 

 

Edited by BorizzK (see edit history)

Share this post


Link to post
Share on other sites
  • 0

Други.

Поскольку БИСы посмотрели и сказали - от 0.63 и выше можно модить и это не пиратство, то это добавляет оптимизма.

А кроме того, они перевыпустили 0.63 под стим с встроенным одиночным режимом. Теперь если Вы переключились на бету и ввели волшебное слово в спецстроке и у Вас установилась 0.63 бета, то при запуске будет выбор обычный или одиночный режим.

 

Волшебное слово: ireallywanttotest

 

 

Share this post


Link to post
Share on other sites
  • 0

Очень странно, проверяю в стиме и у меня версия 0.62, даже беты нет, где и от куда взяли 0.63?

Share this post


Link to post
Share on other sites
  • 0

Есть такое, и это обнадеживает. Поиграл в эту одиночку, скажу так, если они мелкие недоработки и баги поправят, получится очень красивая и крутая игра, все плавно и шустро работает (ну за исключением фризов временами). Вырисовывается картина будущей годной игры.

Что касается менюшек - есть подозрение, что надо копать scripts\3_Game\constants.c добавляя константы в виде id окна и кнопки, scripts\5_Mission\mission\missionBase.c добавляя в CreateScriptedMenu вызов окна в зависимости от выбираемых ид окон виджетов, и в scripts\5_Mission\mission\missionGameplay.c в событии OnKeyPress вызов функции с меню при нажатии той или иной клавиши. пример там есть для клавиши Q (if (key == KeyCode.KC_Q))без каких-либо действий, есть предположение, что там была включена панель разработчиков игры (но как включить не понял пока).

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

Share this post


Link to post
Share on other sites
  • 0
11 минуту назад, Alex39 сказал:

Очень странно, проверяю в стиме и у меня версия 0.62, даже беты нет, где и от куда взяли 0.63?

свойства игры в стиме, раздел бетта версии, введи "ireallywanttotest", затем выбери там stress-test. Докачаются файлы и у тебя 0.63 уже. Назад вернуться также, только вместо stress-test выбери "отказаться"

 

Если игру запустить с параметром:

 -mission=.\Missions\dayzOffline.ChernarusPlus

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

Edited by 123new (see edit history)

Share this post


Link to post
Share on other sites
  • 0

123new как включить панель разработчика для 0.62 я кажется уже знаю. Зпвтра проверю идею ))))

 

Share this post


Link to post
Share on other sites
  • 0

BorizzK главное для сборки клиент-сервер проверяй, в оффлайн клиенте это уже и так реализовали

Share this post


Link to post
Share on other sites
  • 0

Еще поизучал 0.62

 

Немного моих теоретических догадок, тк пока изучаю код итд итп

 

Админку активировать на клиенте не представляется проблемой

Активировать SceneEditor сложнее, я его активировал в оффлайн-клиенте - он почти такой же как и в 0.63 версии, в нем пока не все работает локально, но уже что-то...

А активировать на сервере особо нечего

 

На сервере enscript используется ограниченно

На клиенте же начиная с 0.62 почти повсеместно

 

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

 

В кратце про взаимодействие

Для взаимодействия клиента/сервера с сервера можно использовать
spawnForClient из SQF с передачей параметров, а внутри уже заворачивать все в enscript (например для создания визуальных эффектов типа создания камеры и тп.)

Для этого мы берем callmethod/callfunction и вызываем на клиенте необходимую нам процедуру/функцию из sqf

Потипу

 

На сервере (ActivateCameraClient условное название стандартной процедуры УЖЕ имеющейся в файлах игры на клиенте!!! Что там к чему я еще пока не разбирался), 10 - условно время в секундах сколько показывать убийцу

[_id,_killer] spawnForClient {
(_this select 1) callmethod ["ActivateCameraClient",10]; //callmethod всегда вызывается для какого-либо конкретного обьекта
};

 

В итоге на клиенте будет выполненна стандартная  процедура ActivateCameraClient, которая получив обьект киллера покажет убитому картинку с киллером в течение 10 сек (образно)

 

Ну и о вызываемой процедуре enscript

 

где-то - например в gameMission.c обьявлена стандартная процедура

void ActivateCameraClient (int var1) // переменная var1 тип целое число

{

vector pos_killer = this.GetPosition()

//тут код потипу CreateCamera(pos_killer);

}

 

Про координаты/позицию

 

На самом деле не стороне клиента позицию можно получить легко в энскрипте и ее не надо пересылать

Напимер текущю известную клиентской части позицию игрока (клиента) в мире

PlayerBase player = GetGame().GetPlayer(); //в переменную player класса PlayerBase получаем обьект текущего игрока

vector pos_player = player.GetPosition(); //pos_player переменная типа vector получаем текущие координаты !!! в enscript нужно четко определять тип переменной (переменные в enscript отдельная тема)

или

this.GetPosition(); вернет текущие координаты полученные с сервера (насколько я понял) в функции/процедуре - что такое this все догадались? (в нее попаk  обьект _killer). // тут была очепятка тк изначально отправлял клиенту не обьект, а координаты

 

Все это пока теория, не проверенная на практике, но мне кажется, что я не ошибаюсь.

 

В enscript еще еще есть замена spawnforclient и publicVariableServer. Однако это имеет смысл если рулить процессом только из enscript, что со стороны сервера 0.62 мне не кажется удачным решением.

 

Виталий Мизев мне в кратце обьяснил что к чему

Процитирую его

 

Цитата

Использование удаленных вызовов процедур - RPC (remote procedure call).

В ЕнСкрипте для замены функций spawnForClient, spawnForPlayer и publicVariableServer была введена система RPC (remote procedure call).
В зависимости от области вызова вызова и параметров функция передает выполнение от сервера к клиенту или наоборот.

Формат использования:

GetGame().RPC(<Объект>, <Уникальный идентификатор>, <Параметры>, <Особый клиент> );

- где:

Объект - Объект для которого выполнится удаленная процедура. Если NULL, то процедура выполнится на сервере. В классе этого объекта должна быть функция обработки удаленной процедуры - OnRPC().
Если вызов выполняется на сервер, то функция OnRPC() находится в модуле \scripts\3_Game\DayZGame.c. - все вызовы с клиентов к серверу обработаются тут.

Уникальный идентификатор - то, чем вы отличите один тип вызов от других.Число int. Задаете сами, можно с использование констант.

<Параметры> - параметры с переменными которые вы хотите передать.

<Особый клиент> - клиент, которому нужно (только ему) передать удаленный вызов. Если NULL вызовы передаются сразу всем.

Пример Сервер -> Клиент:

Скажем, Вы хотите передать какую-то переменную клиенту от сервера.

(Я не показываю инициализацию переменных. Смотрите в инструкции).

GetGame().RPC(Player, 1500844, Param5, Null);

Обязательно в классе (scripts\4_World\Entities\ManBase\PlayerBase.c) должна быть функция OnRPC() (она там есть).

Дописываем обработку:

if( rpc_type == 1500844) { <Ваша функция>}

Пример Клиент -> Сервер:

На клиенте вызываем удаленную процедуру

GetGame().RPC(NULL , 58841, Param5, Null);

На серверной стороне в файле: scripts\3_Game\DayZGame.c в функцию

void OnRPC(Object target, int rpc_type, ParamsReadContext ctx)

добавляем:

if (target)
{
// call rpc on target
target.OnRPC(rpc_type, ctx);
}
else
{
switch(rpc_type)
{
case 58841:
<Ваша функция>
 

Продолжаю дальнейшие изыскания...

Edited by BorizzK (see edit history)

Share this post


Link to post
Share on other sites
  • 0

BorizzK а можешь дать пример вызова панели разработчиков в 0.62 в клиент-серверном виде? Хотя бы чисто поглядеть на то что в текущем патче творится у них.

Share this post


Link to post
Share on other sites
  • 0

123new В текущей 063 версии все так же - панель разработчика расчитана на работу с оффлайн версией - ко всем результатам работы нужно прекручивать передачу значений с клиента на сервер.
Я сейчас постепенно разберусь с нюансами и начну плавно ковырять стандартную панель в 0.62 + там же есть SCENE EDITOR который криво, но удалось запустить опять таки локально.
Надо учитывать одно - код панели разработчика (читай интерфейс) вызывается и выполняется только на клиенте

те он должен быть активирован на клиенте) а дальше нужно просто реализовать в нем передачу данных на сервер и прием и обработку их сервером, но надо еще отделить мух от котлет, что бы взаимодействие могло происходить только с клиентом обладающим определенными правами, а то какойнить левый чел сможет творить что захочет. Те, например eventhandler для приема данных с клиента нужно активировать ислючительно для клиента с uid админа. И делать это нужно исключительно на enscript, без использования sqf на сервере вообще для 0.62, а на 0.63 судя по всему sqf вообще с сервера уберут.

Сижу думаю. Алгоритм приблизительно вырисовывается.

 

Ну и кроме того в 0.63 они местами поменяли и синтаксис и некоторые другие нюансы в enscript. Не глобально, но старое написанное к 0.63 не прикрутить - надо менять код. Да они да же в 0.63 клиенте первого публичного билда и 2х последующих умудрились внести изменения в enscript  и то что делал Виталий Мизев и Fidov перестало работать и они потом чинили.

Виталий профессиональный программист пишущий на Cи/Си++, потому он в принципе довольно быстро освоил enscript. Буду его терзать иногда на предмет понимания. Думаю еще через пару недель (если время будет позволять) разберусь с enscript в 0.62, ну а к выходу 0.63 и появлению серверов в доступе для моддинга все заинтерисованные тут разберутся )))

 

P.S. Жаль, что в энскрипт нельзя  создавать массив-массивов

 

И в дополнение

 

Что же представляет из себя Enfusion Scripts — новый язык программирования игровых механизмов игры DayZ Standalone?

(с) Виталий Мизев

https://vk.com/@dayzundergound-chto-zhe-predstavlyaet-iz-sebya-enfusion-scripts-novyi-yazyk

 

Edited by BorizzK (see edit history)

Share this post


Link to post
Share on other sites
  • 0

BorizzK в целом понял общую картину бытия, в общих так сказать красках. Я сам лишь c# изучаю, потому мне сложнее понимать этот язык, но что-то общее есть. Ладно, жду, возможно еще что интересное у тебя получится сделать. А проверку на исполнение на сервере по тем же uid можно делать, благо они то как раз от клиента передаются. Правда в текущем виде, в случае если что-то некорректно обработается или не сможет обработаться, энскрипт может сервер просто крашнуть, чем могут специально воспользоваться "темные личности". и это весьма прискорбно.

Share this post


Link to post
Share on other sites
  • 0

123new могут специально воспользоваться "темные личности".

 

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

Чего стоит одна publicVariableServer

Что стоило сделать прием переменной от клиента только в его контекст на стороне сервера??? там делов-то на пару килобайт, а то и меньше

 

Edited by BorizzK (see edit history)

Share this post


Link to post
Share on other sites
  • 0

Про enScript. Опубликую тут, что бы было.

(С) Mizev

 

Что же представляет из себя Enfusion Scripts — новый язык программирования игровых механизмов игры DayZ Standalone?

С версии игры 0.59 Bohemia Interactive начала вводить новый внутренний язык программирования скриптов игры. Старый язык скриптов уже изжил себя и программировать на нем было весьма затруднительно.

Как и в большинстве подобных скриптовых языках других игр за основу был взят синтаксис С++ и объектно-ориентированное программирование. Раз уж игра создается с помощью Visual C++, то это зачем придумывать что-то иное!

Они создают игру на С++, затем компилируют DLL и EXE, но часть скриптов как бы «остается не скомпилированной» и представляется нам в текстовом виде, чистым листингом. Вот эту часть нам доступна для модификации и мы можем изменять эти скрипты сообразно нашей фантазии.

Почти все скрипты упакованы в файл scripts.pbo и если его "разбинарить», то мы получим папку scripts с содержимым.

Кто мало знаком с С++ я немного расскажу, что он из себя представляет. (В силу своих познаний.)

И так…

Фактически вся игра — это классы. Некоторые сущности со свойствами и функциями. Скажем класс PlayerBase — базовый класс игрока. Класс может наследовать другой класс. Т.е. есть родительский класс и есть наследуемый класс. Для того же PlayerBase родительским классом будет ManBase.

 

7k5JKm7PvEE.jpg

 

Дочерний класс наследуют все свойства и функции родительского класса. При том в дочернем классе можно добавить новые свойства и функции, а если нужно функции можно «переопределять» — функция с одинаковым именем в родительском классе и дочернем будут выполнять разные действия.

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

Например (простой пример): Класс Игрок у него есть свойство Жизненные силы.

Функция класса выполнит какое-то действие или произведет вычисление и может вернуть значение.

Например (простой пример): ПредметВРуке = Игрок.ЧтоВРуке(); — в переменную вернется ссылка на предмет в руках у персонажа или NULL (ничего).

Использование классов в скриптах.

Первейшее — это мне нужно определить класс, указать что он наследует, какие будут свойства и функции у класса.

class PlayerBase extends ManBase — имя класса PlayerBase и он дочерний класса ManBase. Так что все те свойства, которые были определены в классе ManBase, будут и у него. Добавляем новые свойства:

private int m_BloodType; — ManBase не содержит свойства тип крови, а вот у PlayerBase такое свойство будет. Свойство я определил как private пользоваться им я могу только внутри класса и получить его из другого класса не смогу. Поэтому я добавлю функцию:

int GetBloodType()

{

return m_BloodType;

}

При вызове этой функции из другого класса мне вернется тип крови.

Мой класс выглядит так:

sSSFwn2usDU.jpg

 

Теперь, где мне нужно, я могу получить тип крови игрового персонажа.

PlayerBase player; ← Создаю переменную класса PlayerBase.

player = GetGame().GetPlayer(); ← присваиваю переменной значение нужного мне объекта.

int bloodT = player.GetBloodType(); ← получаю тип крови моего объекта.

К примеру класс ManBase имел свойство position. Тип vector. (Пример только для примера, в реальности это не так).

Поскольку PlayerBase наследует класс ManBase, то имеет тоже свойство и я могу получить его:

vector posPlayer = player.position;

vector — это тип данных, как int (целые числа) или float (вещественные). Это массив вида [float, float, float]. Применяется в игре для задания координат или направления — [x, z, y].

 

Share this post


Link to post
Share on other sites
  • 0

Ну и немного примеров, тс из реальной жизни

 

1. GetGame().GetPlayer().GetInventory().CreateInInventory("Knife"); - кладем нож в инвентарь игроку

 

То же самое

Game mygame = GetGame();
PlayerBase player = mygame.GetPlayer();
InventoryBase inv = player.GetInventory();
inv.CreateInInventory("Knife");

 

1. GetHudDebug().RefreshCrosshairVisibility();

GetHudDebug() - это функция класса которая вернет какой-то объект, определенного класса, а RefreshCrosshairVisibility() это функция этого объекта.

 

 

 

Share this post


Link to post
Share on other sites
  • 0

BorizzK ну понятно, что пилить, на то и есть он, моддинг. BIS вообще все по своему считает, и то что там кто-то по UID разграничение доступа назначает для BIS это вообще не существует. Вот зуб даю, что сделают они это через #login в чате с заменой интерфейса shift p с армы на интерфейс админ-панели в будущем, и проверка будет проходить лишь по статусу админа на сервере (т.е. залогинился ли игрок или нет).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • By magliner
      Привет ! Ну вот моя история с вопросом в конце.. Я фанат Дэйз ванилы черноруси, заколебало сидеть на бездушных серверах со слабой админкой и терять лут от софтеров, решил создать под свои скромные запросы около ванильный сервер.. Нашел хорошего исполнителя, быстро и четко запустили отладили и ВОТ я имею СВОЙ сервер.. клас! вечер восторга и изучения
      Пожалуйста, Войдите или Зарегистрируйтесь, чтобы увидеть это: Вложение.

      Пожалуйста, Войдите или Зарегистрируйтесь, чтобы увидеть это: Вложение.
    • By SemKa1407
      Ссылка на архив: https://disk.yandex.ru/d/WmYW5AcZozGSiA
      Инструкция, написанная на коленке, есть в архиве (для полных нулей).
    • By Troy1
      Всем привет. Подскжите ну или помогите пожалуйста решить вопрос.
      Вопрос звучит так. На сервере есть трейдер зоны и базы игроков. 
      Если в течение определённого времени, на пример 1 - 2 часа с машиной не кто не взаимодействует и машина не находится в зоне трейдера или на теретории базы, то машина отлетает в гараж или на штраф стоянку.
      На сервере используется TraderPlus.
       
      Есть такие решения у кого?
      За ранние благодарю.
    • By radical
      Доброго времени суток! Хотел вот поинтересоваться, плюс по возможности чтобы растолковали что к чему.
      Суть вопроса: хочу на сервер сделать те же самые ванильные вещи, но, кхм, размер клеточек у ванильных по меньше прописать, чтоб в инвентаре поместились. Как это сделать я примерно понял, config.cpp я поправлю, но встал вопрос ребром:  но кроме этого файла, что надо делать. Вопросов много появляется, а в интернете информацию сложно накопать. Решил попросить помощи у знающих людей.
      1. По возможности хотелось бы от начала до конца увидеть весь путь изменения одного ванильного предмета
      2. Из просьбы что выше появляется вопрос: с остальными ванильными предметами такое же решение делать? ( Это при условии, если тема 1 решится)
       
      P.S. Если будут какие то файлы, ссылки, да даже просто объяснения, это меня сдвинет с мёртвой точки, а то завис)
    • By fedotovyasha
      Где можно достать карту в очень высоком разрешении, все в интернете такого себе качества. Хочу сделать свою карту
  • Our picks

×
×
  • Create New...

Important Information

By using this site, you automaticly agree to our Guidelines and Privacy Policy.
We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.