• Уважаемые гости и новички, приветствуем Вас на нашем форуме
    Здесь вы можете найти ответы практически на все свои вопросы о серии игр «Готика» (в том числе различных модах на нее), «Ведьмак», «Ризен», «Древние свитки», «Эра дракона» и о многих других играх. Можете также узнать свежие новости о разработке новых проектов, восхититься творчеством наших форумчан, либо самим показать, что вы умеете. Ну и наконец, можете обсудить общие увлечения или просто весело пообщаться с посетителями «Таверны».

    Чтобы получить возможность писать на форуме, оставьте сообщение в этой теме.
    Удачи!
  • Друзья, доброго времени суток!
    Стартовал новый литературный конкурс от "Ордена Хранителей" - "Пираты Миртанского моря".
    Каждый может принять в нём участие и снискать славу и уважение, а в случае занятия призового места ещё и получить награду. Дерзайте
  • Дорогие друзья, год подходит к концу, и пришло время подвести его итоги и наградить достойных

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

Union SDK - Инструменты разработчика

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.301
Благодарности
4.641
Баллы
625
  • Первое сообщение
  • #1
UnionProjectIcon.png


Union SDK

инструменты разработчика

Тема находится в состоянии наполнения



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

Рекомендуется смотреть на YouTube, поскольку там имеется сегментированный таймлайн.






Схемы классов движка
1600263933953.png
1600263981919.png
1600264017579.png
 

Вложения

  • sizeof.xlsx
    896,7 KB · Просмотры: 77
  • Union_SDK_1_0m.zip
    20,6 MB · Просмотры: 94
Последнее редактирование:

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.301
Благодарности
4.641
Баллы
625
Насколько я понимаю скрипт создаст мне npc с определенным id и будет присутствовать всегда в мире и в сейве
Не проблема. Персонажей с одинаковым id полно и без твоих.
Рандом внешнего вида скриптом наиболее оптимальный вариант, плюс довольно легко делается. В совокупности с плагином может идти в виде скрипта-инъекции.
Мне что бы сделать хотя бы имитацию рандома придется сделать пул таких npc
Скрипты открывал? Все можно зарандомить пулом правильных функций, возвращающих случайные атрибуты. При каждом новом создании npc от инстанции со случайной выборкой атрибутов, рандом будет работать всегда, так как инстанция ни что иное, как функция с неявным this.
Рандом отработает при новой игре или загрузке игры
Для сохраненных персонажей он не сработает (почти), это будет правильно, если, как ты говоришь, по задумке за тобой может увязаться персонаж. Если же он не играет какой-то важной роли, то есть замечательный флаг класса zCVob::dontWriteIntoArchive. Вся массовка может быть выгружена с окончанием сессии.
Но не вышло. Может нужно активировать что то после InsertNpc() что бы начала обрабатываться очередь?
Лучше делать ai на скриптах, в любом случае без минимальной рутины он будет вести себя как дерево. Но сначала изучи инъекции, если плагин не будет привязан к моду.
 

Jedi

Участник форума
Регистрация
11 Янв 2023
Сообщения
11
Благодарности
2
Баллы
15
Gratt
Спасибо за подробный ответ! Инъекции звучит как спасение, на самом деле)
В совокупности с плагином может идти в виде скрипта-инъекции.
Особенно это
если плагин не будет привязан к моду
и это, если я правильно все понял

Все таки правда придется хорошо покурить даедалус))
 
Последнее редактирование:

Slavemaster


Модостроитель
Регистрация
10 Июн 2019
Сообщения
1.086
Благодарности
1.909
Баллы
320
Рандом отработает при новой игре или загрузке игры, не знаю точно как это работает.
Код в instance-функции отрабатывает при каждой загрузке NPC. И даже при загрузке NPC из сейва, хотя после этого поля перезаписываются.
Попытался сделать это так:
InsertNpc не спавнит NPC мгновенно. Можно использовать oCNpc::Enable.
 

Jedi

Участник форума
Регистрация
11 Янв 2023
Сообщения
11
Благодарности
2
Баллы
15
InsertNpc не спавнит NPC мгновенно. Можно использовать oCNpc::Enable.
Похоже мне не хватало этой команды
C++:
rtnMan->UpdateSingleRoutine(pNpc);
Непись оживает и после ogame->spawnman->InsertNpc и после oCNpc::Enable, разницы не заметил.

Это правда оооочень сильно помогло. Очень крутой инструмент *thumbs up*
Он покрыл все мои потребности во внешности персонажа и поведении персонажа. Благо имя персонажа можно без каких-либо проблем менять на лету в плагине
C++:
std::string name = "";
pNpc->name[0] = zSTRING(name.c_str());
Поведение можно менять в скриптах через диалоги среди пула рутин, которые можно там же расписать
Daedalus:
Npc_ExchangeRoutine(self,"FOLLOW");

Но есть момент о который я споткнулся опять( Я бы хотел на лету менять сообщения диалога внутри плагина. Сами текстовые строки фраз и пунктов выбора диалога. Вот они в скриптах:
Daedalus:
AI_Output(...);    //Фраза

instance DIA_ANY_HELLO(C_Info)
{
    ...
    description = "Пункт диалога";
    ...
};
И как это сделать я не смог разобраться пока что.

Вот пара векторов, куда начал копать:
Насколько я понял: oCInfo - это класс инстанса всей ветки диалога. Через него что то изменить у меня не получилось. Хоть и получить его как то так удалось
C++:
oCInfo* pInfo = ogame->infoman->GetInformation(player, pNpc, 0);
// где 0 - я так понял порядковый номер диалоговой ветки, 
// которая зависит от того где она инициализирована в скрипте даедалуса.
description могу только прочитать через pInfo->GetText(), изменить не могу. Строки от AI_Output не понял как даже прочитать. Видимо в буфере памяти лежит структура или связный список из этих штук. Скорее всего GetDataAdr() GetDataSize() как раз для этого, но как их прочитать не знаю) Возможно как то через парсер, но даже если выйдет - смогу ли изменить ее? Даже если не буду менять размер этого буфера, что бы избежать вылета.

Еще один вектор моих изысканий: а смогу ли я в таком случае с нуля добавить хотя бы простую прямую диалоговую ветку хотя бы без ветвления? Вроде есть oCMsgConversation, который вроде похож по полям на AI_Output, но как им пользоваться не понял. Этот лес показался мне еще дремучее)

Еще один вариант над которым размышлял: можно ли как то динамически повлиять на скрипт из плагина? Что уже мне кажется полным бредом по определению.

Возможно будет проще мне найти две функции, которые рендерят текст для пунктов диалога и для фраз и там в тупую заменить одну строку другой. А в скрипте заранее подготовлю удобные для поиска шаблонные переменные аля {{dia_text_1}} - которые и буду ловить в if else.

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

Slavemaster


Модостроитель
Регистрация
10 Июн 2019
Сообщения
1.086
Благодарности
1.909
Баллы
320
Непись оживает и после ogame->spawnman->InsertNpc и после oCNpc::Enable, разницы не заметил.
Могу сказать, что записи СпаунМенеджера сохраняются в сейве.
И как это сделать я не смог разобраться пока что.
Если из скриптов, то можно в condition функции присвоить, так как она перед отображением всё равно вызывается: DIA_ANY_HELLO.description = "Bla-bla-bla".
description могу только прочитать через pInfo->GetText(), изменить не могу.
Посмотри на поле pInfo->pd
Еще один вектор моих изысканий: а смогу ли я в таком случае с нуля добавить хотя бы простую прямую диалоговую ветку хотя бы без ветвления? Вроде есть oCMsgConversation, который вроде похож по полям на AI_Output, но как им пользоваться не понял. Этот лес показался мне еще дремучее)
У меня есть кусок кода, по которому я получал текст диалога. Возможно, присвоение текста делается аналогично:
C++:
void SetName(const string& name)
{
    this->name = name;
    this->text = "";

    const int number = ogame->GetCutsceneManager()->LibValidateOU(Z name);

    if (number < 0)
        return;

    zCCSBlock* block = ogame->csMan->LibGet(number);
    zCCSAtomicBlock* atomic = dynamic_cast<zCCSAtomicBlock*>(block->GetChild(0));
    oCMsgConversation* message = dynamic_cast<oCMsgConversation*>(atomic->command);
    this->text = A message->text;

    return;
}
Еще один вектор моих изысканий: а смогу ли я в таком случае с нуля добавить хотя бы простую прямую диалоговую ветку хотя бы без ветвления? Вроде есть oCMsgConversation, который вроде похож по полям на AI_Output, но как им пользоваться не понял. Этот лес показался мне еще дремучее)
Ну как минимум, можно из плагина внешние функции вызывать. Хоть это и не совсем хорошо, но работать будет.
 

Jedi

Участник форума
Регистрация
11 Янв 2023
Сообщения
11
Благодарности
2
Баллы
15
Могу сказать, что записи СпаунМенеджера сохраняются в сейве.
Возможно я тебя не верно понял. Но я попробовал заспавнить моба через оба варианта и сохранить игру. При загрузке нпц стоят на том же месте. Для меня это будет не критично я думаю, т.к. планирую в определенный момент выгружать их через
C++:
ogame->spawnman->DeleteNpc(pNpc);

Посмотри на поле pInfo->pd
C++:
pInfo->pd.description = "Вариант диалога";
Работает идеально, спасибо)

У меня есть кусок кода, по которому я получал текст диалога.
Это мне очень помогло, спасибо! Я правда не понял какую строку ты передаешь в аргументе. ogame->GetCutsceneManager()->LibValidateOU(...) мне всегда возвращала значение 1.
Но я смог сделать по-другому:
C++:
zCCSBlock* block = ogame->csMan->LibGetFirst();
while (block = ogame->csMan->LibGetNext()) {
    zCCSAtomicBlock* atomic = dynamic_cast<zCCSAtomicBlock*>(block->GetChild(0));
    oCMsgConversation* message = dynamic_cast<oCMsgConversation*>(atomic->command);

    if (message->name == "DIA_Rnd_Hello_14_00.WAV") {
        // max 275 symbols
        message->text = "Пу пу пууу";
    } else if (...) {
        ...
    }
    ...
}
И да запись на удивление работает и работает так, то динамически подстраивается время показа фразы в диалоге :)
 

Slavemaster


Модостроитель
Регистрация
10 Июн 2019
Сообщения
1.086
Благодарности
1.909
Баллы
320
Возможно я тебя не верно понял. Но я попробовал заспавнить моба через оба варианта и сохранить игру.
Забей. При вставке NPC он всё равно из СпаунМенеджера удаляется (хотя мне и не понятно, зачем его туда засовывать).
Я правда не понял какую строку ты передаешь в аргументе
Третий аргумент функции AI_Output
 

Jedi

Участник форума
Регистрация
11 Янв 2023
Сообщения
11
Благодарности
2
Баллы
15
Уважаемые форумчане, столкнулся с такой проблемой. Может кто встречался тоже:

Насильно вывожу из состояния диалога таким образом:
Код:
player->EV_StopProcessInfos(
    new oCMsgConversation(
        oCMsgConversation::EV_STOPPROCESSINFOS,
        player
    )
);

Адекватно все отрабатывает, кроме одной особенности - на ESC перестает вызываться меню. После входа\выхода в диалог с любым другим NPC - вызов меню восстанавливается. Как то можно этот маленький баг пофиксить?)
 

Slavemaster


Модостроитель
Регистрация
10 Июн 2019
Сообщения
1.086
Благодарности
1.909
Баллы
320
Попробуй почистить GetEM() и потом через него же добавить сообщение EV_STOPPROCESSINFOS
Пост автоматически объединён:

Может, ещё и собеседника почистить придётся.
 
Последнее редактирование:

Jedi

Участник форума
Регистрация
11 Янв 2023
Сообщения
11
Благодарности
2
Баллы
15
Попробуй почистить GetEM() и потом через него же добавить сообщение EV_STOPPROCESSINFOS
Действительно, так работает идеально, спасибо! Причем не чистил, просто поменял способ отправки в EM
Код:
oCNpc* who = npc->GetTalkingWith();
if (who) {
    npc->GetEM(FALSE)->OnMessage(
        new oCMsgConversation(oCMsgConversation::EV_STOPPROCESSINFOS),
        npc
    );
}
 

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
462
Благодарности
286
Баллы
230

