Перейти к контенту

[SOC] Мелкие правки движка


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

Хотел бы узнать план. Какие еще "уроки" будут в ближайшее время?

Изменено пользователем Kondr48
Добавлено Kondr48,

Как такового плана нет. Просто в процессе своих мелких правок решил описывать, как и что делаю. Так по мере работы буду выкладывать.

Ссылка на комментарий

Может не по теме, помещу под спойлер, но все же:

 

В рамках 1.0004 - как убрать красную надпись в режиме demo_record. Убрать нормально, способ "потыкать на кнопочки" приводит к записи демо, что не нужно, и убрает весь худ пока не удалишь user.ltx. Интересно именно удаление вызова отрисовки текста в движке.
Искал такие вещи в интернетах, есть для 1.0006 - и то ссылка не пашет.
А тема идеально вроде подходит)

 

Не соответствует правилам.

Ссылка на комментарий

CRAZY_STALKER666, в исходниках вот здесь стоит посмотреть: FDemoRecord.cpp

if (psHUD_Flags.test(HUD_DRAW)){
			if ((Device.dwTimeGlobal/750)%3!=0) {
//				pApp->pFontSystem->SetSizeI	(0.02f);
				pApp->pFontSystem->SetColor	(color_rgba(255,0,0,255));
				pApp->pFontSystem->SetAligment(CGameFont::alCenter);
				pApp->pFontSystem->OutSetI	(0,-.05f);
				pApp->pFontSystem->OutNext	("%s","RECORDING");
				pApp->pFontSystem->OutNext	("Key frames count: %d",iCount);
				pApp->pFontSystem->SetAligment(CGameFont::alLeft);
				pApp->pFontSystem->OutSetI	(-0.2f,+.05f);
				pApp->pFontSystem->OutNext	("SPACE");
				pApp->pFontSystem->OutNext	("BACK");
				pApp->pFontSystem->OutNext	("ESC");
				pApp->pFontSystem->OutNext	("F11");
				pApp->pFontSystem->OutNext	("F12");
				pApp->pFontSystem->SetAligment(CGameFont::alLeft);
				pApp->pFontSystem->OutSetI	(0,+.05f);
				pApp->pFontSystem->OutNext	("= Append Key");
				pApp->pFontSystem->OutNext	("= Cube Map");
				pApp->pFontSystem->OutNext	("= Quit");
				pApp->pFontSystem->OutNext	("= Level Map ScreenShot");
				pApp->pFontSystem->OutNext	("= ScreenShot");
			}
		}

 

 

А в рамках 4 патча даже не знаю: хексом мб это искать и закомментировать. По сути это и смысл использования исходников: нашел то, что нужно и подправил/дописал. А так по сути тема больше для правок исходников.

Изменено пользователем Kondr48
  • Спасибо 1
Ссылка на комментарий

Я, кстати, категорически против что колбеки вешали исключительно на актора, т.е. колбек на удар ножом вешаем на объект (биндер) ножа, передаём точку, вектор и силу удара, так же на выстрел из оружия, любого, ручного, станкового, БТР'а, вертолёта вешаем на сам объект, а не на несчастного актора. А то получается полная солянка, а не скриптинг. Поверьте так гораздо удобней и соответствует  ООП. А так же, колбек на нажатие клавиш должен быть не только на акторе, но и на активный управляемый объект, это: актив итем(оружие которое держим в руках), текущий холдер(техника в которой сидим), активный детектор(который держим в руках). Я эти идеи частично реализовал в своём проекте XRay-Extensions NanoBot.

Изменено пользователем НаноБот
  • Согласен 1

...в конце концов, важен лишь, машинный код.

СТАЛКЕР только для ПК!

Ссылка на комментарий

НаноБот, если колбек нужен будет не только актору, то да. Согласен. Однако в случае с ножом, есть ли в этом смысл, если этот колбек будет использоваться только для актора?

P.S. Нет желания подкинуть сюда пару статеек по работе на исходниках? К примеру адаптацию Вашего проекта новая баллистика? Или те же колбеки?

Изменено пользователем Kondr48
  • Спасибо 1
Ссылка на комментарий

По поводу коллбэков возникает вопрос: а точно ли все, что есть именно в виде коллбэков и все, что планируется добавить, надо делать именно "коллбэками" ?

Там разного обрамления ненужного не слишком многовато получается ?

 

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

