Skip to content

Commit

Permalink
Add estimated average stats calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
DerpyNewbie committed Mar 28, 2024
1 parent c75eae2 commit 5f1f0c8
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using CenturionCC.System.Editor.Utils;
using System;
using System.Linq;
using CenturionCC.System.Editor.Utils;
using CenturionCC.System.Gun;
using CenturionCC.System.Gun.DataStore;
using UdonSharpEditor;
Expand All @@ -16,17 +18,26 @@ public class GunBulletDataStoreEditor : UnityEditor.Editor
private static float _offsetMin = 1F;
private static float _offsetMax = 5F;
private static int _simPoints = 200;
private float _cachedAvgDistance = 0F;
private float _cachedAvgHighestPoint = 0F;
private int _cachedMaxPatterns = 0;

private bool _hasCache = false;

private void OnSceneGUI()
{
if (!_usePreview || _shootingRef == null) return;
var shootingRef = _shootingRef;
if (!_usePreview) return;

serializedObject.ApplyModifiedProperties();
var data = (GunBulletDataStore)target;
if (_useRangePreview) DrawRange(_shootingRef, Vector3.zero, Quaternion.identity);
var data = target as GunBulletDataStore;
if (data == null) return;
if (shootingRef == null) shootingRef = data.transform;

if (_useRangePreview) DrawRange(shootingRef, Vector3.zero, Quaternion.identity);
for (int i = (int)_offsetMin; i <= (int)_offsetMax; i++)
{
DrawHandles(_shootingRef, Vector3.zero, Quaternion.identity, data, i);
DrawHandles(shootingRef, Vector3.zero, Quaternion.identity, data, i);
}
}

Expand All @@ -53,6 +64,10 @@ public override void OnInspectorGUI()
using (new EditorGUI.IndentLevelScope())
{
_usePreview = EditorGUILayout.Toggle("Use Preview", _usePreview);
if (_usePreview)
EditorGUILayout.HelpBox("Preview trajectory is just an approximation, Do not expect accuracy!",
MessageType.Warning);

using (new EditorGUI.DisabledGroupScope(!_usePreview))
{
_useRangePreview = EditorGUILayout.Toggle("Use Range Preview", _useRangePreview);
Expand All @@ -64,6 +79,39 @@ public override void OnInspectorGUI()

if (_usePreview && _shootingRef != null)
GUILayout.Label($"Previewing pattern {(int)_offsetMin} to {(int)_offsetMax}");

if (GUILayout.Button("Calculate Stats"))
{
var data = target as GunBulletDataStore;
if (data == null) throw new ArgumentNullException(nameof(data));
var recoils = data.RecoilPattern;
var maxPatterns = recoils.MaxPatterns;
var dists = new float[maxPatterns];
var highests = new float[maxPatterns];
for (int i = 0; i < maxPatterns; i++)
{
GetPredictedStats(data, i, out var dist, out var highest);
dists[i] = dist;
highests[i] = highest;
}

_cachedMaxPatterns = maxPatterns;
_cachedAvgDistance = dists.Average();
_cachedAvgHighestPoint = highests.Average();
_hasCache = true;
}

if (_hasCache)
{
using (new EditorGUI.DisabledGroupScope(true))
{
EditorGUILayout.HelpBox("This is just an approximation. Expect around +-5m error.",
MessageType.Warning);
EditorGUILayout.IntField("Patterns", _cachedMaxPatterns);
EditorGUILayout.FloatField("Avg Distance", _cachedAvgDistance);
EditorGUILayout.FloatField("Avg Highest", _cachedAvgHighestPoint);
}
}
}
}

Expand Down Expand Up @@ -120,5 +168,18 @@ public static void DrawRange(Transform parent, Vector3 offsetPos, Quaternion off
Handles.Label(point + left, $"{i}m");
}
}

public static void GetPredictedStats(GunBulletDataStore data, int offset, out float distance, out float highest)
{
var line = GunBullet.PredictTrajectory(Vector3.zero, Quaternion.identity, data, offset, _simPoints);
highest = float.NegativeInfinity;
distance = float.NegativeInfinity;
for (int i = 1; i < line.Length; i++)
{
var p = line[i];
if (p.y >= highest) highest = p.y;
if (p.y <= 0 && line[i - 1].y >= 0) distance = p.magnitude;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ [SerializeField] [Tooltip("In m/s")]
[SerializeField]
private GunRecoilPatternDataStore recoilPattern;

public GunRecoilPatternDataStore RecoilPattern => recoilPattern;
public override int ProjectileCount => projectileCount;

public override void Get(int i,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
using UdonSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using UdonSharp;
using UnityEngine;

[assembly: InternalsVisibleTo("CenturionCC.System.Editor")]

namespace CenturionCC.System.Gun.DataStore
{
[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
Expand Down Expand Up @@ -34,6 +40,10 @@ public class GunRecoilPatternDataStore : UdonSharpBehaviour
0.3F
};

public Vector3[] RecoilOffsetPatterns => recoilOffsetPatterns;
public Vector3[] PositionOffsetPatterns => positionOffsetPatterns;
public float[] SpeedOffsetPatterns => speedOffsetPatterns;

public virtual Vector3 GetRecoilOffset(int count)
{
return recoilOffsetPatterns[count % recoilOffsetPatterns.Length];
Expand All @@ -55,5 +65,39 @@ public virtual void Get(int count, out float speedOffset, out Vector3 recoilOffs
recoilOffset = recoilOffsetPatterns[count % recoilOffsetPatterns.Length];
positionOffset = positionOffsetPatterns[count % positionOffsetPatterns.Length];
}

#if !COMPILER_UDONSHARP && UNITY_EDITOR

public int MaxPatterns => Lcm(new[]
{ recoilOffsetPatterns.Length, positionOffsetPatterns.Length, speedOffsetPatterns.Length });

private static int Lcm(int[] vs)
{
vs = vs.Where(x => x > 1).ToArray();
if (vs.Length < 2)
return vs.Length == 1 ? vs[0] : 1;

var div = 2;
var divs = new List<int>();

while (true)
{
if (vs.Count(x => x % div == 0) == vs.Length)
{
vs = vs.Select(x => x / div).ToArray();
divs.Add(div);
}
else
{
div++;
}

Array.Sort(vs);
if (vs[vs.Length - 2] < div) break;
}

return divs.Aggregate(1, (current, i) => current * i);
}
#endif
}
}

0 comments on commit 5f1f0c8

Please sign in to comment.