Jedi,​

Вот ещё один вариант экстренного выхода ГГ из диалога:
C++:
void Close_DialogeSystem()
{
    oCInformationManager& infoman = oCInformationManager::GetInformationManager();
    if (!infoman.HasFinished())
    {
        if (infoman.Npc)
        {
            infoman.Npc->StopRunningOU();
            infoman.Npc->GetEM()->Clear();
        }
        if (player)
        {
            player->StopRunningOU();
            player->GetEM()->Clear();
        }
        infoman.Exit();
    }
}

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

СырGuy

Участник форума
Регистрация
4 Мар 2022
Сообщения
29
Благодарности
5
Баллы
45
Добрый денек. Пытаюсь добавить файл Union ".cpp", согласно уроку номер 3. Но почему-то его нету в меню добавления. Union SDK установлен. Что я пропустил, подскажите, пожалуйста


Урок:


1698130479531.png



Мое:

1698130327433.png
 

LikerGothic


Модостроитель
Регистрация
11 Фев 2017
Сообщения
1.661
Благодарности
2.486
Баллы
380
СырGuy, в визуал студии 2015 версии SDK чето плохо работает, там у меня тоже нет пункта, использую 2017 или 2019 студию, ну или новее.
 

СырGuy

Участник форума
Регистрация
4 Мар 2022
Сообщения
29
Благодарности
5
Баллы
45

MEG@VOLT

★★★★★★★★★
ТехАдмин
Регистрация
24 Мар 2006
Сообщения
9.900
Благодарности
6.777
Баллы
1.625
Фух, как же это познавать что-то новое...
MW 7, Gratt, MEG@VOLT вот, скинул систему диалогов, если вдруг заходите посмотреть.
Псиб, вопросы ниже))
Мег, вот тебе и квест на ближайшие пару дней - словить зависание
скорее всего пару дней на понятие че-кому надо))
MEG@VOLT, так поставь любую другую версию компилятора, или ты про какой-то другой плагин.
А да пофиг, 2022 уже поставил, на ней щас ковырять буду.
И так:
"Код плагина.txt"
Все правильно?
1698835604380.png

Далее внизу вставляю функцию из AB_DialogMany.cpp.
И в Plugin.h все из AB_DialogMany.h
Ошибок в файле Plugin.h студия не находит, а вот в Plugin.cpp 23 ошибки:
C++:
Серьезность    Код    Описание    Проект    Файл    Строка    Состояние подавления
Ошибка (активно)    E0135    класс "Gothic_II_Addon::zCAICamera" не содержит члена "StartDialogCam_Union"    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    228 
Ошибка (активно)    E0020    идентификатор "AI_WaitTillEnd" не определен    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    172 
Ошибка (активно)    E0165    слишком мало аргументов в вызове функции    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    199 
Ошибка (активно)    E0135    класс "Gothic_II_Addon::zCAICamera" не содержит члена "StartDialogCam_Union"    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    226 
Ошибка (активно)    E0258    оператор "this" можно использовать только внутри нестатической функции-члена    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    235 
Ошибка (активно)    E0135    класс "Gothic_II_Addon::oCNpc" не содержит члена "StopRunningOU_Union"    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    243 
Ошибка (активно)    E0020    идентификатор "printWin" не определен    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    245 
Ошибка (активно)    E0135    класс "Gothic_II_Addon::oCInformationManager" не содержит члена "OnInfo_Union"    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    252 
Ошибка (активно)    E0020    идентификатор "printWin" не определен    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    256 
Ошибка (активно)    E0020    идентификатор "printWin" не определен    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    260 
Ошибка (активно)    E0135    класс "Gothic_II_Addon::CGameManager" не содержит члена "HandleCancelKey_Union"    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    269 
Ошибка (активно)    E0135    класс "Gothic_II_Addon::CGameManager" не содержит члена "HandleCancelKey_Union"    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    270 
Ошибка (активно)    E0020    идентификатор "IsGameRunning" не определен    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    271 
Ошибка (активно)    E0020    идентификатор "gameSession" не определен    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    271 
Ошибка (активно)    E0020    идентификатор "zERR_MESSAGE" не определен    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    284 
Ошибка (активно)    E0020    идентификатор "zERR_MESSAGE" не определен    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    286 
Ошибка (активно)    E0020    идентификатор "NPC_TALK_ANI" не определен    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    304 
Ошибка (активно)    E0165    слишком мало аргументов в вызове функции    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    361 
Ошибка (активно)    E0289    отсутствуют экземпляры конструктора "Gothic_II_Addon::oCMsgAttack::oCMsgAttack", соответствующие списку аргументов    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    368 
Ошибка (активно)    E0289    отсутствуют экземпляры конструктора "Gothic_II_Addon::oCMsgWeapon::oCMsgWeapon", соответствующие списку аргументов    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    371 
Ошибка (активно)    E0135    класс "Gothic_II_Addon::oCNpc" не содержит члена "AI_TurnToNPC"    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    375 
Ошибка (активно)    E0020    идентификатор "AI_WaitTillEnd" не определен    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    386 
Ошибка (активно)    E0020    идентификатор "AI_WaitTillEnd" не определен    UnionPlugin1    C:\Users\user\source\repos\UnionPlugin1\UnionPlugin1\Plugin.cpp    396
ну и собсно не компилится.
И не понял куда вставлять код из "Внешние функции, Union.txt"
Во вложении Plugin.cpp и Plugin.h
 

