Improved weapon and turret sync

This commit is contained in:
sardelka9515
2022-10-19 19:07:46 +08:00
parent a50ae062d8
commit 69419d41e0
23 changed files with 541 additions and 673 deletions

4
.editorconfig Normal file
View File

@ -0,0 +1,4 @@
[*.cs]
# CS0649: Field 'VehicleInfo.Name' is never assigned to, and will always have its default value null
dotnet_diagnostic.CS0649.severity = silent

View File

@ -0,0 +1,27 @@
using RageCoop.Core;
using Newtonsoft.Json;
using System.Data.HashFunction.Jenkins;
using System;
namespace RageCoop.Client.DataDumper
{
public static class Program
{
static UInt32 Hash(string key)
{
int i = 0;
uint hash = 0;
while (i != key.Length)
{
hash += key[i++];
hash += hash << 10;
hash ^= hash >> 6;
}
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;
return hash;
}
}
}

View File

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<OutputType>exe</OutputType>
<OutDir>..\..\bin\Debug\Client.DataDumper</OutDir>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.Data.HashFunction.Jenkins" Version="2.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Core\RageCoop.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -189,7 +189,11 @@ namespace RageCoop.Client.Loader
{
CurrentDomain.DoKeyEvent(keys, status);
}
public override object InitializeLifetimeService()
{
// Return null to avoid lifetime restriction on the marshaled object.
return null;
}
public void Dispose()
{
lock (this)

View File

@ -1,5 +1,6 @@
using GTA;
using GTA.Math;
using GTA.Native;
using System;
using System.Drawing;
using System.Threading;
@ -11,174 +12,80 @@ namespace RageCoop.Client
internal class DevTool : Script
{
public static Vehicle ToMark;
public static bool UseSecondary = false;
public static int Current = 0;
public static int Secondary = 0;
public static MuzzleDir Direction = MuzzleDir.Forward;
public static Script Instance;
public DevTool()
{
Util.StartUpCheck();
Instance = this;
Tick += OnTick;
KeyDown += OnKeyDown;
Pause();
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
if (ToMark == null || (!ToMark.Exists())) { return; }
if (DevToolMenu.Menu.SelectedItem == DevToolMenu.boneIndexItem)
{
switch (e.KeyCode)
{
case Keys.Right:
Current++;
break;
case Keys.Left:
Current--;
break;
}
}
else if (DevToolMenu.Menu.SelectedItem == DevToolMenu.secondaryBoneIndexItem)
{
switch (e.KeyCode)
{
case Keys.Right:
Secondary++;
break;
case Keys.Left:
Secondary--;
break;
}
}
Update();
}
private static void Update()
{
if (Current > ToMark.Bones.Count - 1)
{
Current = 0;
}
else if (Current < 0)
{
Current = ToMark.Bones.Count - 1;
}
DevToolMenu.boneIndexItem.AltTitle = Current.ToString();
if (Secondary > ToMark.Bones.Count - 1)
{
Secondary = 0;
}
else if (Secondary < 0)
{
Secondary = ToMark.Bones.Count - 1;
}
DevToolMenu.secondaryBoneIndexItem.AltTitle = Secondary.ToString();
}
private void OnTick(object sender, EventArgs e)
{
if (ToMark == null || !ToMark.Exists()) { return; }
Update();
Draw(Current);
if (UseSecondary)
var wb = Game.Player.Character?.Weapons?.CurrentWeaponObject?.Bones["gun_muzzle"];
if (wb?.IsValid==true)
{
Draw(Secondary);
World.DrawLine(wb.Position, wb.Position + wb.RightVector, Color.Blue);
}
}
private static void Draw(int boneindex)
{
var bone = ToMark.Bones[boneindex];
World.DrawLine(bone.Position, bone.Position + 2 * bone.ForwardVector, Color.Blue);
World.DrawLine(bone.Position, bone.Position + 2 * bone.UpVector, Color.Green);
World.DrawLine(bone.Position, bone.Position + 2 * bone.RightVector, Color.Yellow);
Vector3 todraw = bone.ForwardVector;
switch ((byte)Direction)
if (ToMark == null) return;
if (WeaponUtil.VehicleWeapons.TryGetValue((uint)(int)ToMark.Model, out var info))
{
case 0:
todraw = bone.ForwardVector;
break;
case 1:
todraw = bone.RightVector;
break;
case 2:
todraw = bone.UpVector;
break;
case 3:
todraw = bone.ForwardVector * -1;
break;
case 4:
todraw = bone.RightVector * -1;
break;
case 5:
todraw = bone.UpVector * -1;
break;
}
World.DrawLine(bone.Position, bone.Position + 10 * todraw, Color.Red);
}
public static void CopyToClipboard(MuzzleDir dir)
{
if (ToMark != null)
{
string s;
if (UseSecondary)
foreach (var ws in info.Weapons)
{
if ((byte)dir < 3)
foreach (var w in ws.Value.Bones)
{
s = $@"
// {ToMark.DisplayName}
case {ToMark.Model.Hash}:
return BulletsShot%2==0 ? {Current} : {Secondary};
";
}
else
{
s = $@"
// {ToMark.DisplayName}
case {ToMark.Model.Hash}:
return BulletsShot%2==0 ? {Current} : {Secondary};
";
DrawBone(w.BoneName, ws.Value.Name);
}
}
else
{
if ((byte)dir < 3)
{
s = $@"
// {ToMark.DisplayName}
case {ToMark.Model.Hash}:
return {Current};
";
}
else
{
s = $@"
// {ToMark.DisplayName}
case {ToMark.Model.Hash}:
return {Current};
";
}
}
Thread thread = new Thread(() => Clipboard.SetText(s));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
GTA.UI.Notification.Show("Copied to clipboard, please paste it on the GitHub issue page!");
}
}
void FindAndDraw()
{
DrawBone("weapon_1a");
DrawBone("weapon_1b");
DrawBone("weapon_1c");
DrawBone("weapon_1d");
DrawBone("weapon_2a");
DrawBone("weapon_2b");
DrawBone("weapon_2c");
DrawBone("weapon_2d");
DrawBone("weapon_3a");
DrawBone("weapon_3b");
DrawBone("weapon_3c");
DrawBone("weapon_3d");
DrawBone("weapon_4a");
DrawBone("weapon_4b");
DrawBone("weapon_4c");
DrawBone("weapon_4d");
DrawBone("weapon_1e");
DrawBone("weapon_1f");
DrawBone("weapon_1g");
DrawBone("weapon_1h");
DrawBone("weapon_2e");
DrawBone("weapon_2f");
DrawBone("weapon_2g");
DrawBone("weapon_2h");
DrawBone("weapon_3e");
DrawBone("weapon_3f");
DrawBone("weapon_3g");
DrawBone("weapon_3h");
DrawBone("weapon_4e");
DrawBone("weapon_4f");
DrawBone("weapon_4g");
DrawBone("weapon_4h");
}
void DrawBone(string name, string text = null)
{
text = text ?? name;
var b = ToMark.Bones[name];
if (b.IsValid)
{
var start = b.Position;
var end = b.Position + b.ForwardVector * 5;
World.DrawLine(start, end, Color.AliceBlue);
Util.DrawTextFromCoord(end, text, 0.35f);
}
}
}
internal enum MuzzleDir : byte
{
Forward = 0,
Right = 1,
Up = 2,
Backward = 3,
Left = 4,
Down = 5,
}
}

