Сообщение отредактировал Вадим Буренков: 15 June 2009 - 17:42
Скриптинг в GTA IV
#101
Отправлено 15 June 2009 - 17:41
#102
Отправлено 16 June 2009 - 07:29
Сообщение отредактировал Вадим Буренков: 16 June 2009 - 08:34
#103
Отправлено 18 June 2009 - 09:28
Вадим, вещи типа
i32 = type LongInt; //32 битное знаковое целое u32 = type LongWord; //32 битное безнаковое целое i16 = type SmallInt; //16 битное знаковое целое
это определения синонимов. Вся документация - это сами заголовочные файлы и описания нативов в вики на этом сайте. Вызовы нативов упакованы в asi библиотеки, а вызвать мы их можем хоть из дельфи хоть из С, хоть из lua.
У меня такое предложение. Вместо однократного объявления в interface:
procedure AddScore(playerIndex : PID; score : i32); stdcall; external LIB;определить классы Player, Ped, Vehicles, и т.д., опубликовать функции:
type Playa = class public procedure AddScore(playerIndex : PID; score : i32); stdcall; procedure Char(playerIndex : PID; ptrPed : PPedID); stdcall; procedure Group(playerIndex : PID; pAnyGroup : PGroup); stdcall; function Id() : u32; stdcall; function Name(playerIndex : PID) : PChar; stdcall; ... end;Я тут укоротил имена функций, в принципе можно доть любые имена, и даже одни и те же для разных функций в разных классах. Потом уже в implementation писать:
implementation procedure Playa.AddScore; external LIB name 'AddScore'; // тут реальные имена function Playa.Id() : u32; external LIB name 'GetPlayerId'; function Playa.HasChar(playerIndex : PID) : b8; external LIB name 'PlayerHasChar'; ...Если занятся таким редактированием, то в принципе у натив-функций должна вырисоваться некая иерархия, и можно даже будет построить дерево классов с полиморфизмом (например функция здоровья для игрока и педа - override одной абстрактной функции), а не просто объявлять функции одну за другой.
Сообщение отредактировал JNikc: 21 June 2009 - 20:23
#104
Отправлено 18 June 2009 - 09:57
Прикрепленные файлы
#105
Отправлено 20 June 2009 - 13:53
Но я еще помимо разбивания на классы делаю работу с процедурами более удобной. Например чтобы создать машину нужно загрузить ее в память, проверить загружена ли она, создать ее и очистить память. Делать это крайне неудобно, поэтому я заношу в класс не стандартные процедуры, а измененные мной.
Вот процедура простого создания автомобиля:
function CreateCar(x,y,z:f32;CarModel:eModel):vehicle; begin RequestModel(CarModel); // запрашиваем модель // ждем пока не загрузится while not(HasModelLoaded(CarModel)) do begin Wait(0); end; //спавним тачку в координатах CreateCar(CarModel, x, y, z, Result, true); // освобождаем память MarkModelAsNoLongerNeeded(CarModel); end;А в скрипте можно создать машину всего одной командой
Car:=CreateCar(x,y,z,MODEL_ANNIHILATOR);Сейчас загрузил Alice Ultimate Delphi SDK, буду разбераться.
Сообщение отредактировал Вадим Буренков: 20 June 2009 - 13:55
#106
Отправлено 21 June 2009 - 19:49
В игре обсчим счетом ~3000 функций. Это больше, чем описано в Windows.pas, или WinNT.H (в смысле импортных)!!! При том, что в последних активно используются классы и ООП. Поэтому я вижу, что с таким обилием функций трудновато справится, не упаковав их. При этом спад в скорости врят ли будет большим.
Все типы
type ScriptAny = u32; Player = u32; Vehicle = u32; Ped = u32; Group = u32; Obj = u32; CoverPoint = u32; Train = u32; Interior = u32; Blip = u32; Pickup = u32; TextureDict = u32; Texture = u32; Fire = u32; Car = type Vehicle; // = u32 Char = type Ped; // = u32 Marker = type Blip; // = u32
это по сути ID, разных объектов. Т.е. в игре экземпляры этих типов могут иметь идентификаторы от 0 до 2^32 - 1, и этого точно хватит на все про все (можно было взять меньше, но 16 бит вроде мало, а 32 - прекрасно поддерживается большинством аппаратных платформ). Пока мы описываем все функции в модуле - для наглядности можно разделять разные ID, но если использовать классы, то за счет инкапсуляции становится ясно к чему относится идентификатор - к игроку, модели, интерьеру, и т.д. Поэтому вместо типов выше я определяю только два:
ID = u32; // Общий идентификатор любого объекта PID = ^u32; // Соответствующий указатель
Что касается векторов, то всё так же:
TVector = record
X, Y, Z : f32;
end;
PVector = ^TVector;
Плюс, я определил для вектора функции перемещения, поворота и масштабирования. Теперь немного о классах. Всего два общих класса. Один общий класс - GObject (аналог TObject в Дельфи) имеет защищенный, наследуемый ID, также защищенный абстрактный виртуальный метод его получения (который будет различаться у потомков) и конструктор с деструктором. Пока так:
type GObject = class protected ID : ID; Ind : Ind; public // constructor Create; // destructor Destroy; override; procedure Refresh; virtual; abstract; end;
Далее от него наследуем остальные классы. Если посмотреть на функции Char, Group, ... со всеми этими create, и remove, то кажется естественным определять их как классы. Особенно для педов - там около 5 функций создания и еще несколько уничтожения, то же самое для разных объектов - можно сразу делать перегрузку функций.
type TPlayer = class(GObject) public Name : String; Char : ID; Group : ID; MaxArmorr : u32; constructor Create; overload; constructor Create(NID : ID; x: f32; y: f32; z: f32); overload; procedure AddScore(score: i32); ... function IsDead: b8; function IsFreeAimingAtChar(ped: Ped): b8; function IsFreeForAmbientTask: b8; function IsPlaying: b8; function IsPressingHorn: b8; ... end;
В первую очередь появились поля - ID, наследуемый от GObject, плюс Name, Char, Group, MaxArmorr. Сразу по созданию экземпляра класса эти поля заполняются. Все остальные функции стали методами, укоротились в названии (понятно, что относятся к плееру), и больше не надо указывать ID, потому что он прописывается при создании. Есть функции, которые вообще носят вспомогательную роль, например ковертация индекса и ID, их можно вообще спрятать. А вот примерный конструктор:
constructor TPlayer.Create; begin ID := GetPlayerId; Name := GetPlayerName(ID); GetPlayerChar(ID, Char); GetPlayerGroup(ID, Group); GetPlayerMaxArmour(ID, MaxArmour); end;
Здесь функции уже непосредственно нативные, но они скрыты и не должны быть доступны, только если специально подключить к скрипту модуль Native.
Другой общий класс - TGame - определяет работу с опциями и свойствами игры.
TObject TPlayer TPed TGroup Tvehicles TGarages TInteriore TBlip TPickups TWorld Tobj Tmodels TGame TText TTexture TStats TPad TSound TMisc
Функции General в класс лучше не объединять.
Итого 2 общих класса = 11 + 6 классов.
Сообщение отредактировал JNikc: 21 June 2009 - 19:52
#107
Отправлено 21 June 2009 - 20:18
Прикрепленные файлы
#108
Отправлено 21 June 2009 - 21:18
#109
Отправлено 22 June 2009 - 00:10
#110
Отправлено 22 June 2009 - 08:11
Сообщение отредактировал Вадим Буренков: 22 June 2009 - 08:22
#111
Отправлено 22 June 2009 - 08:35
Сообщение отредактировал JNikc: 22 June 2009 - 08:37
#112
Отправлено 22 June 2009 - 08:54
Проблема в том, что раньше (GTASA и SannyBuilder) я пользовался первым способом, а тут никакого SCO нет, ведь скрипты пишутся в чистом .ext на Delphi, а подбирать такое количество значений вручную можно вечно и безрезультатно.либо декомпилировать sco и смотреть КАК используются функции по контектсу, и делать выводы. Либо ставить разные параметры и смотреть на результаты в игре.
А разве уже есть программы для редактирования игровых скриптов gta4 в SCO?
А как с помошью Alice SDK вывести на экран коогдинаты игрока. Получить я их смог, а выводить не умею(пробовал Print'ом и не получается).
Сообщение отредактировал Вадим Буренков: 22 June 2009 - 11:19
#113
Отправлено 22 June 2009 - 12:36
#114
Отправлено 22 June 2009 - 12:44
Все мысли, в общем-то правильные, вот только они получаются слишком оторванные от реальности. Посмотри, как в GTA вообще и в IV в частности устроена система объектов. Много станет понятнее.
(для меня, при взкляде со стороны игровых объектов, многие вещи звучат просто дико)
Что касается размера аргументов - все типы виртуальной машины кратны 32 битам.
В описании нативных функций есть несколько неточностей, когда параметром передается не набор отдельных значений, а целые структуры.
От какого номера?Там ещё есть хитрая зависимость хэша натива от её номера.
Сообщение отредактировал listener: 22 June 2009 - 13:06
#115
Отправлено 22 June 2009 - 15:52
Посмотри, как в GTA вообще и в IV в частности устроена система объектов. Много станет понятнее.
Я действительно не имею никакого представления об этом. Надо видимо пройтись по Вики...
А то, что выглядит дико, это как? Я конечно в том файле неправильно прописал конструкторы, но в остальном - ещё почти ничего нет. Я просто подумал паковать шаблоны, которые используются при скриптинге (делай раз, делай два, ...) в методы, ну и воспринимать объекты игры как ООП экземпляры. Или это вообще не пройдёт?????
вот только они получаются слишком оторванные от реальности
Это всего лишь "размышления на тему". Однако - работает. Правда я не знаю что лучше - писать как обычно или на классах. Вот пример spawn в классах:
program Spw;
uses GameClasses;
procedure Spawn; ctdcall;
begin
Game := TGame.Create;
Playa := TPlayer.Create;
if Game.KeyPressed('K') then begin
Car := TVehicle.Create(Playa.X + 2.0, Playa.Y, Playa.Z);
Game.Wait(100);
end;
// Делаем ещё что-то
Car.Free;
Playa.Free;
Game.Free;
end;
exports Spawn;
От какого номера?
От номера в списке NativesList.txt. Я имел в виду hash = Hasher.Hash(item); Эта функция показалась мне хитрой)) - т.е. почему именно так? Ответ видимо в exe...
#116
Отправлено 22 June 2009 - 17:51
Эх, если бы было все так просто... В wiki есть очень мало. В теме на sb-шном форуме есть несколько больше, чем в wiki и на gtaf вместе взятых. Плюс к этому, я выкладывал некоторое количество отреверсенных исходников - по ним должно быть слегка понятно, что-же происходит в мире системных объектов.Посмотри, как в GTA вообще и в IV в частности устроена система объектов. Много станет понятнее.
Я действительно не имею никакого представления об этом. Надо видимо пройтись по Вики...
Пройдет, конечно. Вот только пользоваться этим за рамками "шаблонов скриптинга" будет крайне неудобно.А то, что выглядит дико, это как? Я конечно в том файле неправильно прописал конструкторы, но в остальном - ещё почти ничего нет. Я просто подумал паковать шаблоны, которые используются при скриптинге (делай раз, делай два, ...) в методы, ну и воспринимать объекты игры как ООП экземпляры. Или это вообще не пройдёт?????
Вообще, игровые объекты GTA - тема для очень большого отдельного рассказа.
Несколько фактов.
Есть объекты, которые можно условно назвать "статическими" и "динамическими". Статические объекты, создаются при инициализации игры. Это гаражи, парковки, пикапы, модели и т.д. Да, некоторые из них можно добавлять из скрипта, но это именно добавление - убрать уже созданный гараж - нетривиальная задача. Эти объекты собираются в массив и обращение к ним производится по индексу в массиве.
"Динамические" объекты постоянно создаются и разрушаются. Они собраны в пулы, и обращения к ним производтся по хэндлу, в котором кодируется индекс в пуле и номер поколения объекта.
Плюс к вышеперечисленному, есть уникальные объекты (CWeather, CClock, CPopulation и т.д.), которые существуют в единственном экземпляре и которые в opcode/native не передаются в явном виде.
Как следствие, мы получаем, что возможность сделать в скрипте объект и методы объекта не предусматривается, поэтому о каком-то единообразном способе описания объектов можно забыть.
Уходя чуточку в сторону, RAGE VM используется не только в GTA, но и в других играх. А объекты в них совсем другие (поискать список natives MC:LA ?). Т.е., если закладываться на GTA-шную структуру объектов и поддерживать их на уровне транслятора - то этот транслятор нельзя будет использовать в MC:LA, Red Dead Redemption и остальном (Mafia2 ?)
Еще немного о структуре объектов.
CPlayer и CPlayerPed - это концептуально разные классы. Первый содержит набор структур, которые существуют только для игрока (CWanted, деньги, небольшой кусочек статистики (вся статистика находится в CStats) и т.д.) Второй - это сабкласс CPed, у которого заоверрайдены методы управления и заблокирована часть AI.
CGame вообще имеет три метода инициализации, три метода завершения и метод process. Т.е., никаких методов и полей, интересных с точки зрения скрипта, у него нет. (Wait - метод CRunningScript/rage::scrThread).
CVehicle в чистом виде, никогда не используется. Используется один из его сабклассов. И, если CHeli или CPlane унаследован от CAutomobile, то CTrain или CBike - нет. Пока используются абстрактные хэндлы, это можно игнорировать (тип хэндла общий для пула, а пул? для всех потомков CVehicle, используется один), как только начинается описание классов, либо нужно копировать иерархию, лито переносить в CCar методы, которые гарантированно не применимы к произвольному транспортному средству, например, getNextCarriage).
И такого очень много. Плюс к этому, есть такое поле непаханное, как AI (по которому накопано очень мало). Плюс звук. Плюс модели (по которым постоянно задают кучу вопросов). Все это нужно изучать, систематизировать и документировать - а толпы желающих этим заняться, я что-то не наблюдаю...
От какого номера?
Хм. Это в где такой?От номера в списке NativesList.txt. Я имел в виду hash = Hasher.Hash(item); Эта функция показалась мне хитрой)) - т.е. почему именно так? Ответ видимо в exe...
Вообще, в скрипте для вызова native используется хэш от имени. Если быть совсем точным - Jenkins One-at-a-time hash.
Имена были взяты из функций, регистрирующих обработчики для native.
#117
Отправлено 22 June 2009 - 18:13
//создаем человека CreateChar(4, Model, x, y ,z, @Actor, true); //даем оружие GiveWeaponToChar(Actor,WEAPON_SHOTGUN, 100, true);Данный код не работает, поскольку человек создается командой CreateChar определенное время, а команда GiveWeaponToChar наступает до его создания
Вот рабочий пример:
//создаем человека CreateChar(4, Model, x, y ,z, @Actor, true); //если Char не создан ждем while not DoesCharExist(Actor) do wait(0); //как Char создался код идет дальше. GiveWeaponToChar(Actor,WEAPON_SHOTGUN, 100, true);
Также разобрал команду
TaskShootAtChar(Char1, Char2 : Ped; TimeMaybe : u32; UnkI : i32);
Char1-кто стреляет
Char2-в кого стреляют
TimeMaybe-время
UnkI- мне известны значения: 1 - просто навести оружие на Char2 но не стрелять; 5,4(возможно 3 и 2) - стрелять
Есть предположение что 2,3,4,5 это часть тела в которую стрелять.
Сообщение отредактировал Вадим Буренков: 22 June 2009 - 19:01
#118
Отправлено 22 June 2009 - 20:30
Бедная hash = Hasher.Hash(item) : это из исходников Aru (RageLib/Common/Hasher.cs), там есть как бы бетовый декомпилятор sco и я до него дорвался. Кстати есть там же и ресурсы (в виде исходников) по моделям и аудио..
"Отреверсенных"?? Вам что удалось откатить ассамблер обратно к классам и объектам которые могли использовать в R* разрабы, и востановить их иерархию? (Вот было бы шикарно если бы они к каждой игре выпускали обширный мануал).
Статические объекты - добрался до гаражаей, моделей и т.д. для них действительно не ввести конструктор/деструктор, нет смысла.
CPlayer и CPlayerPed - это концептуально разные классы.
Но у них есть много общих свойств, почему нельзя сделать их потомками абстрактного класса?
Да : я описываю классы скорее не с точки зрения ресурсов игры (за незнанием) а с точки зрения пользователя игры.
если создаешь какой либо игровой объект (машину, человека и.т.д), то нужно останавливать код до тех пор пока она не создастся
Это общее правило для всех версий, в SB тоже нужно было ожидание делать. Уже немало скриптовых модов (в т.ч. gta-real.com) и под луа немало интересных, поэтому советую сразу учится на примерах, да и просто попробывать неплохо.
Так, о TaskShootAtChar я думал как о ->CTask. Теперь это не имеет смысла, можно асоциировать методы Task c CMan(<-CPed, <-CPlayer)
Есть предположение что 2,3,4,5 это часть тела в которую стрелять.
Видимо так оно и есть!
Сообщение отредактировал JNikc: 22 June 2009 - 20:33
#119
Отправлено 23 June 2009 - 08:13
В SB я не делал ожидания и у меня все работало. И я не видел ни одного скрипта в SB где проверялось существование обьекта командой Exsist после создания . Эта команда нужна была только когда ты берешь например случайную машину из игры в раюиусе x метров от игрока , и нужно проверить существует ли такая машина.Это общее правило для всех версий, в SB тоже нужно было ожидание делать.
В основном все моды по изменению погоды и времени, камеры, прицепления к обьектам и.т.д. Ничего интересного не нашел. Правдо был мод киллера(типа миссий), но он упакован в ASI и я не знаю как достать исходный код.Уже немало скриптовых модов (в т.ч. gta-real.com) и под луа немало интересных
Кто нибудь зеает как использовать Group команды?Вот код:
//создаб группу CreateGroup(false,@MyGroup,true); while not DoesGroupExist(MyGroup) do wait(0); //находим координаты GetOffsetFromCharInWorldCoords(PlayerChar, 0, 15, 0, @tx, @ty, @tz); //создаем Char'а Actor.ActorCreate(MODEL_IG_BRUCIE,tx,ty,tz,Actors[1]); //дальше нужно добавить его в группу, но ничего не происходит SetGroupMember(MyGroup,Actors[1]);Я также эксперементировал с коммандами
SetGroupFormation
SetGroupFormationSpacing
SetGroupSeparationRange, но они не дают результата.
Если же добавлять Char'а в группу игрока, то все работает:
GetPlayerGroup(PlayerID, @MyGroup); SetGroupMember(MyGroup,Actors[1]);Помогите, очень нужно.Кстати, может знает кто где найти моды на Alice SDK с открытым кодом на Delphi?
Сообщение отредактировал Вадим Буренков: 23 June 2009 - 09:50
#120
Отправлено 24 June 2009 - 12:48
Количество пользователей, читающих эту тему: 2
0 пользователей, 2 гостей, 0 анонимных















