# 【GTA5】スクリプティングのためのメモ【MOD】

# はじめに

今回は Script Hook V .NET でスクリプトを書くにあたって、ためになるであろうサイトのリンクやクラスの簡易的な説明を残しておきたいと思います。

# 基本のコード

まずは、スクリプトを書くにあたって、絶対に覚えておくべきことです。
以下のコードを見てください。

using System;
using System.Windows.Forms;
using GTA;

namespace aridai
{
    public class MyScript : Script
    {
        public MyScript()
        {
            Tick += OnTick;
            KeyDown += OnKeyDown;
        }

        private void OnTick(object sender, EventArgs e)
        {

        }

        private void OnKeyDown(object sender, KeyEventArgs e)
        {

        }
    }
}

Script Hook V .NETscripts フォルダ内にあるDLLの中の GTA.Script 抽象クラスを派生したクラスを見つけて実行しようとします。
ですので、必ず GTA.Script クラスを継承したクラスを作るようにしてください。

また、このクラスはイベントを持っており、そのイベントにイベントハンドラを登録し、そのイベントハンドラ内にスクリプトを書いていくのが基本となります。

この中で最も重要なのは Tick イベントでしょう。
これは大体毎フレーム呼ばれるイベントで、このイベントのハンドラに更新処理を書いていきます。

また、KeyDown イベントというものもあります。
これはキーボードのキーが入力されたときに発生します。
イベント引数に System.Windows.Forms.KeyEventArgs を取るので、扱い方はフォームアプリケーションと同じです。

他にも Aborted イベントや OnKeyUp イベントがありますが、ここでは割愛します。

# クラス紹介

さて、ここで簡単に主要となるクラスを見ていきたいと思います。

# Entityクラス

GTAに出てくるオブジェクトはこの Entity 抽象クラスを実装しています。
このクラスは座標情報や加速度、対爆や無敵属性などの属性情報を持っています。

# Pedクラス

ゲーム中に出てくる人間、また、動物、ソンビなどのキャラクタはこの Ped クラスで表されます。
Entity クラスが持つ情報に加え、体力やアーマーの情報や所持している武器やお金、実行中の動作 (タスク) なども持っています。

# Vehicleクラス

自動車やバイク、ヘリなどの乗り物はこの Vehicle クラスで表されます。
改造パーツや耐久値、乗車中のPedの情報や、洗車したり、ドアを破壊するようなメソッドも持っています。

# Propクラス

落ちているアイテムなどは Prop クラスで表されます。
しかし、あまり使う機会はなさそうです。

# Gameクラス

入力情報やディスプレイ情報、バージョン情報に加え、現在操作中のプレーヤなどはこの Game 静的クラスが持っています。

# Game.IsControlPressedメソッド

ユーザーの入力をゲーム中の動作レベルで取得することができます。
例えば、ジャンプボタンが押されているかどうかは以下のようなコードで判定することができます。

bool isJumpButtonPressed =
    Game.IsControlPressed(0, Control.Jump);

GTA.Script.KeyDown イベントを使うことで キーボードレベルでの入力 を取得することができますが、ゲームパッドを使って操作している場合はそれでは不便です。
そのようなときにこのメソッドを使うと良いでしょう。

# Game.Playerプロパティ

このプロパティは現在操作中のプレーヤを取得することができます。
Player クラスには手配度情報など、操作プレーヤならではのプロパティやメソッドが用意されています。
また、Game.Player.Character プロパティには Ped 型のデータが入っているので、座標情報や加速度情報などの普通のPedの持つデータを扱う場合はこのプロパティ使います。

# Worldクラス

このクラスは静的クラスで、スポーン処理や座標関連、存在するEntityの一覧の取得などのワールドに関する処理を行います。

# GetNearbyEntitiesメソッド

これは指定半径内にあるEntityの一覧を取得する処理です。
Entity型の配列を戻り値として返します。