Вложения

  • UnionPlugin1.zip
    3,1 KB · Просмотры: 1

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.301
Благодарности
4.641
Баллы
625
В самом верху есть комбобокс с конфигурацией проекта. Выбери там Release G2A. В настройках проекта (пкм по проекту > свойства) и укажи версию компилятора v143, которая соответствует 2022 студии. Код внешних функций скопируй и вставь перед функцией define externals. Создай cpp и h файлы в проекте, используя Union Wizard и расположи их в диалоге выше, чем plugin cpp и h. Затем скопируй в них информацию из ликеровских файлов.
 

LikerGothic


Модостроитель
Регистрация
11 Фев 2017
Сообщения
1.661
Благодарности
2.486
Баллы
380
MEG@VOLT, выбери тип плагина G2A Release или что-то похожее.
Внешки вставлять в Game_DefineExternals (ну которые с++ код)
 

LikerGothic


Модостроитель
Регистрация
11 Фев 2017
Сообщения
1.661
Благодарности
2.486
Баллы
380
MEG@VOLT, printWin удали, это тестовый вывод.
А ну и еще все функции в API надо сувать.
Например zBOOL CGameManager::HandleCancelKey_Union(int key); надо добавлять в userAPI в h файлы
 

MEG@VOLT

★★★★★★★★★
ТехАдмин
Регистрация
24 Мар 2006
Сообщения
9.900
Благодарности
6.777
Баллы
1.625
@MEG@VOLT, выбери тип плагина G2A Release или что-то похожее.
А без разницы
выбираю любой из этих:
1698836665443.png

и эти 23 ошибки все равно остаются))
А вот простого G2A Release нет, в 2017 студии я тоже не увидел простого G2A Release
@MEG@VOLT, printWin удали, это тестовый вывод.
3 ошибки пропало :D


Выбери там Release G2A.
ну ты видел на скрине выше))
Код внешних функций скопируй и вставь перед функцией define externals.
Внешки вставлять в Game_DefineExternals (ну которые с++ код)
куда? *around the head*
Создан новый проект:
1698837550185.png

Ошибки все те же ))
 

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.301
Благодарности
4.641
Баллы
625
Удали весь этот хлам и создай чистый проект. Чистым его и собери. Только потом добавляй в него код.
Версию движка ставишь любую G2A + Release, затем для этой конфигурации меняешь тулсет на v143.
IMG_20231101_142334.jpg


Жмешь ок и далее в самом верху выбираешь тот же движок, который выбрал в настройках проекта. Затем пробуешь скомпилить.
 
Сверху Снизу