-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExtensions.cs
More file actions
122 lines (111 loc) · 4.75 KB
/
Extensions.cs
File metadata and controls
122 lines (111 loc) · 4.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// This class adds functions to built-in types.
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Events;
using System;
using System.Collections.Generic;
using System.Linq;
namespace uMMORPG
{
public static class Extensions
{
// string to int (returns errVal if failed)
public static int ToInt(this string value, int errVal=0)
{
Int32.TryParse(value, out errVal);
return errVal;
}
// string to long (returns errVal if failed)
public static long ToLong(this string value, long errVal=0)
{
Int64.TryParse(value, out errVal);
return errVal;
}
// UI SetListener extension that removes previous and then adds new listener
// (this version is for onClick etc.)
public static void SetListener(this UnityEvent uEvent, UnityAction call)
{
uEvent.RemoveAllListeners();
uEvent.AddListener(call);
}
// UI SetListener extension that removes previous and then adds new listener
// (this version is for onEndEdit, onValueChanged etc.)
public static void SetListener<T>(this UnityEvent<T> uEvent, UnityAction<T> call)
{
uEvent.RemoveAllListeners();
uEvent.AddListener(call);
}
// NavMeshAgent helper function that returns the nearest valid point for a
// given destination. This is really useful for click & wsad movement
// because the player may click into all kinds of unwalkable paths:
//
// ________
// |xxxxxxx|
// |x| |x|
// P A|B| C |x|
// |x|___|x|
// |xxxxxxx|
//
// if a player is at position P and tries to go to:
// - A: the path is walkable, everything is fine
// - C: C is on a NavMesh, but we can't get there directly. CalcualatePath
// will return A as the last walkable point
// - B: B is not on a NavMesh, CalulatePath doesn't work here. We need to
// find the nearest point on a NavMesh first (might be A or C) and then
// calculate the nearest valid one (A)
public static Vector3 NearestValidDestination(this NavMeshAgent agent, Vector3 destination)
{
// can we calculate a path there? then return the closest valid point
NavMeshPath path = new NavMeshPath();
if (agent.CalculatePath(destination, path))
return path.corners[path.corners.Length - 1];
// otherwise find nearest navmesh position first. we use a radius of
// speed*2 which works fine. afterwards we find the closest valid point.
if (NavMesh.SamplePosition(destination, out NavMeshHit hit, agent.speed * 2, NavMesh.AllAreas))
if (agent.CalculatePath(hit.position, path))
return path.corners[path.corners.Length - 1];
// nothing worked, don't go anywhere.
return agent.transform.position;
}
// NavMeshAgent's ResetPath() function clears the path, but doesn't clear
// the velocity immediately. This is a nightmare for finite state machines
// because we often reset a path, then switch to casting, which would then
// receive a movement event because velocity still isn't 0 until a few
// frames later.
//
// We need a function that truly stops all movement.
public static void ResetMovement(this NavMeshAgent agent)
{
agent.ResetPath();
agent.velocity = Vector3.zero;
}
// check if a list has duplicates
// new List<int>(){1, 2, 2, 3}.HasDuplicates() => true
// new List<int>(){1, 2, 3, 4}.HasDuplicates() => false
// new List<int>().HasDuplicates() => false
public static bool HasDuplicates<T>(this List<T> list)
{
return list.Count != list.Distinct().Count();
}
// find all duplicates in a list
// note: this is only called once on start, so Linq is fine here!
public static List<U> FindDuplicates<T, U>(this List<T> list, Func<T, U> keySelector)
{
return list.GroupBy(keySelector)
.Where(group => group.Count() > 1)
.Select(group => group.Key).ToList();
}
// string.GetHashCode is not guaranteed to be the same on all machines, but
// we need one that is the same on all machines. simple and stupid:
public static int GetStableHashCode(this string text)
{
unchecked
{
int hash = 23;
foreach (char c in text)
hash = hash * 31 + c;
return hash;
}
}
}
}