Created
August 20, 2019 07:59
-
-
Save ikt32/58d7bf002aabee23d090988987565cb0 to your computer and use it in GitHub Desktop.
Glowing Brake Discs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Drawing; | |
using GTA; | |
using GTA.Math; | |
using GTA.Native; | |
static class MathExt | |
{ | |
public static T Clamp<T>(this T val, T min, T max) where T : IComparable<T> | |
{ | |
if (val.CompareTo(min) < 0) return min; | |
else if (val.CompareTo(max) > 0) return max; | |
else return val; | |
} | |
public static float Lerp(float firstFloat, float secondFloat, float by) | |
{ | |
return firstFloat * (1 - by) + secondFloat * by; | |
} | |
public static float Map(float x, float in_min, float in_max, float out_min, float out_max) | |
{ | |
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; | |
} | |
public static float DegToRad(float angle) | |
{ | |
return (float)(Math.PI * (double)angle / 180.0); | |
} | |
public static Vector3 GetOffsetInWorldCoords(Vector3 position, Vector3 rotation, Vector3 forward, Vector3 offset) | |
{ | |
const float deg2Rad = (float)0.01745329251994329576923690768489; | |
float num1 = (float)System.Math.Cos(rotation.Y * deg2Rad); | |
float x = num1 * (float)System.Math.Cos(-rotation.Z * deg2Rad); | |
float y = num1 * (float)System.Math.Sin(rotation.Z * deg2Rad); | |
float z = (float)System.Math.Sin(-rotation.Y * deg2Rad); | |
Vector3 right = new Vector3((float)x, (float)y, (float)z); | |
Vector3 up = Vector3.Cross(right, forward); | |
return position + (right * offset.X) + (forward * offset.Y) + (up * offset.Z); | |
} | |
} | |
public class GlowVehicle | |
{ | |
private readonly Vehicle _vehicle; | |
public GlowVehicle(Vehicle vehicle) | |
{ | |
_vehicle = vehicle; | |
CurrVelocity = Function.Call<Vector3>(Hash.GET_ENTITY_SPEED_VECTOR, Vehicle, true); | |
LastVelocity = CurrVelocity; | |
Acceleration = (CurrVelocity - LastVelocity) / Game.LastFrameTime; | |
} | |
public Vehicle Vehicle | |
{ | |
get { return _vehicle; } | |
} | |
public float[] BrakeTemps = new float[4]; | |
public int[] PtfxHandles = new int[4] { 0, 0, 0, 0 }; | |
public Vector3 CurrVelocity { get; private set; } | |
public Vector3 LastVelocity { get; private set; } | |
public Vector3 Acceleration { get; private set; } | |
public void Update() | |
{ | |
LastVelocity = CurrVelocity; | |
CurrVelocity = Function.Call<Vector3>(Hash.GET_ENTITY_SPEED_VECTOR, Vehicle, true); | |
Acceleration = (CurrVelocity - LastVelocity) / Game.LastFrameTime; | |
} | |
public void ClearPtfx() | |
{ | |
for (int i = 0; i < 4; ++i) | |
{ | |
if (this.PtfxHandles[i] != 0) | |
{ | |
Function.Call(Hash.REMOVE_PARTICLE_FX, this.PtfxHandles[i], 0); | |
this.PtfxHandles[i] = 0; | |
} | |
} | |
} | |
} | |
public class GlowingDisks : Script | |
{ | |
private List<GlowVehicle> _glowVehicles = null; | |
public GlowingDisks() | |
{ | |
_glowVehicles = new List<GlowVehicle>(); | |
Tick += OnTick; | |
Aborted += OnAbort; | |
} | |
private void OnAbort(object sourc, EventArgs e) | |
{ | |
foreach (var v in _glowVehicles) | |
{ | |
v.ClearPtfx(); | |
} | |
} | |
private void OnTick(object source, EventArgs e) | |
{ | |
Vehicle[] allVehicles = World.GetAllVehicles(); | |
for (int i = 0; i < _glowVehicles.Count; ++i) | |
{ | |
bool exist = _glowVehicles[i].Vehicle.Exists(); | |
float distance = 0.0f; | |
if (exist) | |
distance = World.GetDistance(Game.Player.Character.Position, _glowVehicles[i].Vehicle.Position); | |
if (!exist || distance > 50.0f) | |
{ | |
_glowVehicles.RemoveAt(i); | |
--i; | |
} | |
} | |
// Add newly discovered vehicles | |
foreach (var v in allVehicles) | |
{ | |
if (GetNumWheels(v) != 4) | |
continue; | |
if (World.GetDistance(Game.Player.Character.Position, v.Position) > 50.0f) | |
continue; | |
if (!_glowVehicles.Exists(x => x.Vehicle == v)) | |
{ | |
_glowVehicles.Add(new GlowVehicle(v)); | |
} | |
} | |
// Glow | |
foreach (var v in _glowVehicles) | |
{ | |
v.Update(); | |
DrawDisks(v); | |
} | |
} | |
void DrawDisks(GlowVehicle v) | |
{ | |
if (v.Vehicle.GetBoneIndex("wheel_lf") == -1) return; | |
if (v.Vehicle.GetBoneIndex("wheel_rf") == -1) return; | |
if (v.Vehicle.GetBoneIndex("wheel_lr") == -1) return; | |
if (v.Vehicle.GetBoneIndex("wheel_rr") == -1) return; | |
Vector3[] wheelCoords = new Vector3[4]; | |
wheelCoords[0] = v.Vehicle.GetBoneCoord("wheel_lf"); | |
wheelCoords[1] = v.Vehicle.GetBoneCoord("wheel_rf"); | |
wheelCoords[2] = v.Vehicle.GetBoneCoord("wheel_lr"); | |
wheelCoords[3] = v.Vehicle.GetBoneCoord("wheel_rr"); | |
int[] boneIdxs = new int[4]; | |
boneIdxs[0] = v.Vehicle.GetBoneIndex("wheel_lf"); | |
boneIdxs[1] = v.Vehicle.GetBoneIndex("wheel_rf"); | |
boneIdxs[2] = v.Vehicle.GetBoneIndex("wheel_lr"); | |
boneIdxs[3] = v.Vehicle.GetBoneIndex("wheel_rr"); | |
float[] weightShiftFactor = new float[4]; | |
weightShiftFactor[0] = -v.Acceleration.Y; | |
weightShiftFactor[1] = -v.Acceleration.Y; | |
weightShiftFactor[2] = v.Acceleration.Y; | |
weightShiftFactor[3] = v.Acceleration.Y; | |
var wheelRotSpeeds = GetWheelRotationSpeeds(v.Vehicle); | |
var steeredWheelAngles = GetWheelSteeringAngles(v.Vehicle); | |
var brakePressures = GetBrakePressures(v.Vehicle); | |
Vector3 p = v.Vehicle.Position; | |
for (int i = 0; i < 4; ++i) | |
{ | |
if (float.IsNaN(v.BrakeTemps[i])) | |
v.BrakeTemps[i] = 0.0f; | |
float targetVal = 0.0f; | |
if (brakePressures[i] > 0.0f) | |
{ | |
targetVal = (brakePressures[i] + weightShiftFactor[i] / 40.0f) * Math.Abs(wheelRotSpeeds[i]); | |
} | |
targetVal = targetVal.Clamp(0.0f, 1.0f); | |
if (targetVal > 0.0f) | |
v.BrakeTemps[i] = MathExt.Lerp(v.BrakeTemps[i], targetVal, 1.0f - (float)Math.Pow(0.100f, Game.LastFrameTime)); | |
else | |
{ | |
float coolRateMod = MathExt.Map(Math.Abs(wheelRotSpeeds[i]), 0.0f, 60.0f, 0.100f, -0.200f); | |
coolRateMod = coolRateMod.Clamp(-200.0f, 100.0f); | |
v.BrakeTemps[i] = MathExt.Lerp(v.BrakeTemps[i], 0.0f, 1.0f - (float)Math.Pow(0.800f + coolRateMod, Game.LastFrameTime)); | |
} | |
v.BrakeTemps[i].Clamp(0.0f, 1.0f); | |
if (float.IsNaN(v.BrakeTemps[i])) | |
v.BrakeTemps[i] = 0.0f; | |
//v.BrakeTemps[i] = 1.0f; //TODO: Temporary | |
// Drawing ptfx | |
if (v.BrakeTemps[i] > 0.066f) | |
{ | |
if (v.PtfxHandles[i] == 0) | |
{ | |
//RequestEffectLibrary("veh_impexp_rocket"); | |
Function.Call(Hash.REQUEST_NAMED_PTFX_ASSET, "veh_impexp_rocket"); | |
while (!Function.Call<bool>(Hash.HAS_NAMED_PTFX_ASSET_LOADED, "veh_impexp_rocket")) | |
Wait(0); | |
Function.Call(Hash._0x6C38AF3693A69A91, "veh_impexp_rocket"); //USE_PARTICLE_FX_ASSET | |
v.PtfxHandles[i] = Function.Call<int>(Hash._START_PARTICLE_FX_LOOPED_ON_ENTITY_BONE, | |
"veh_rocket_boost", | |
v.Vehicle, | |
-0.09f, 0.0f, 0.0f, | |
0.0f, 0.0f, -90.0f, | |
boneIdxs[i], 1.375f, | |
false, false, false); | |
Function.Call(Hash.SET_PARTICLE_FX_LOOPED_EVOLUTION, v.PtfxHandles[i], "boost", 0.0f, 0); | |
Function.Call(Hash.SET_PARTICLE_FX_LOOPED_EVOLUTION, v.PtfxHandles[i], "charge", 0.0f, 0); | |
Function.Call(Hash.SET_PARTICLE_FX_LOOPED_ALPHA, v.PtfxHandles[i], 100.0f); | |
} | |
} | |
if (v.BrakeTemps[i] < 0.050f) | |
{ | |
if (v.PtfxHandles[i] != 0) | |
{ | |
Function.Call(Hash.REMOVE_PARTICLE_FX, v.PtfxHandles[i], 0); | |
v.PtfxHandles[i] = 0; | |
} | |
} | |
Function.Call(Hash.SET_PARTICLE_FX_LOOPED_ALPHA, v.PtfxHandles[i], v.BrakeTemps[i] * 100.0f); | |
Function.Call(Hash.SET_PARTICLE_FX_LOOPED_EVOLUTION, v.PtfxHandles[i], "charge", v.BrakeTemps[i], 0); | |
// want the outer edges to glow before the inner parts | |
//Function.Call(Hash.SET_PARTICLE_FX_LOOPED_SCALE, v.PtfxHandles[i], 2.375f - v.BrakeTemps[i], 0); | |
// lmao hot | |
//float boostFire = v.BrakeTemps[i] > 0.66f ? ( v.BrakeTemps[i] - 0.66f )/0.33f: 0.0f; | |
//Function.Call(Hash.SET_PARTICLE_FX_LOOPED_EVOLUTION, v.PtfxHandles[i], "boost", boostFire, 0); | |
//// Drawing/Positioning marker | |
//float mult = GetDrawnWheelAngleMult(v.Vehicle); | |
//float actualAngle = steeredWheelAngles[i] * mult; | |
//float debugAngle = actualAngle - MathExt.DegToRad(90.0f); | |
//float steeringAngleRelX = (float)-Math.Sin(debugAngle); | |
//float steeringAngleRelY = (float)Math.Cos(debugAngle); | |
//Vector3 forward = v.Vehicle.GetOffsetInWorldCoords(new Vector3(steeringAngleRelX, steeringAngleRelY, 0.0f)); | |
//Vector3 dir = forward - p; | |
//Vector3 rot = new Vector3 | |
//{ | |
// X = 90.0f | |
//}; | |
// | |
//float sgn = -1.0f; | |
//if (i % 2 != 0) sgn = 1.0f; | |
//Vector3 coord = MathExt.GetOffsetInWorldCoords(wheelCoords[i], rot, dir, new Vector3(0, sgn * 0.011f, 0)); | |
// | |
//Color color = Color.FromArgb( | |
// (int)(v.BrakeTemps[i] * 160.0f), | |
// (int)(v.BrakeTemps[i] * 255.0f), | |
// v.BrakeTemps[i] > 0.66f ? (int)(((v.BrakeTemps[i] - 0.66f) / (0.33f)) * 128.0f) : 0, | |
// 0); | |
// | |
//DrawMarker(MarkerType.HorizontalCircleFat, | |
// coord, dir, rot, 0.31f, color); | |
//DrawMarker(MarkerType.HorizontalCircleFat, | |
// coord, dir, rot, 0.21f, color); | |
// rip for this ptfx | |
//Function.Call(Hash.SET_PARTICLE_FX_LOOPED_COLOUR, v.PtfxHandles[i], | |
//0.0f, //R | |
//0.0f, //G | |
//255.0f, //B | |
//false); | |
} | |
} | |
private void DrawMarker(MarkerType marker, Vector3 pos, Vector3 dir, Vector3 rot, float scale, Color color) | |
{ | |
World.DrawMarker(marker, pos, dir, rot, new Vector3(scale, scale, scale), color); | |
} | |
unsafe ulong GetWheelsPtr(Vehicle handle) | |
{ | |
var address = (ulong)handle.MemoryAddress; | |
ulong offset = 0xBB0; //TODO: Future-proof | |
return *((ulong*)(address + offset)); | |
} | |
private unsafe int GetNumWheels(Vehicle v) | |
{ | |
return *(int*)((ulong)v.MemoryAddress + 0xBB8); //TODO: Future-proof | |
} | |
unsafe List<ulong> GetWheelPtrs(Vehicle handle) | |
{ | |
var wheelPtr = GetWheelsPtr(handle); | |
var numWheels = GetNumWheels(handle); | |
List<ulong> wheelPtrs = new List<ulong>(); | |
for (int i = 0; i < numWheels; i++) | |
{ | |
var wheelAddr = *((ulong*)(wheelPtr + 0x008 * (ulong)i)); | |
wheelPtrs.Add(wheelAddr); | |
} | |
return wheelPtrs; | |
} | |
unsafe List<float> GetWheelRotationSpeeds(Vehicle handle) | |
{ | |
List<ulong> wheelPtrs = GetWheelPtrs(handle); | |
ulong offset = 0x170; // TODO: Future-proof | |
List<float> speeds = new List<float>(); | |
foreach (var wheel in wheelPtrs) | |
{ | |
speeds.Add(-*((float*)(wheel + offset))); | |
} | |
return speeds; | |
} | |
unsafe List<float> GetWheelSteeringAngles(Vehicle handle) | |
{ | |
List<ulong> wheelPtrs = GetWheelPtrs(handle); | |
ulong offset = 0x1CC; // TODO: Future-proof | |
List<float> angles = new List<float>(); | |
foreach (var wheel in wheelPtrs) | |
{ | |
angles.Add(*((float*)(wheel + offset))); | |
} | |
return angles; | |
} | |
unsafe List<float> GetBrakePressures(Vehicle handle) | |
{ | |
List<ulong> wheelPtrs = GetWheelPtrs(handle); | |
ulong offset = 0x1D0; // TODO: Future-proof | |
List<float> angles = new List<float>(); | |
foreach (var wheel in wheelPtrs) | |
{ | |
angles.Add(*((float*)(wheel + offset))); | |
} | |
return angles; | |
} | |
unsafe ulong GetModelInfoPtr(Vehicle handle) | |
{ | |
var address = (ulong)handle.MemoryAddress; | |
ulong offset = 0x020; //TODO: Future-proof | |
return *((ulong*)(address + offset)); | |
} | |
unsafe float GetDrawnWheelAngleMult(Vehicle handle) | |
{ | |
return *(float*)(GetModelInfoPtr(handle) + 0x49c); | |
} | |
void ShowText(float x, float y, string text, float size = 0.2f) | |
{ | |
Function.Call(Hash.SET_TEXT_FONT, 0); | |
Function.Call(Hash.SET_TEXT_SCALE, size, size); | |
Function.Call(Hash.SET_TEXT_COLOUR, 255, 0, 0, 255); | |
Function.Call(Hash.SET_TEXT_WRAP, 0.0, 1.0); | |
Function.Call(Hash.SET_TEXT_CENTRE, 0); | |
Function.Call(Hash.SET_TEXT_OUTLINE, true); | |
Function.Call(Hash._SET_TEXT_ENTRY, "STRING"); | |
Function.Call(Hash._ADD_TEXT_COMPONENT_STRING, text); | |
Function.Call(Hash._DRAW_TEXT, x, y); | |
} | |
void RequestEffectLibrary(string lib) | |
{ | |
Function.Call(Hash.REQUEST_NAMED_PTFX_ASSET, lib); | |
while (!Function.Call<bool>(Hash.HAS_NAMED_PTFX_ASSET_LOADED, lib)) | |
Wait(0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment