Files
RAGECOOP-V/Client/Scripts/Util/WeaponUtil.cs
sardelka9515 2828b9b74f Clean up
2022-10-23 19:02:39 +08:00

378 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using GTA;
using GTA.Math;
using GTA.Native;
using Newtonsoft.Json;
using RageCoop.Core;
using Console = GTA.Console;
namespace RageCoop.Client
{
#region DUMP
internal class VehicleInfo
{
public VehicleBone[] Bones;
public uint Hash;
public string Name;
public string[] Weapons;
}
internal class VehicleBone
{
public uint BoneID;
public uint BoneIndex;
public string BoneName;
}
internal class WeaponBones
{
public VehicleBone[] Bones;
public string Name;
}
internal class VehicleWeaponInfo
{
public uint Hash;
public string Name;
public Dictionary<uint, WeaponBones> Weapons = new Dictionary<uint, WeaponBones>();
public static void Dump(string input, string output)
{
Console.Info("Generating " + output);
if (!File.Exists(input))
{
Console.Info("Downloading");
HttpHelper.DownloadFile(
"https://raw.githubusercontent.com/DurtyFree/gta-v-data-dumps/master/vehicles.json", input);
}
Console.Info("Deserialising");
var infos = JsonConvert.DeserializeObject<VehicleInfo[]>(File.ReadAllText(input));
Console.Info("Serialising");
File.WriteAllText(output,
JsonConvert.SerializeObject(
infos.Select(x => FromVehicle(x)).Where(x => x != null),
Formatting.Indented));
}
public static VehicleWeaponInfo FromVehicle(VehicleInfo info)
{
if (info.Weapons.Length == 0) return null;
var result = new VehicleWeaponInfo { Hash = info.Hash, Name = info.Name };
for (var i = 0; i < info.Weapons.Length; i++)
result.Weapons.Add((uint)Game.GenerateHash(info.Weapons[i])
, new WeaponBones
{
Name = info.Weapons[i],
Bones = info.Bones.Where(x =>
x.BoneName.StartsWith($"weapon_{i + 1}") && !x.BoneName.EndsWith("rot")).ToArray()
});
return result;
}
}
internal class WeaponInfo
{
public uint Hash;
public string Name;
}
[StructLayout(LayoutKind.Explicit, Size = 312)]
public struct DlcWeaponData
{
}
internal class WeaponFix
{
public Dictionary<uint, string> Bullet = new Dictionary<uint, string>();
public Dictionary<uint, string> Lazer = new Dictionary<uint, string>();
}
#endregion
internal static class WeaponUtil
{
public const string VehicleWeaponLocation = @"RageCoop\Data\VehicleWeapons.json";
public const string WeaponFixLocation = @"RageCoop\Data\WeaponFixes.json";
public static Dictionary<uint, VehicleWeaponInfo> VehicleWeapons = new Dictionary<uint, VehicleWeaponInfo>();
public static WeaponFix WeaponFix;
public static readonly HashSet<uint> ExplosiveBullets = new HashSet<uint>
{
(uint)VehicleWeaponHash.PlayerLazer,
(uint)WeaponHash.Railgun,
1638077257
};
public static readonly HashSet<WeaponHash> ProjectileWeapons = new HashSet<WeaponHash>
{
WeaponHash.HomingLauncher,
WeaponHash.RPG,
WeaponHash.Firework,
WeaponHash.UpNAtomizer,
WeaponHash.GrenadeLauncher,
WeaponHash.GrenadeLauncherSmoke,
WeaponHash.CompactGrenadeLauncher,
WeaponHash.FlareGun
};
public static readonly HashSet<VehicleWeaponHash> VehicleProjectileWeapons = new HashSet<VehicleWeaponHash>
{
VehicleWeaponHash.PlaneRocket,
VehicleWeaponHash.SpaceRocket,
VehicleWeaponHash.Tank,
(VehicleWeaponHash)3565779982, // STROMBERG missiles
(VehicleWeaponHash)3169388763 // SCRAMJET missiles
};
static WeaponUtil()
{
if (!File.Exists(VehicleWeaponLocation))
{
Directory.CreateDirectory(@"RageCoop\Data\tmp");
var input = @"RageCoop\Data\tmp\vehicles.json";
VehicleWeaponInfo.Dump(input, VehicleWeaponLocation);
}
// Parse and load to memory
foreach (var w in JsonConvert.DeserializeObject<VehicleWeaponInfo[]>(
File.ReadAllText(VehicleWeaponLocation))) VehicleWeapons.Add(w.Hash, w);
WeaponFix = JsonConvert.DeserializeObject<WeaponFix>(File.ReadAllText(WeaponFixLocation));
}
public static void DumpWeaponFix(string path = WeaponFixLocation)
{
var P = Game.Player.Character;
var pos = P.Position + Vector3.WorldUp * 3;
var types = new HashSet<int> { 3 };
P.IsInvincible = true;
var fix = new WeaponFix();
foreach (VehicleWeaponHash v in Enum.GetValues(typeof(VehicleWeaponHash)))
{
Console.Info("Testing: " + v);
if (types.Contains(v.GetWeaponDamageType()))
{
var asset = new WeaponAsset((int)v);
asset.Request(1000);
World.ShootBullet(pos, pos + Vector3.WorldUp, P, asset, 0, 1000);
if (!Function.Call<bool>(Hash.IS_BULLET_IN_AREA, pos.X, pos.Y, pos.Z, 10f, true) &&
!Function.Call<bool>(Hash.IS_PROJECTILE_IN_AREA, pos.X - 10, pos.Y - 10, pos.Z - 10, pos.X + 10,
pos.Y + 10, pos.Z + 10, true))
fix.Bullet.Add((uint)v, $"{nameof(VehicleWeaponHash)}.{v}");
foreach (var p in World.GetAllProjectiles()) p.Delete();
Script.Wait(50);
}
}
foreach (WeaponHash w in Enum.GetValues(typeof(WeaponHash)))
if (types.Contains(w.GetWeaponDamageType()))
{
Console.Info("Testing: " + w);
var asset = new WeaponAsset((int)w);
asset.Request(1000);
World.ShootBullet(pos, pos + Vector3.WorldUp, P, asset, 0, 1000);
if (!Function.Call<bool>(Hash.IS_BULLET_IN_AREA, pos.X, pos.Y, pos.Z, 10f, true) &&
!Function.Call<bool>(Hash.IS_PROJECTILE_IN_AREA, pos.X - 10, pos.Y - 10, pos.Z - 10, pos.X + 10,
pos.Y + 10, pos.Z + 10, true))
fix.Bullet.Add((uint)w, $"{nameof(WeaponHash)}.{w}");
foreach (var p in World.GetAllProjectiles()) p.Delete();
Script.Wait(50);
}
AddLazer(VehicleWeaponHash.PlayerSavage);
AddLazer(VehicleWeaponHash.StrikeforceCannon);
void AddLazer(dynamic hash)
{
fix.Lazer.Add((uint)hash, $"{hash.GetType().Name}.{hash.ToString()}");
}
File.WriteAllText(path, JsonConvert.SerializeObject(fix, Formatting.Indented));
P.IsInvincible = false;
}
public static void DumpWeaponHashes(string path = VehicleWeaponLocation)
{
var hashes = new Dictionary<uint, string>();
foreach (var wep in JsonConvert.DeserializeObject<WeaponInfo[]>(
HttpHelper.DownloadString(
"https://raw.githubusercontent.com/DurtyFree/gta-v-data-dumps/master/weapons.json")))
{
if (!wep.Name.StartsWith("WEAPON")) continue;
hashes.Add(wep.Hash, wep.Name);
}
var output = "public enum WeaponHash : uint\r\n{";
var lines = new List<string>();
foreach (var hash in hashes)
lines.Add($"{CoreUtils.FormatToSharpStyle(hash.Value, 7)} = {hash.Key.ToHex()}");
lines.Sort();
foreach (var l in lines) output += $"\r\n\t{l},";
output += "\r\n}";
File.WriteAllText(path, output);
}
public static void DumpVehicleWeaponHashes(string path = @"RageCoop\Data\VehicleWeaponHash.cs")
{
var hashes = new Dictionary<uint, string>();
foreach (var veh in VehicleWeapons.Values)
foreach (var hash in veh.Weapons)
if (!hashes.ContainsKey(hash.Key))
hashes.Add(hash.Key, hash.Value.Name);
var output = "public enum VehicleWeaponHash : uint\r\n{\r\n\tInvalid = 0xFFFFFFFF,";
var lines = new List<string>();
foreach (var hash in hashes) lines.Add($"{CoreUtils.FormatToSharpStyle(hash.Value)} = {hash.Key.ToHex()}");
lines.Sort();
foreach (var l in lines) output += $"\r\n\t{l},";
output += "\r\n}";
File.WriteAllText(path, output);
}
public static uint GetWeaponFix(uint hash)
{
if (WeaponFix.Bullet.TryGetValue(hash, out var _)) return (uint)VehicleWeaponHash.SubcarMg;
if (WeaponFix.Lazer.TryGetValue(hash, out var _)) return (uint)VehicleWeaponHash.PlayerLazer;
return hash;
}
public static Dictionary<uint, bool> GetWeaponComponents(this Weapon weapon)
{
Dictionary<uint, bool> result = null;
if (weapon.Components.Count > 0)
{
result = new Dictionary<uint, bool>();
foreach (var comp in weapon.Components) result.Add((uint)comp.ComponentHash, comp.Active);
}
return result;
}
public static Vector3 GetMuzzlePosition(this Ped p)
{
if (p.IsOnTurretSeat()) return p.CurrentVehicle.GetMuzzleBone(p.VehicleWeapon).Position;
var wb = p.Weapons?.CurrentWeaponObject?.Bones["gun_muzzle"];
if (wb?.IsValid == true) return wb.Position;
return p.Bones[Bone.SkelRightHand].Position;
}
public static float GetWeaponDamage(this Ped P, uint hash)
{
var comp = P.Weapons.Current.Components.GetSuppressorComponent();
return Function.Call<float>(Hash.GET_WEAPON_DAMAGE, hash,
comp.Active ? comp.ComponentHash : WeaponComponentHash.Invalid);
}
public static int GetMuzzleIndex(this Vehicle v, VehicleWeaponHash hash)
{
if (VehicleWeapons.TryGetValue((uint)v.Model.Hash, out var veh) &&
veh.Weapons.TryGetValue((uint)hash, out var wp))
return (int)wp.Bones[CoreUtils.RandInt(0, wp.Bones.Length)].BoneIndex;
return -1;
}
public static EntityBone GetMuzzleBone(this Vehicle v, VehicleWeaponHash hash)
{
if ((uint)hash == 1422046295) hash = VehicleWeaponHash.WaterCannon;
var i = v.GetMuzzleIndex(hash);
if (i == -1) return null;
return v.Bones[i];
}
public static bool IsUsingProjectileWeapon(this Ped p)
{
var vp = p.VehicleWeapon;
var type = Function.Call<int>(Hash.GET_WEAPON_DAMAGE_TYPE, vp);
if (vp != VehicleWeaponHash.Invalid)
return type == 3
? false
: VehicleProjectileWeapons.Contains(vp) || (type == 5 && !ExplosiveBullets.Contains((uint)vp));
var w = p.Weapons.Current;
return w.Group == WeaponGroup.Thrown || ProjectileWeapons.Contains(w.Hash);
}
public static int GetWeaponDamageType<T>(this T hash) where T : Enum
{
return Function.Call<int>(Hash.GET_WEAPON_DAMAGE_TYPE, hash);
}
public static string GetFlashFX(this WeaponHash w, bool veh)
{
if (veh)
switch ((VehicleWeaponHash)w)
{
case VehicleWeaponHash.Tank:
return "muz_tank";
default: return "muz_buzzard";
}
switch (w.GetWeaponGroup())
{
case WeaponGroup.SMG:
return "muz_smg";
case WeaponGroup.Shotgun:
return "muz_smg";
case WeaponGroup.AssaultRifle:
return "muz_assault_rifle";
case WeaponGroup.Pistol:
return "muz_pistol";
case WeaponGroup.Stungun:
return "muz_stungun";
case WeaponGroup.Heavy:
switch (w)
{
case WeaponHash.Minigun:
return "muz_minigun";
case WeaponHash.RPG:
return "muz_rpg";
default:
return "muz_minigun";
}
case WeaponGroup.Sniper:
return "muz_alternate_star";
case WeaponGroup.PetrolCan:
return "weap_petrol_can";
case WeaponGroup.FireExtinguisher:
return "weap_extinguisher";
default:
return "muz_assault_rifle";
}
}
public static WeaponGroup GetWeaponGroup(this WeaponHash hash)
{
return Function.Call<WeaponGroup>(Hash.GET_WEAPONTYPE_GROUP, hash);
}
}
/*
class WeaponInfo
{
public string Name;
public string MuzzleFx;
}
public class AimingInfo
{
public string Name;
public float HeadingLimit;
public float SweepPitchMin;
public float SweepPitchMax;
}
*/
}