Сейчас там по умолчанию стоят "затычки", которые есть-пить не просят. Возникает мысль добавить этот самый "коллбэк". Добавляем. Начинаем прописывать в конфигах, script_binding =,

все вот эти вот load/save/init/reinit/update и прочую ересь совсем не нужную, разгребать те скрипты, которые сто лет ни кто не трогал, потому что ни за каким надом нужны не были...

То есть, куча работы и накладных расходов.

 

И, да, само вот это вот "а на актора или еще куда"

Может, подумать уже какой другой механизм ?

P.S. Нет желания подкинуть сюда пару статеек по работе на исходниках?

Поддерживаю. Кто уже довольно неплохо разгреб, в каких файлах функциях что лежит - может поделитесь ?

Изменено пользователем Dennis_Chikin
  • Согласен 2
Ссылка на комментарий
добавление, например, на выстрел в Вашем примере - это всего лишь вызов в нужном месте что нибудь типа псевдокод вызова калбека на выстрел из класса оружия
auto source=this;
if (m_Owner==Actor()) 
{
 source=Actor();
}

source->callback(типкалбекахит)(кто_стрелял, из_чего, чем);
теперь в классе актора, или сталкера (да, нужен скриптовый класс биндера "script_binding= ", иначе у чего будет движок вызывать эти методы при их наличии?) регистрируем этот калбек через set_callback в одном вызове (ну и в одном очищаем) - чаще всего init/net_destroy. все, дальше обрабатываем так как надо. никаких load/save/update не требуется. 
еще один пример - реализация калбека на хит по объекту. движком генерируем вызов этого калбека из CGameObject (прародителя усех объектов в луа). в самих скриптах только в объектах (биндере), например, бочки делаем обработку этого калбека - и все, обрабатываются только бочки. 

И, да, само вот это вот "а на актора или еще куда

Само собой, иногда приходиться идти на хитрость - есть окно инвентаря - вот куда ему добавить перехват калбека , если по умолчанию, ни сам класс этого окна не экспортируется в игру (это полбеды), ни в игре нету дочернего класса от CUIInventoryWnd, чтобы на нем добавить обработчики (как это например сделано для главного меню). Но со вторым вариантом возиться долго и не интересно. проще всегда делать 
Actor()->callback(калбек_из_окна)(окно_каллбека, другие параметры)
и в биндере актора перехватить это калбек. все, чесно и прозрачно. Придумывать единый механизм, отличный от Actor() для таких целей - ну не знаю, не уверен что это окупиться. 

Кто уже довольно неплохо разгреб, в каких файлах функциях что лежит - может поделитесь

Поделиться чем? в движке примерно 4к файлов *.cpp. Сформулируйте вопрос... 
Изменено пользователем Kondr48
Немного подправил цитаты.
  • Нравится 1
Ссылка на комментарий

Создание нового слота

...

после: m_slots_array[sLOT_QUICK_ACCESS_3] = m_pUISlotQuickAccessList_3;

...

У меня нет нигде m_slots_array. Результат поиска в 4611 файлах - 0. Версия исходников 1.0007(rc1). Если пропустить все, касаемо  m_slots_array - работать новый слот будет ?

Изменено пользователем UnLoaded
Ссылка на комментарий

UnLoaded

Версия исходников 1.0007(rc1)

Ну это еще не аргумент. Я например форкнулся с r180 с репозитория на xp-dev, собственно туторы по этой версии я и писал. Если у Вас именно "чистые" исходники, то для начала вам нужно добавить туда все недостоющие части кода по слотам из этой (или более высокой, если хотите) ревизии. А если ревизия итак оттуда, то, по данному "тутору" слоты легко создаются и 

m_slots_array

там присутствует.

Изменено пользователем Kondr48
Ссылка на комментарий

Восстановление функции рождения артефактов при срабатывании аномалии
Каким образом и куда вставлять данные файлы?
 

Увы, у меня нет исходников, а если бы и были, то что потом делать с исходниками?

 

(при слиянии потерялась вторая заметка)

Вот то и делать: ставить visual studio, и разбираться, как оно работает. (Если честно, то я это поделие так и не осилил - слишком много окошечек и кнопочек.) dc

Изменено пользователем Dennis_Chikin
Добавлено Kondr48,

В исходники, куда же еще.
ваша_папка_исходников\trunk\xray\xr_3da\

Ссылка на комментарий

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

Для начала, в движке CoP есть такой удобный инструмент как UIHelper, для дальнейшей работы он нам понадобится, поэтому добавляем в xrGame\ui:

