RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

[RUO 2.0] RangeUtility

Vorspire

Knight
[RUO 2.0] RangeUtility

Server.RangeUtility

I don't have time to write a massive post full of bells and whistles this time, because this release is aimed at more experienced developers who would like an extended Range API.

The RangeUtility basically provides methods for traversing and comparing Points on a given Map.

---------------------------------------------------------------------------------------------

The base function that makes the entire thing possible is ZipRange.
ZipRange was named after the way .NET implemented the new Array.Zip method, as it iterates through 2 index's, ZipRange traverses the X and Y axis to calculate the Points that should be included in the final Array.

---------------------------------------------------------------------------------------------

ZipRange also has efficiency in mind;

You can use the ZipRange method's Callback argument to supply a method to run for each Point that passes the range validation.

If the Callback returns true, the ZipRange internal X-Y for-loops will break and the process will complete without going through all of the Points that could be validated.

The Callback is particularly useful if you want to search for the first instance of an Item within range, and if found, break the method to continue the process.

The Callback has also been designed in such a way that you can specify an optional Reference Object, which will be passed to the Callback to be modified and that modification will bubble back up to the initial place you called ZipRange from.

The Reference Object for the Callback can be anything you want and can be changed dynamically where needed, it can be used to feed arguments to the Callback method, which then, the Callback method can transform it into another Type and it will bubble up.

ZipRange will always return a Point3DList[], of which structure can be accessed like so:
Rich (BB code):
Point3DList[] list = ZipRange( ... );

for(int distance = 0; distance < list.Length distance++)
{
    foreach( Point3D p in list[distance] )
    {
          ...
    }
}

---------------------------------------------------------------------------------------------

The RangeUtility also incorporates a few methods for searching and indexing different Types, these are all based on one function also; GetObjectsInRange<T>
- See the script for more details on that, as the other methods, like GetMobilesInRange, which call GetObjectsInRange<Mobile> too.

---------------------------------------------------------------------------------------------

Anyway, here's the script in plain-text format, so it can be reviewed and discussed without downloading.

[syntax]
using System;
using System.Collections.Generic;
using System.Text;

using Server;
using Server.Items;
using Server.Mobiles;

namespace Server
{
public delegate bool ZipRangeCallback<T>(ZipRangeResult result, ref T state);

public struct ZipRangeResult
{
private Point3D _Center;
public Point3D Center { get { return _Center; } }

private Map _Map;
public Map Map { get { return _Map; } }

private int _Distance;
public int Distance { get { return _Distance; } }

private Point3D _Current;
public Point3D Current { get { return _Current; } }

public ZipRangeResult(Point3D center, Map map, int distance, Point3D current)
{
_Center = center;
_Map = map;
_Distance = distance;
_Current = current;
}
}

public class RangeUtility
{
public static List<Point3D>[] ZipRange(Point3D center, Map map, int range)
{
List<Point3D>[] list = new List<Point3D>[range + 1];

for (int x = -range; x <= range; x++)
{
for (int y = -range; y <= range; y++)
{
int distance = (int)Math.Sqrt(x * x + y * y);

if (distance <= range)
{
if (list[distance] == null)
{ list[distance] = new List<Point3D>(); }

Point3D p = new Point3D(center.X + x, center.Y + y, map.GetAverageZ(center.X + x, center.Y + y));
list[distance].Add(p);
}
}
}

return list;
}

public static List<Point3D>[] ZipRange(Point3D center, Map map, int range, ZipRangeCallback<object> handler, ref object arg)
{ return ZipRange<object>(center, map, range, handler, ref arg); }

public static List<Point3D>[] ZipRange<T>(Point3D center, Map map, int range, ZipRangeCallback<T> handler, ref T arg)
{
bool die = false;
List<Point3D>[] list = new List<Point3D>[range + 1];

for (int x = -range; x <= range; x++)
{
for (int y = -range; y <= range; y++)
{
int distance = (int)Math.Sqrt(x * x + y * y);

if (distance <= range)
{
if (list[distance] == null)
{ list[distance] = new List<Point3D>(); }

Point3D p = new Point3D(center.X + x, center.Y + y, map.GetAverageZ(center.X + x, center.Y + y));
list[distance].Add(p);

if (handler != null)
{ die = handler.Invoke(new ZipRangeResult(center, map, distance, p), ref arg); }

if (die)
{ return list; }
}
}
}

return list;
}

public static bool InRange2D(Point3D check, Point3D p, Map map, int range)
{
object state = check;
ZipRange(p, map, range, new ZipRangeCallback<object>(InRange2D_Callback), ref state);
return (bool)state;
}

private static bool InRange2D_Callback(ZipRangeResult result, ref object state)
{
Point3D check = (Point3D)state;

if (check.X == result.Current.X && check.Y == result.Current.Y)
{ state = true; }

return (bool)state;
}

public static bool InRange3D(Point3D check, Point3D p, Map map, int range, int floor, int roof)
{
object state = new object[] { check, floor, roof };
ZipRange(p, map, range, new ZipRangeCallback<object>(InRange3D_Callback), ref state);
return (bool)state;
}

private static bool InRange3D_Callback(ZipRangeResult result, ref object state)
{
object[] states = (object[])state;
Point3D check = (Point3D)states[0];
int floor = (int)states[1];
int roof = (int)states[2];

if (check.X == result.Current.X && check.Y == result.Current.Y && check.Z >= floor && check.Z <= roof)
{ state = true; }

return (bool)state;
}

public static List<T> GetObjectsInRange<T>(Point3D center, Map map, int range)
{
List<T> state = new List<T>();
ZipRange(center, map, range, new ZipRangeCallback<List<T>>(GetObjectsInRange_Callback<T>), ref state);
return state;
}

private static bool GetObjectsInRange_Callback<T>(ZipRangeResult result, ref List<T> state)
{
IPooledEnumerable eable = result.Map.GetObjectsInRange(result.Current, 0);
foreach (object o in eable)
{
if (o is T)
{ state.Add((T)o); }
}
eable.Free();
return false;
}

public static List<Mobile> GetMobilesInRange(Point3D center, Map map, int range)
{ return GetObjectsInRange<Mobile>(center, map, range); }

public static List<BaseVendor> GetVendorsInRange(Point3D center, Map map, int range)
{ return GetObjectsInRange<BaseVendor>(center, map, range); }

public static List<PlayerMobile> GetPlayersInRange(Point3D center, Map map, int range)
{ return GetObjectsInRange<PlayerMobile>(center, map, range); }

public static List<BaseCreature> GetCreaturesInRange(Point3D center, Map map, int range)
{ return GetObjectsInRange<BaseCreature>(center, map, range); }

public static List<Item> GetItemsInRange(Point3D center, Map map, int range)
{ return GetObjectsInRange<Item>(center, map, range); }

public static List<IEntity> GetEntitiesInRange(Point3D center, Map map, int range)
{ return GetObjectsInRange<IEntity>(center, map, range); }
}
}
[/syntax]

I hope the community finds this one useful :)
 
Top