View File

@ -1,24 +1,37 @@
using GTA;
using LemonUI.Menus;
using System;
using System.Threading.Tasks;
using System.Drawing;
using RageCoop.Client.Scripting;
using Console = GTA.Console;
using System.IO;
using Newtonsoft.Json;
using GTA.Native;
namespace RageCoop.Client
{
class AnimDic
{
public string DictionaryName;
public string[] Animations;
}
internal static class DevToolMenu
{
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "DevTool", "Help with the development")
const string AnimationsPath = @"RageCoop\Data\animDictsCompact.json";
public static NativeMenu Menu = new NativeMenu("RAGECOOP", "DevTool", "Internal testing tools")
{
UseMouse = false,
Alignment = Main.Settings.FlipMenu ? GTA.UI.Alignment.Right : GTA.UI.Alignment.Left
};
private static readonly NativeCheckboxItem enableItem = new NativeCheckboxItem("Enable");
public static readonly NativeItem dumpItem = new NativeItem("Dump vehicle weapons");
public static readonly NativeItem dumpFixItem = new NativeItem("Dump weapon fixes");
public static readonly NativeItem dumpWHashItem = new NativeItem("Dump WeaponHash.cs");
public static readonly NativeItem getAnimItem = new NativeItem("Get current animation");
public static readonly NativeItem dumpVWHashItem = new NativeItem("Dump VehicleWeaponHash.cs");
private static readonly NativeCheckboxItem enableSecondaryItem = new NativeCheckboxItem("Secondary", "Enable if this vehicle have two muzzles");
public static NativeItem boneIndexItem = new NativeItem("Current bone index");
public static NativeItem secondaryBoneIndexItem = new NativeItem("Secondary bone index");
public static NativeItem clipboardItem = new NativeItem("Copy to clipboard");
public static NativeListItem<MuzzleDir> dirItem = new NativeListItem<MuzzleDir>("Direction");
static DevToolMenu()
{
Menu.Banner.Color = Color.FromArgb(225, 0, 0, 0);
@ -26,55 +39,70 @@ namespace RageCoop.Client
enableItem.Activated += enableItem_Activated;
enableItem.Checked = false;
enableSecondaryItem.CheckboxChanged += EnableSecondaryItem_Changed;
secondaryBoneIndexItem.Enabled = false;
clipboardItem.Activated += ClipboardItem_Activated;
dirItem.ItemChanged += DirItem_ItemChanged;
foreach (var d in Enum.GetValues(typeof(MuzzleDir)))
dumpItem.Activated += DumpItem_Activated;
dumpVWHashItem.Activated += (s,e)=> WeaponUtil.DumpVehicleWeaponHashes();
dumpWHashItem.Activated += (s, e) => WeaponUtil.DumpWeaponHashes();
dumpFixItem.Activated += (s, e) => WeaponUtil.DumpWeaponFix();
getAnimItem.Activated += (s, e) =>
{
dirItem.Items.Add((MuzzleDir)d);
}
dirItem.SelectedIndex = 0;
if (File.Exists(AnimationsPath))
{
var anims = JsonConvert.DeserializeObject<AnimDic[]>(File.ReadAllText(AnimationsPath));
foreach(var anim in anims)
{
foreach(var a in anim.Animations)
{
if (Function.Call<bool>(Hash.IS_ENTITY_PLAYING_ANIM, Main.P,anim.DictionaryName,a,3))
{
Console.Info(anim.DictionaryName + " : " + a);
GTA.UI.Notification.Show(anim.DictionaryName+" : "+a);
}
}
}
}
else
{
GTA.UI.Notification.Show($"~r~{AnimationsPath} not found");
}
};
Menu.Add(enableItem);
Menu.Add(boneIndexItem);
Menu.Add(enableSecondaryItem);
Menu.Add(secondaryBoneIndexItem);
Menu.Add(dirItem);
Menu.Add(clipboardItem);
Menu.Add(dumpItem);
Menu.Add(dumpVWHashItem);
Menu.Add(dumpWHashItem);
Menu.Add(dumpFixItem);
Menu.Add(getAnimItem);
}
private static void EnableSecondaryItem_Changed(object sender, EventArgs e)
private static void DumpItem_Activated(object sender, EventArgs e)
{
if (enableSecondaryItem.Checked)
dumpItem.Enabled = false;
Directory.CreateDirectory(@"RageCoop\Data\tmp");
var input = @"RageCoop\Data\tmp\vehicles.json";
var dumpLocation = @"RageCoop\Data\VehicleWeapons.json";
try
{
DevTool.UseSecondary = true;
secondaryBoneIndexItem.Enabled = true;
VehicleWeaponInfo.Dump(input, dumpLocation);
Console.Info($"Weapon info dumped to " + dumpLocation);
}
else
catch (Exception ex)
{
DevTool.UseSecondary = false;
secondaryBoneIndexItem.Enabled = false;
Console.Error($"~r~" + ex.ToString());
}
finally
{
dumpItem.Enabled = true;
}
}
private static void DirItem_ItemChanged(object sender, ItemChangedEventArgs<MuzzleDir> e)
{
DevTool.Direction = dirItem.SelectedItem;
}
private static void ClipboardItem_Activated(object sender, EventArgs e)
{
DevTool.CopyToClipboard(dirItem.SelectedItem);
}
private static void enableItem_Activated(object sender, EventArgs e)
{
if (enableItem.Checked)
{
DevTool.Instance.Resume();
DevTool.ToMark = Game.Player.Character.CurrentVehicle;
DevTool.Instance.Resume();
}
else
{

View File

@ -42,11 +42,10 @@ namespace RageCoop.Client
}
};
private static readonly AutoResetEvent _publicKeyReceived = new AutoResetEvent(false);
private static bool _recycle;
public static void ProcessMessage(NetIncomingMessage message)
{
if (message == null) { return; }
_recycle = true;
var _recycle = true;
switch (message.MessageType)
{
case NetIncomingMessageType.StatusChanged:
@ -293,7 +292,7 @@ namespace RageCoop.Client
{
recycle = false;
// Dispatch to script thread
API.QueueAction(() => { SyncEvents.HandleEvent(packetType, msg); Peer.Recycle(msg); return true; });
API.QueueAction(() => { SyncEvents.HandleEvent(packetType, msg); return true; });
}
break;
}

View File

@ -16,7 +16,7 @@ using System.Resources;
// Version informationr(
[assembly: AssemblyVersion("1.5.6.1")]
[assembly: AssemblyFileVersion("1.5.6.1")]
[assembly: AssemblyVersion("1.5.6.98")]
[assembly: AssemblyFileVersion("1.5.6.98")]
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]

View File

@ -128,6 +128,9 @@
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\.editorconfig">
<Link>.editorconfig</Link>
</None>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>

View File

@ -175,7 +175,7 @@ namespace RageCoop.Client
return;
}
Vector3 targetPos = MainPed.Bones[Bone.IKHead].Position;
Vector3 targetPos = MainPed.Bones[Bone.IKHead].Position + Vector3.WorldUp * 0.5f;
Point toDraw = default;
if (Util.WorldToScreen(targetPos, ref toDraw))
{
@ -688,7 +688,6 @@ namespace RageCoop.Client
}
if (MainPed.IsOnTurretSeat())
{
// Function.Call(Hash.SET_VEHICLE_TURRET_SPEED_THIS_FRAME, MainPed.CurrentVehicle, 100);
Function.Call(Hash.TASK_VEHICLE_AIM_AT_COORD, MainPed.Handle, AimCoords.X, AimCoords.Y, AimCoords.Z);
}
if (MainPed.VehicleWeapon == VehicleWeaponHash.Invalid)

View File

@ -43,7 +43,7 @@ namespace RageCoop.Client
#endregion
public static void Cleanup(bool keepPlayer = true, bool keepMine = true)
{
foreach (var ped in PedsByID.Values)
foreach (var ped in PedsByID.Values.ToArray())
{
if ((keepPlayer && (ped.ID == Main.LocalPlayerID)) || (keepMine && (ped.OwnerID == Main.LocalPlayerID))) { continue; }
RemovePed(ped.ID);
@ -51,7 +51,7 @@ namespace RageCoop.Client
PedsByID.Clear();
PedsByHandle.Clear();
foreach (int id in new List<int>(VehiclesByID.Keys))
foreach (int id in VehiclesByID.Keys.ToArray())
{
if (keepMine && (VehiclesByID[id].OwnerID == Main.LocalPlayerID)) { continue; }
RemoveVehicle(id);
@ -59,7 +59,7 @@ namespace RageCoop.Client
VehiclesByID.Clear();
VehiclesByHandle.Clear();
foreach (var p in ProjectilesByID.Values)
foreach (var p in ProjectilesByID.Values.ToArray())
{
if (p.Shooter.ID != Main.LocalPlayerID && p.MainProjectile != null && p.MainProjectile.Exists())
{

View File

@ -3,6 +3,7 @@ using GTA.Math;
using Lidgren.Network;
using RageCoop.Core;
using System;
using System.Runtime.InteropServices;
namespace RageCoop.Client
{
@ -30,9 +31,7 @@ namespace RageCoop.Client
{
// Main.Logger.Trace($"bullet shot:{(WeaponHash)hash}");
var start = owner.MainPed.GetMuzzlePosition();
if (owner.MainPed.IsOnTurretSeat()) { start = owner.MainPed.Bones[Bone.SkelHead].Position; }
if (start.DistanceTo(impactPosition) > 10)
{
// Reduce latency
@ -43,17 +42,8 @@ namespace RageCoop.Client
public static void TriggerVehBulletShot(uint hash, Vehicle veh, SyncedPed owner)
{
int i;
// ANNIHL
if (veh.Model.Hash == 837858166)
{
Networking.SendVehicleBullet(hash, owner, veh.Bones[35]);
Networking.SendVehicleBullet(hash, owner, veh.Bones[36]);
Networking.SendVehicleBullet(hash, owner, veh.Bones[37]);
Networking.SendVehicleBullet(hash, owner, veh.Bones[38]);
}
else if ((i = veh.GetMuzzleIndex()) != -1)
if ((i = veh.GetMuzzleIndex(owner.MainPed.VehicleWeapon)) != -1)
{
Networking.SendVehicleBullet(hash, owner, veh.Bones[i]);
}
@ -72,8 +62,6 @@ namespace RageCoop.Client
#region HANDLE
public static ParticleEffectAsset CorePFXAsset = new ParticleEffectAsset("core");
private static WeaponAsset _weaponAsset = default;
private static uint _lastWeaponHash;
private static void HandlePedKilled(Packets.PedKilled p)
{
@ -94,60 +82,21 @@ namespace RageCoop.Client
}
private static void HandleBulletShot(Vector3 start, Vector3 end, uint weaponHash, int ownerID)
{
switch (weaponHash)
{
// Minigun, not working for some reason
case (uint)WeaponHash.Minigun:
weaponHash = 1176362416;
break;
// Valkyire, not working for some reason
case 2756787765:
weaponHash = 1176362416;
break;
// Tampa3, not working for some reason
case 3670375085:
weaponHash = 1176362416;
break;
// Ruiner2, not working for some reason
case 50118905:
weaponHash = 1176362416;
break;
// SAVAGE
case 1638077257:
weaponHash = (uint)VehicleWeaponHash.PlayerLazer;
break;
case (uint)VehicleWeaponHash.PlayerBuzzard:
weaponHash = 1176362416;
break;
}
var p = EntityPool.GetPedByID(ownerID)?.MainPed;
if (p == null) { p = Game.Player.Character; Main.Logger.Warning("Failed to find owner for bullet"); }
var damage = (int)p.GetWeaponDamage(weaponHash);
weaponHash = WeaponUtil.GetWeaponFix(weaponHash);
if (!CorePFXAsset.IsLoaded) { CorePFXAsset.Request(); }
if (_lastWeaponHash != weaponHash)
{
_weaponAsset.MarkAsNoLongerNeeded();
_weaponAsset = new WeaponAsset(weaponHash);
_lastWeaponHash = weaponHash;
}
if (!_weaponAsset.IsLoaded) { _weaponAsset.Request(); }
World.ShootBullet(start, end, p, _weaponAsset, (int)p.GetWeaponDamage(weaponHash));
var asset = new WeaponAsset(weaponHash);
if (!asset.IsLoaded) { asset.Request(); }
World.ShootBullet(start, end, p, asset, damage);
Prop w;
if (((w = p.Weapons.CurrentWeaponObject) != null) && (p.VehicleWeapon == VehicleWeaponHash.Invalid))
var turret = false;
if ((((w = p.Weapons.CurrentWeaponObject) != null) && (p.VehicleWeapon == VehicleWeaponHash.Invalid)) || (turret = p.IsOnTurretSeat()))
{
if (p.Weapons.Current.Components.GetSuppressorComponent().Active)
{
World.CreateParticleEffectNonLooped(CorePFXAsset, "muz_pistol_silencer", p.GetMuzzlePosition(), w.Rotation, 1);
}
else
{
World.CreateParticleEffectNonLooped(CorePFXAsset, WeaponUtil.GetFlashFX((WeaponHash)weaponHash), p.GetMuzzlePosition(), w.Rotation, 1);
}
World.CreateParticleEffectNonLooped(CorePFXAsset, p.Weapons.Current.Components.GetSuppressorComponent().Active ? "muz_pistol_silencer" : WeaponUtil.GetFlashFX((WeaponHash)weaponHash, turret), p.GetMuzzlePosition(), turret ? p.CurrentVehicle.GetMuzzleBone(p.VehicleWeapon).GetRotation() : w.Rotation, 1);
}
}
public static void HandleVehicleBulletShot(Packets.VehicleBulletShot p)
@ -157,8 +106,8 @@ namespace RageCoop.Client
if (v == null) { return; }
var b = v.Bones[p.Bone];
World.CreateParticleEffectNonLooped(CorePFXAsset,
WeaponUtil.GetFlashFX((WeaponHash)p.WeaponHash),
b.Position, b.ForwardVector.ToEulerRotation(v.Bones[35].UpVector), 1);
WeaponUtil.GetFlashFX((WeaponHash)p.WeaponHash, true),
b.Position, b.GetRotation(), 1);
}
public static void HandleEvent(PacketType type, NetIncomingMessage msg)
{
@ -166,8 +115,7 @@ namespace RageCoop.Client
{
case PacketType.BulletShot:
{
Packets.BulletShot p = new Packets.BulletShot();
p.Deserialize(msg);
var p = msg.GetPacket<Packets.BulletShot>();
HandleBulletShot(p.StartPosition, p.EndPosition, p.WeaponHash, p.OwnerID);
break;
}

View File

@ -335,7 +335,11 @@ namespace RageCoop.Client
{
return v.Bones[35].Position + v.Bones[35].ForwardVector * 100;
}
if (p.IsOnTurretSeat()) { return p.GetLookingCoord(); }
if (p.IsOnTurretSeat())
{
var b = p.CurrentVehicle.GetMuzzleBone(p.VehicleWeapon);
return b.Position + b.ForwardVector * 50;
}
if (weapon != null)
{
// Not very accurate, but doesn't matter
@ -459,6 +463,7 @@ namespace RageCoop.Client
public static bool IsTurretSeat(this Vehicle veh, int seat)
{
if (Function.Call<bool>(Hash.IS_TURRET_SEAT, veh, seat)) { return true; }
if (!Function.Call<bool>(Hash.DOES_VEHICLE_HAVE_WEAPONS, veh.Handle))
{
return false;

View File

@ -1,6 +1,7 @@
using GTA;
using GTA.Math;
using GTA.Native;
using LemonUI.Elements;
using Newtonsoft.Json;
using RageCoop.Core;
using System;
@ -14,6 +15,10 @@ namespace RageCoop.Client
{
internal static class Util
{
public static Vector3 GetRotation(this EntityBone b)
{
return b.ForwardVector.ToEulerRotation(b.UpVector);
}
public static void StartUpCheck()
{
if (AppDomain.CurrentDomain.GetData("RageCoop.Client.LoaderContext") == null)
@ -42,6 +47,21 @@ namespace RageCoop.Client
return new SizeF(width, 1080f);
}
}
public static void DrawTextFromCoord(Vector3 coord, string text, float scale = 0.5f, Point offset = default)
{
Point toDraw = default;
if (WorldToScreen(coord, ref toDraw))
{
toDraw.X += offset.X;
toDraw.Y += offset.Y;
new ScaledText(toDraw, text, scale, GTA.UI.Font.ChaletLondon)
{
Outline = true,
Alignment = GTA.UI.Alignment.Center,
Color = Color.White,
}.Draw();
}
}
public static bool WorldToScreen(Vector3 pos, ref Point screenPos)
{
float x, y;

View File

@ -1,22 +1,239 @@
using GTA;
using GTA.Math;
using GTA.Native;
using Newtonsoft.Json;
using RageCoop.Core;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System;
using Console = GTA.Console;
using System.Drawing;
using System.Runtime.InteropServices;
namespace RageCoop.Client
{
internal class MuzzleInfo
#region DUMP
class VehicleInfo
{
public MuzzleInfo(Vector3 pos, Vector3 forward)
{
Position = pos;
ForawardVector = forward;
}
public Vector3 Position;
public Vector3 ForawardVector;
public string Name;
public string[] Weapons;
public uint Hash;
public VehicleBone[] Bones;
}
class VehicleBone
{
public uint BoneID;
public uint BoneIndex;
public string BoneName;
}
class WeaponBones
{
public string Name;
public VehicleBone[] Bones;
}
class VehicleWeaponInfo
{
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 (int 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;
}
public uint Hash;
public string Name;
public Dictionary<uint, WeaponBones> Weapons = new Dictionary<uint, WeaponBones>();
}
class WeaponInfo
{
public string Name;
public uint Hash;
}
[StructLayout(LayoutKind.Explicit, Size = 312)]
public struct DlcWeaponData
{
}
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 static Dictionary<uint, VehicleWeaponInfo> VehicleWeapons = new Dictionary<uint, VehicleWeaponInfo>();
public static WeaponFix WeaponFix;
public const string VehicleWeaponLocation= @"RageCoop\Data\VehicleWeapons.json";
public const string WeaponFixLocation = @"RageCoop\Data\WeaponFixes.json";
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)
{
Dictionary<uint, string> 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{";
List<string> 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")
{
Dictionary<uint, string> 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,";
List<string> 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;
@ -36,334 +253,37 @@ namespace RageCoop.Client
public static Vector3 GetMuzzlePosition(this Ped p)
{
var w = p.Weapons.CurrentWeaponObject;
if (w != null)
if (p.IsOnTurretSeat())
{
var hash = p.Weapons.Current.Hash;
if (MuzzleBoneIndexes.ContainsKey(hash)) { return w.Bones[MuzzleBoneIndexes[hash]].Position; }
return w.Position;
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;
}
private static long BulletsShot = 0;
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);
/*
if (P.IsInVehicle() && (hash!=(uint)P.Weapons.Current.Hash))
{
// This is a vehicle weapon
P.VehicleWeapon=(VehicleWeaponHash)hash;
return 100;
}
switch (P.Weapons.Current.Group)
{
case WeaponGroup.Pistol: return 30;
case WeaponGroup.AssaultRifle: return 30;
case WeaponGroup.SMG: return 20;
case WeaponGroup.MG: return 40;
case WeaponGroup.Shotgun: return 30;
case WeaponGroup.Sniper: return 200;
case WeaponGroup.Heavy: return 30;
}
return 0;
*/
}
public static int GetMuzzleIndex(this Vehicle v)
public static int GetMuzzleIndex(this Vehicle v, VehicleWeaponHash hash)
{
BulletsShot++;
switch (v.Model.Hash)
if (VehicleWeapons.TryGetValue((uint)v.Model.Hash, out var veh) && veh.Weapons.TryGetValue((uint)hash, out var wp))
{
// cerberus3
case 1909700336:
return 53;
// cerberus2
case 679453769:
return 54;
// cerberus
case -801550069:
return 90;
/*
// cerberus (flame)
case -801550069:
i=BulletsShot%2==0 ? 89 : 88;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
// cerberus (passenger flame)
case -801550069:
i=BulletsShot%2==0 ? 76 : 75;
return new MuzzleInfo(v.Bones[i].Position, v.Bones[i].ForwardVector);
*/
// ISSI6
case 1239571361:
return BulletsShot % 2 == 0 ? 12 : 14;
// ISSI5
case 1537277726:
return BulletsShot % 2 == 0 ? 30 : 32;
// ISSI4
case 628003514:
return BulletsShot % 2 == 0 ? 14 : 12;
// DOMINATOR6
case -1293924613:
return BulletsShot % 2 == 0 ? 51 : 55;
// IMPALER4
case -1744505657:
return BulletsShot % 2 == 0 ? 64 : 63;
// IMPERATOR3
case -755532233:
return BulletsShot % 2 == 0 ? 86 : 88;
// SLAMVAN6
case 1742022738:
return BulletsShot % 2 == 0 ? 78 : 76;
// CHAMPION
case -915234475:
return BulletsShot % 2 == 0 ? 60 : 61;
// MONSTER4
case 840387324:
return BulletsShot % 2 == 0 ? 63 : 65;
// BRUTUS2
case -1890996696:
return 67;
// BRUISER2
case -1694081890:
return BulletsShot % 2 == 0 ? 45 : 51;
// TECHNICAL3
case 1356124575:
return 67;
// TECHNICAL2
case 1180875963:
return 54;
// TECHNICAL
case -2096818938:
return 63;
// PATRIOT3
case -670086588:
return BulletsShot % 2 == 0 ? 87 : 89;
// NIGHTSHARK
case 433954513:
return BulletsShot % 2 == 0 ? 1 : 2;
/*
// NIGHTSHARK (second)
case 433954513:
return BulletsShot%2==0 ? 3 : 4;
*/
// MENACER
case 2044532910:
return BulletsShot % 2 == 0 ? 91 : 90;
/*
// MENACER
case 2044532910:
return new MuzzleInfo(v.Bones[75].Position, v.Bones[75].ForwardVector);
// MENACER
case 2044532910:
return new MuzzleInfo(v.Bones[78].Position, v.Bones[78].ForwardVector);
*/
// CARACARA
case 1254014755:
return 83;
/*
// CARACARA
case 1254014755:
return BulletsShot%2==0 ? 93 : 94;
*/
// INSURGENT
case -1860900134:
return 49;
// INSURGENT3
case -1924433270:
return 81;
/*
// INSURGENT3
case -1924433270:
return BulletsShot%2==0 ? 86 : 91;
*/
// BLAZER5
case -1590337689:
return BulletsShot % 2 == 0 ? 17 : 18;
// BRUISER
case 668439077:
return BulletsShot % 2 == 0 ? 66 : 68;
// BRUTUS
case 2139203625:
return 84;
// MONSTER3
case 1721676810:
return BulletsShot % 2 == 0 ? 53 : 55;
// BRUISER3
case -2042350822:
return BulletsShot % 2 == 0 ? 52 : 50;
// BRUTUS3
case 2038858402:
return 84;
// MONSTER5
case -715746948:
return BulletsShot % 2 == 0 ? 63 : 65;
// JB7002
case 394110044:
return BulletsShot % 2 == 0 ? 54 : 53;
// DOMINATOR5
case -1375060657:
return BulletsShot % 2 == 0 ? 35 : 36;
// IMPALER3
case -1924800695:
return BulletsShot % 2 == 0 ? 75 : 76;
// IMPERATOR2
case 1637620610:
return BulletsShot % 2 == 0 ? 97 : 99;
// SLAMVAN5
case 373261600:
return BulletsShot % 2 == 0 ? 51 : 53;
// RUINER2
case 941494461:
return BulletsShot % 2 == 0 ? 65 : 66;
// TAMPA3
case -1210451983:
return 87;
// SCRAMJET
case -638562243:
return BulletsShot % 2 == 0 ? 44 : 45;
// VIGILANTE
case -1242608589:
return BulletsShot % 2 == 0 ? 42 : 43;
// ZR380
case 540101442:
return BulletsShot % 2 == 0 ? 57 : 63;
// ZR3802
case -1106120762:
return BulletsShot % 2 == 0 ? 57 : 63;
// ZR3803
case -1478704292:
return BulletsShot % 2 == 0 ? 53 : 59;
// STROMBERG
case 886810209:
return BulletsShot % 2 == 0 ? 85 : 84;
// SLAMVAN4
case -2061049099:
return BulletsShot % 2 == 0 ? 76 : 78;
// IMPERATOR
case 444994115:
return BulletsShot % 2 == 0 ? 88 : 86;
// IMPALER2
case 1009171724:
return BulletsShot % 2 == 0 ? 63 : 64;
// DOMINATOR4
case -688189648:
return BulletsShot % 2 == 0 ? 59 : 60;
// SAVAGE
case -82626025:
return 30;
// BUZZARD
case 788747387:
return BulletsShot % 2 == 0 ? 28 : 23;
// ANNIHL
case 837858166:
return (int)BulletsShot % 4 + 35;
// HYDRA
case 970385471:
return BulletsShot % 2 == 0 ? 29 : 28;
// STARLING
case -1700874274:
return BulletsShot % 2 == 0 ? 24 : 12;
// RHINO
case 782665360:
return 30;
default:
return AddOnDataProvider.GetMuzzleIndex(v.Model.Hash);
return (int)wp.Bones[CoreUtils.RandInt(0, wp.Bones.Length)].BoneIndex;
}
return -1;
}
public static EntityBone GetMuzzleBone(this Vehicle v, VehicleWeaponHash hash)
{
var i = v.GetMuzzleIndex(hash);
if (i == -1) { return null; }
return v.Bones[i];
}
public static bool IsUsingProjectileWeapon(this Ped p)
{
@ -377,83 +297,16 @@ namespace RageCoop.Client
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 readonly HashSet<uint> ExplosiveBullets = new HashSet<uint>
{
(uint)VehicleWeaponHash.PlayerLazer,
(uint)WeaponHash.Railgun,
1638077257
};
public static readonly Dictionary<WeaponHash, int> MuzzleBoneIndexes = new Dictionary<WeaponHash, int>
{
{WeaponHash.HeavySniper,6},
{WeaponHash.MarksmanRifle,9},
{WeaponHash.SniperRifle,9},
{WeaponHash.AdvancedRifle,5},
{WeaponHash.SpecialCarbine,9},
{WeaponHash.BullpupRifle,7},
{WeaponHash.AssaultRifle,9},
{WeaponHash.CarbineRifle,6},
{WeaponHash.MachinePistol,5},
{WeaponHash.SMG,5},
{WeaponHash.AssaultSMG,6},
{WeaponHash.CombatPDW,5},
{WeaponHash.MG,6},
{WeaponHash.CombatMG,7},
{WeaponHash.Gusenberg,7},
{WeaponHash.MicroSMG,10},
{WeaponHash.APPistol,8},
{WeaponHash.StunGun,4},
{WeaponHash.Pistol,8},
{WeaponHash.CombatPistol,8},
{WeaponHash.Pistol50,7},
{WeaponHash.SNSPistol,8},
{WeaponHash.HeavyPistol,8},
{WeaponHash.VintagePistol,8},
{WeaponHash.Railgun,9},
{WeaponHash.Minigun,5},
{WeaponHash.Musket,3},
{WeaponHash.HeavyShotgun,10},
{WeaponHash.PumpShotgun,11},
{WeaponHash.SawnOffShotgun,8},
{WeaponHash.BullpupShotgun,8},
{WeaponHash.AssaultShotgun,9},
{WeaponHash.HeavySniperMk2,11},
{WeaponHash.MarksmanRifleMk2,9},
{WeaponHash.CarbineRifleMk2,13},
{WeaponHash.SpecialCarbineMk2,16},
{WeaponHash.BullpupRifleMk2,8},
{WeaponHash.CompactRifle,7},
{WeaponHash.MilitaryRifle,11},
{WeaponHash.AssaultrifleMk2,17},
{WeaponHash.MiniSMG,5},
{WeaponHash.SMGMk2,6},
{WeaponHash.CombatMGMk2,16},
{WeaponHash.UnholyHellbringer,4},
{WeaponHash.PistolMk2,12},
{WeaponHash.SNSPistolMk2,15},
{WeaponHash.CeramicPistol,10},
{WeaponHash.MarksmanPistol,4},
{WeaponHash.Revolver,7},
{WeaponHash.RevolverMk2,7},
{WeaponHash.DoubleActionRevolver,7},
{WeaponHash.NavyRevolver,7},
{WeaponHash.PericoPistol,4},
{WeaponHash.FlareGun,4},
{WeaponHash.UpNAtomizer,4},
{WeaponHash.HomingLauncher,5},
{WeaponHash.CompactGrenadeLauncher,8},
{WeaponHash.Widowmaker,6},
{WeaponHash.GrenadeLauncher,3},
{WeaponHash.RPG,9},
{WeaponHash.DoubleBarrelShotgun,8},
{WeaponHash.SweeperShotgun,7},
{WeaponHash.CombatShotgun,7},
{WeaponHash.PumpShotgunMk2,7},
};
public static readonly HashSet<WeaponHash> ProjectileWeapons = new HashSet<WeaponHash> {
WeaponHash.HomingLauncher,
WeaponHash.RPG,
@ -471,8 +324,18 @@ namespace RageCoop.Client
(VehicleWeaponHash)3565779982, // STROMBERG missiles
(VehicleWeaponHash)3169388763, // SCRAMJET missiles
};
public static string GetFlashFX(this WeaponHash w)
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:
@ -510,16 +373,9 @@ namespace RageCoop.Client
case WeaponGroup.FireExtinguisher:
return "weap_extinguisher";
default:
return "muz_assault_rifle";
}
switch ((VehicleWeaponHash)w)
{
case VehicleWeaponHash.Tank:
return "muz_tank";
case VehicleWeaponHash.PlayerBuzzard:
return "muz_buzzard";
}
return "muz_assault_rifle";
}
public static WeaponGroup GetWeaponGroup(this WeaponHash hash)
{

View File

@ -2,6 +2,7 @@
using GTA.Native;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;

View File

@ -19,11 +19,33 @@ using System.Text;
[assembly: InternalsVisibleTo("RageCoop.Server")]
[assembly: InternalsVisibleTo("RageCoop.Client")]
[assembly: InternalsVisibleTo("RageCoop.Client.Installer")]
[assembly: InternalsVisibleTo("RageCoop.Client.DataDumper")]
[assembly: InternalsVisibleTo("RageCoop.ResourceBuilder")]
namespace RageCoop.Core
{
internal static class CoreUtils
{
private static Random random = new Random();
public static string FormatToSharpStyle(string input,int offset=14)
{
var ss = input.Substring(offset).Split("_".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
// Replace first character with upper case
for (int i = 0; i < ss.Length; i++)
{
var sec = ss[i].ToLower();
var head = sec[0];
ss[i] = head.ToString().ToUpper() + sec.Remove(0, 1);
}
return string.Join("", ss);
}
public static string ToHex(this int value)
{
return String.Format("0x{0:X}", value);
}
public static string ToHex(this uint value)
{
return String.Format("0x{0:X}", value);
}
private static readonly HashSet<string> ToIgnore = new HashSet<string>()
{
"RageCoop.Client",
@ -35,16 +57,37 @@ namespace RageCoop.Core
"ScriptHookVDotNet3",
"ScriptHookVDotNet"
};
public static int RandInt(int start,int end)
{
return random.Next(start, end);
}
public static string GetTempDirectory(string dir = null)
{
dir = dir ?? Path.GetTempPath();
string path;
do
{
path = Path.Combine(dir, RandomString(10));
} while (Directory.Exists(path) || File.Exists(path));
return path;
}
public static string RandomString(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
public static void GetDependencies(Assembly assembly, ref HashSet<string> existing)
{
if (assembly.FullName.StartsWith("System")) { return; }
foreach(var name in assembly.GetReferencedAssemblies())
foreach (var name in assembly.GetReferencedAssemblies())
{
if (name.FullName.StartsWith("System")) { continue; }
try
{
var asm = Assembly.Load(name);
GetDependencies(asm,ref existing);
GetDependencies(asm, ref existing);
}
catch { }
}

View File

@ -7,7 +7,7 @@ namespace RageCoop.Core
{
internal static class HttpHelper
{
public static void DownloadFile(string url, string destination, Action<int> progressCallback)
public static void DownloadFile(string url, string destination, Action<int> progressCallback = null)
{
if (File.Exists(destination)) { File.Delete(destination); }
AutoResetEvent ae = new AutoResetEvent(false);

View File

@ -15,6 +15,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RageCoop.Client.Loader", "C
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{531656CF-7269-488D-B042-741BC96C3941}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{12E29AB7-74C4-4250-8975-C02D7FFC2D7B}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU

View File

@ -15,7 +15,7 @@ using System.Resources;
[assembly: AssemblyCulture("")]
// Version information
[assembly: AssemblyVersion("1.5.6.1")]
[assembly: AssemblyFileVersion("1.5.6.1")]
[assembly: AssemblyVersion("1.5.6.12")]
[assembly: AssemblyFileVersion("1.5.6.12")]
[assembly: NeutralResourcesLanguageAttribute( "en-US" )]

Binary file not shown.

Binary file not shown.

Binary file not shown.