1. UIHelper.h

////////////////////////////////////////////////////////////////////////////
//	Module 		: UIHelper.h
//	Created 	: 17.01.2008
//	Author		: Evgeniy Sokolov
//	Description : UI Helper class
////////////////////////////////////////////////////////////////////////////

#ifndef	UI_HELPER_H_INCLUDED
#define UI_HELPER_H_INCLUDED

class CUIXml;
class CUIWindow;
class CUIStatic;

class UIHelper
{
public:
	UIHelper		() {};
	~UIHelper		() {};

	static	CUIStatic*			CreateStatic		( CUIXml& xml, LPCSTR ui_path, CUIWindow* parent );
};

#endif // UI_HELPER_H_INCLUDED
 

2. UIHelper.cpp:

////////////////////////////////////////////////////////////////////////////
//	Module 		: UIHelper.cpp
//	Created 	: 17.01.2008
//	Author		: Evgeniy Sokolov
//	Description : UI Helper class implementation
////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "UIHelper.h"
#include "UIXmlInit.h"

CUIStatic* UIHelper::CreateStatic( CUIXml& xml, LPCSTR ui_path, CUIWindow* parent )
{
	CUIStatic* ui			= new CUIStatic();
	if(parent)
	{
		parent->AttachChild	( ui );
		ui->SetAutoDelete	( true );
	}
	CUIXmlInit::InitStatic	( xml, ui_path, 0, ui );
	return ui;
} 

Здесь я оставил только добавление статика, на самом деле в ЗП с помощью этого инструмента можно все что угодно добавлять. Переносите себе по мере необходимости  :), идем дальше.

Нам нужен файл UIMainIngameWnd.h

в группе protected: находим:

CUIZoneMap* UIZoneMap;

И после добавляем:

CUIStatic* m_ind_outfit_broken;

Теперь файл UIMainIngameWnd.cpp.

Сначала не забудьте прописать 

#include "UIHelper.h"

в начале файла там где все остальные.

Находим:

void CUIMainIngameWnd::Init()

К примеру, после:

m_UIIcons			= xr_new<CUIScrollView>(); m_UIIcons->SetAutoDelete(true);
xml_init.InitScrollView		(uiXml, "icons_scroll_view", 0, m_UIIcons);
AttachChild			(m_UIIcons); 

Добавим:

m_ind_outfit_broken		    = UIHelper::CreateStatic(uiXml, "indicator_outfit_broken", this); 

Затем находим: 

void CUIMainIngameWnd::Update() 

И, например, перед:

// health&power
	UIHealthBar.SetProgressPos		(m_pActor->GetfHealth()*100.0f);
	UIMotionIcon.SetPower			(m_pActor->conditions().GetPower()*100.0f); 

Добавим:

PIItem	pItem = m_pActor->inventory().ItemFromSlot(OUTFIT_SLOT);
	m_ind_outfit_broken->Show(false);
	if (pItem)
	{
		float condition = pItem->GetCondition();
	    if (condition<0.75f)
	    {
		  m_ind_outfit_broken->Show(true);
		  if(condition>0.5f)
			m_ind_outfit_broken->InitTexture("ui_inGame2_circle_Armorbroken_green");
		  else if(condition>0.25f)
			m_ind_outfit_broken->InitTexture("ui_inGame2_circle_Armorbroken_yellow");
		  else
			m_ind_outfit_broken->InitTexture("ui_inGame2_circle_Armorbroken_red");
	     }
	} 

Теперь разберем что нужно будет сделать в конфигах.

indicator_outfit_broken 

это имя статика. Добавить надо его в maingame.xml вот так:

 <indicator_outfit_broken x="980" y="410" width="26" height="35" stretch="1"/> 

ну и, соответственно, "зарегистрировать" в игре вот эти текстуры:

"ui_inGame2_circle_Armorbroken_green"
"ui_inGame2_circle_Armorbroken_yellow"
"ui_inGame2_circle_Armorbroken_red"

На этом всё  :) . Собственно у меня по такой схеме сделаны все подобные иконки, потому что система ТЧ показалась мне неоправданно сложной и громоздкой. Ну, быть может, это на мой дилетантский взгляд.  :)

P.S. Конечно, лучше совместить прогресс бар, который показывает состояние брони и этот индикатор. Чтобы два раза не дергать состояние костюма на апдейте. Но я не стал усложнять урок)

 

 