using System;
using System.Windows.Forms;
using GTA;
using GTA.Math;

namespace aridai
{
    public class MyScript : Script
    {
        public MyScript()
        {
            KeyDown += OnKeyDown;
        }

        private void OnKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.F8)
            {
                Vector3 position = Game.Player.Character.Position;
                float radius = 100.0f;
                Entity[] entities = World.GetNearbyEntities(position, radius);

                foreach (Entity entity in entities)
                {
                    entity.Position += new Vector3(0, 0, 20);
                }
            }
        }
    }
}

他にも、PedやVehicleだけに限定した GetNearbyPeds メソッドや GetNearbyVehicles メソッドだったり、半径を指定しない GetAllEntities メソッドなどもあります。

# CreateVehicleメソッド

乗り物をワールド上にスポーンさせるときに使います。
例えば、カリン・クルマをスポーンさせたいときはこのように書きます。

Model model = new Model(GTA.Native.VehicleHash.Kuruma);
Vector3 position = Game.Player.Character.Position + new Vector3(1, 0, 0);
Vehicle kuruma = World.CreateVehicle(model, position);

このメソッドは Model 構造体を引数に取りますが、コンストラクタで GTA.Native.VehicleHash 列挙体を渡して生成しています。
なんとなくで分かるとは思いますが、モデルデータの列挙値を指定しているだけです。

# Raycastメソッド

Unityゲームエンジンなどで使ったことがある人はいると思います。
指定地点から線分を伸ばして衝突したオブジェクトを取得するのに使います。

例えば、メモ前を横切ったPedをぶっ殺すという動作をさせるには以下のように書きます。

using System;
using GTA;
using GTA.Math;

namespace aridai
{
    public class MyScript : Script
    {
        public MyScript()
        {
            Tick += OnTick;
        }

        private void OnTick(object sender, EventArgs e)
        {
            Vector3 source = GameplayCamera.Position;
            Vector3 direction = GameplayCamera.Direction;
            float maxDistance = 100.0f;
            Entity ignore = Game.Player.Character;
            RaycastResult result = World.Raycast(source, direction, maxDistance, IntersectOptions.Everything, ignore);

            if (result.DitHitEntity)
            {
                Entity target = result.HitEntity;
                
                if (target is Ped ped)
                {
                    ped.Kill();
                }
            }
        }
    }
}

GameplayCamera という静的クラスが出てきていますが、これは現在描画しているカメラの情報を持っています。
ここでは座標と方向ベクトルを利用しています。

# ネイティブ関数呼び出し

現時点で、Script Hook V .NET で正式にラップされていない関数があります。
それらは GTA.Native.Function.Call メソッドを使うことで、呼び出すことができます。

例えば、Pedをラグドール化するという処理は Script Hook V .NET ではラップされていません。
そのため、このような呼び出し方をする必要があります。

private void SetPedToRagdoll(Ped ped)
{
    //  http://www.dev-c.com/nativedb/func/info/ae99fb955581844a
    Function.Call(Hash.SET_PED_TO_RAGDOLL, new InputArgument[] { ped, 0, 0, 0, true, true, true });
}

GTA.Native.Function.Call メソッドの第一引数に GTA.Native.Hash 列挙体を、それ以降に引数リストを渡していく感じです。
このネイティブ関数とその引数情報は GTA V Native Database で見つけることができると思います。
ところどころ情報が乏しかったり、詳細が不明な引数も合ったりするようですが、これは試行錯誤しかないです。

# サイトリンク集

最後に役に立つであろうページを紹介します。

# 最後に

情報量が極端に少ない、というかドキュメントというものが存在しないので、メソッド名などから動作を予想して書いていくしかありません。
ですので、GitHubのコード検索やVisual Studioのオブジェクトブラウザなどを上手く利用することが大事だと思います。

私も極力情報を書き残していくので、誰かのためになればいいなと思っています。
エンジョイ!