Изменено пользователем Kondr48
  • Спасибо 1
Ссылка на комментарий

Поговорим немного о диалогах в ТЧ 1.0007. Наверное, большинство знают что диалоги (как, например, и артикли в энциклопедии) являются объектами, которые загружаются один раз за всю сессию игры (на основании паттерна Singleton) в структуру SPhraseDialogData : CSharedResource. т.е. если мы разрабатываем диалог, то для проверки того что именно мы написали необходимо выйти и зайти в игру полностью. Само собой это сводит на нет полностью работу с диалогами, создаваемыми скриптами (через експорт функций класса CPhraseDialog). Но часто хочется оживить Зону и разнообразить диалоги. 

1) расширяем чуть чуть экспорт CPhraseDialog

Добавляем в экспорт CPhraseDialog функцию SetPriority для изменения приоритета нашего диалога. Теперь он выглядит вот так:

class_<CPhraseDialog>("CPhraseDialog")
		.def("AddPhrase",			&CPhraseDialog::AddPhrase_script )
		.def("SetPriority",			&CPhraseDialog::SetPriority),
 

Этим мы можем при создании диалогов помещать начало нашего графа , например, в самый верх или них списка начальных фраз.

 

 

2) В связи с тем что 80-90% диалогов все таки статические (им хватает для жизни preconditions) - добавляем параметр, который позволит управлять, обновлять ли диалог каждый раз, или только при первой загрузке

в структуру

struct SPhraseDialogData : CSharedResource

добавляем поле-признак, например, bool b_bForceReload. в класс CPhraseDialog два метода

public:
	void					SetDialogForceReload(bool value=false) {data()->b_bForceReload=value;}
	bool					GetDialogForceReload() {return data()->b_bForceReload;}
 

 

 

CPhraseDialog::load_shared после SetCaption, например, добавляем

SetDialogForceReload(pXML->ReadAttribInt(dialog_node, "force_reload", 0)==1? true:false);

 

 

т.е. при наличии в конфиге диалога параметра force_reload="1" он помечается как перезагружаемый  :)

<dialog id="test_dynamic" force_reload="1">
	<init_func>subtest.gen_dialog1</init_func>
</dialog> 

3) Добавляем в класс окна диалогов признак, который указывает, что окно в данный момент инициализируется. Это нужно в связи с тем что CPhraseDialogManager::AddAvailableDialog может вызываться из других мест, не только из инициализатора окна диалога. позволяет избежать, например, перестроения диалога, когда он уже начат с кем то из НПС.

в класс CUITalkWnd добавляем

protected:
    bool                m_bInitState;
public:
    bool GetInitState() const {return m_bInitState;}

и инициализацию m_bInitState=false в конструктор класса.

 

 

в методе void CUITalkWnd::InitTalkDialog() в начале пишем
m_bInitState=true;
и аналогично в конце
m_bInitState=false;
Теперь мы имеем признак того что CUITalkWnd инизиализирует графы диалогов.

 

4) Изменяем метод загрузки данных для конкретного диалога с использованием методов CSharedResource

void CPhraseDialog::Load(shared_str dialog_id)
{
	m_DialogId = dialog_id;
	bool need_load=inherited_shared::start_load_shared(m_DialogId); //делаем инициализацию 	SPhraseDialogData* при первом вызове. если синглтон не был создан ранее - он создается, иначе возвращается созданный
        //результат функции - это флаг, указывающий, требуется ли загрузка данных при первичной инициализации.
	if (need_load) //структура создается первый раз, ее надо просто загрузить, также таким образом можно избежать двойного вызова метода загрузки
		inherited_shared::load_shared(m_DialogId, nullptr);
	else if (GetDialogForceReload()) //структура уже создавалась и загружалась ранее
	{ //но установлен флаг для принудительной перезагрузки
		CUIGameSP* ui_sp = smart_cast<CUIGameSP*>(HUD().GetUI()->UIGame());
		if (ui_sp && ui_sp->TalkMenu->GetInitState()) //перезагружаем данные только тогда, когда идет инициализация окна диалога
		{
			data()->SetLoad(false);//для структуры SPhraseDialogData устанавливаем флаг принудительной загрузки
			inherited_shared::load_shared(m_DialogId, nullptr); //обновляем данные
                        //inherited_shared::finish_load_shared вызывать не обязательно, так как load_shared уже выполняет его функционал.

		}
	}
} 

 

 

Все. теперь при каждом открытии окна диалога у Вас будет перезагружаться скрипт subtest.gen_dialog1, который Вам позволит генерировать случайные фразы, например, через math.random  :)

Также, параметр force_reload можно использовать и для перезагрузки на моменте отладки и построения диалогов из конфига xml, но надо учитывать, что данный метод не перезагружает скрипты, которые используются в precondition, строковые константы в других xml файлах и подобные внешние ресурсы. 

Добавлено Kondr48,

Хотелось бы добавить, что для успешной сборки в PhraseDialog.cpp нужно добавить инклуды:

#include "UIGameSp.h"
#include "HUDManager.h"
#include "level.h"
#include "ui\UITalkWnd.h"
 

Заметка изменена

  • Спасибо 3
Ссылка на комментарий

@Winsor, слишком муторный подход, мы просто убрали прокладки. Вот же я показывал:

 

 

 

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

 

 

function create_bye_phrase()
    if not bye_phr_idx then
        bye_phr_idx = math.random(4)
        bye_phr_idx = bye_phr_idx-1
    end
    return game.translate_string("actor_break_dialog_"..bye_phr_idx)
end

 

 

У меня вот как-то так пока, но это все, конечно, мишура:

 

 

C++ class CPhrase {
    function GetGoodwillLevel(); --// позволит задавать благосклонность фразе, последний параметр AddPhrase, но при ПЕРЕстроении графа ими будет пользоваться сподручнее
    function SetGoodwillLevel(number);
--// Karlan->ALL: финалайзер доделывать или нет? помоему он не нужен, мишура все это
};

C++ class CPhraseDialog {
    CPhraseDialog() --// конструктор класса
    --// Karlan->ALL: полной динамики я пока не добился
    --// FIXME почему-то не строится граф, вроде бы все вершины и ребра явно прописываю, но граф в итоге получается абсолютно полностью избитый, возможно для полной динамики придется сделать еще один подкласс, где будут методы полного построения графа в скриптах, так что пока динамический граф можно строить только из шаблонов
    function GetDialog(string); --// для теста
    function SetCaption(string); --// позволяет на лету указать(изменить) заголовок (показывается вместо нулевой фразы) (рекомендуется вызывать ДО создания графа(!))
    function SetPriority(number); --// позволяет на лету указать(изменить) приоритет (рекомендуется вызывать ДО создания графа(!))
    function IsFinished(); --// проверяет есть ли еще какие-то доступные фразы в графе, если true, то выкинет в список выбора темы
};

C++ class CPhraseScript {
    function SetScriptText(string); --// позволяет задать текст скриптом, на входе айди диалога и айди сказанной фразы в строковых представлениях
};

 

 

 

Что, возможно, действительно тут надо - написать класс для создания графов, у меня так руки и не дошли. Попробуй на досуге, я пытался грубыми врезками вклинится без сторонних классов (прямо в CPhraseDialog, как можно видеть), у меня не вышло, хотя совсем глубоко не окапывался. Я уже не помню, но по моему у меня были мысли экспортировать класс, который как раз эти графы все делает.

Ссылка на комментарий

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

Мой пост можно воспринимать как иллюстрацию - как победить shared_data.Она используется не только для диалогов.

Изменено пользователем Winsor
  • Нравится 1
Ссылка на комментарий

 

 

Все диалоги перестраивать каждый раз - лишняя нагрузка

Не все диалоги, а только те, к которым идет обращение. Нагрузки там никакой нет совершенно. Самый сложные диалоги у Сидоровича, и в скорости их чтения абсолютно ничего не изменилось, стоит-ли говорить о других?

 

 

 

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

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

 

 

 

Мой пост можно воспринимать как иллюстрацию - как победить shared_data.Она используется не только для диалогов.

О том я и говорю, у нас ее вообще нет.

 

Право на жизнь конечно имеет, но мне он кажется весьма переусложненным :).

Ссылка на комментарий

@Карлан, было бы неплохо, если бы Вы поделились частью исходников для изучения, как подобный механизм реализован у Вас, а именно CPhraseDialog::Load, CPhraseDialog::load_shared. xr_3da\xrGame\xml_str_id_loader.cpp тоже очень хотелось бы изучить :) 

Спасибо.

  • Спасибо 1
  • Согласен 1
Ссылка на комментарий

Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти
  • Недавно просматривали   0 пользователей

    • Ни один зарегистрированный пользователь не просматривает эту страницу.
×
×
  • Создать...