
#region
using System;
using System.Collections.Generic;
using System.Linq;
using wServer.networking.svrPackets;
#endregion
namespace wServer.realm.entities.player
{
public partial class Player
{
public int UpdatesSend { get; private set; }
public int UpdatesReceived { get; set; }
public const int RADIUS = 15;
const int APPOX_AREA_OF_SIGHT = (int)(Math.PI * RADIUS * RADIUS + 1);
int mapWidth, mapHeight;
private int tickId;
HashSet<Entity> clientEntities = new HashSet<Entity>();
HashSet<IntPoint> clientStatic = new HashSet<IntPoint>(new IntPointComparer());
List<IntPoint> SightTiles = new List<IntPoint>();
IEnumerable<Entity> GetNewEntities()
{
foreach (var i in Owner.Players.Where(i => clientEntities.Add(i.Value)))
yield return i.Value;
foreach (var i in Owner.PlayersCollision.HitTest(X, Y, RADIUS).OfType<Decoy>().Where(i => clientEntities.Add(i)))
yield return i;
foreach (var i in Owner.PlayersCollision.HitTest(X, Y, RADIUS).OfType<Pet>().Where(i => clientEntities.Add(i)))
yield return i;
foreach (var i in Owner.EnemiesCollision.HitTest(X, Y, RADIUS))
{
if (i is Container)
{
var owner = (i as Container).BagOwners?.Length == 1 ? (i as Container).BagOwners[0] : null;
if (owner != null && owner != AccountId) continue;
if (owner == AccountId)
if ((LootDropBoost || LootTierBoost) && (i.ObjectType != 0x500 || i.ObjectType != 0x506))
(i as Container).BoostedBag = true; //boosted bag
}
if (MathsUtils.DistSqr(i.X, i.Y, X, Y) <= RADIUS * RADIUS)
if (clientEntities.Add(i))
yield return i;
}
if (Quest != null && clientEntities.Add(Quest))
yield return Quest;
}
IEnumerable<int> GetRemovedEntities()
{
foreach (var i in clientEntities)
{
if (i is Player && i.Owner != null) continue;
if (!SightTiles.Contains(new IntPoint((int)i.X, (int)i.Y)) && !(i is StaticObject && (i as StaticObject).Static) && i != Quest)
yield return i.Id;
else if (i.Owner == null)
yield return i.Id;
}
}
IEnumerable<ObjectDef> GetNewStatics(int _x, int _y)
{
List<ObjectDef> ret = new List<ObjectDef>();
foreach (var i in SightTiles)
{
int x = i.X;
int y = i.Y;
if (x < 0 || x >= mapWidth || y < 0 || y >= mapHeight)
continue;
var tile = Owner.Map[x, y];
if (tile.ObjId != 0 && tile.ObjType != 0 && clientStatic.Add(new IntPoint(x, y)))
ret.Add(tile.ToDef(x, y));
}
return ret;
}
IEnumerable<IntPoint> GetRemovedStatics(int _x, int _y)
{
foreach (var i in clientStatic)
{
var dx = i.X;
var dy = i.Y;
var tile = Owner.Map[i.X, i.Y];
if (tile.ObjType == 0)
{
int objId = Owner.Map[i.X, i.Y].ObjId;
if (objId != 0)
yield return i;
}
}
}
Dictionary<Entity, int> lastUpdate = new Dictionary<Entity, int>();
void SendUpdate(RealmTime time)
{
SightTiles = (Owner.Dungeon ? Sight.RayCast(this, RADIUS) : Sight.GetSightCircle(this, RADIUS).ToList());
mapWidth = Owner.Map.Width;
mapHeight = Owner.Map.Height;
var map = Owner.Map;
int _x = (int)X;
int _y = (int)Y;
var sendEntities = new HashSet<Entity>(GetNewEntities());
var list = new List<UpdatePacket.TileData>(APPOX_AREA_OF_SIGHT);
int sent = 0;
foreach (var i in SightTiles)
{
int x = i.X;
int y = i.Y;
WmapTile tile;
if (x < 0 || x >= mapWidth ||
y < 0 || y >= mapHeight ||
tiles[x, y] >= (tile = map[x, y]).UpdateCount) continue;
list.Add(new UpdatePacket.TileData()
{
X = (short)x,
Y = (short)y,
Tile = tile.TileId
});
tiles[x, y] = tile.UpdateCount;
sent++;
}
FameCounter.TileSent(sent);
var dropEntities = GetRemovedEntities().Distinct().ToArray();
clientEntities.RemoveWhere(_ => Array.IndexOf(dropEntities, _.Id) != -1);
foreach (var i in sendEntities)
lastUpdate[i] = i.UpdateCount;
var newStatics = GetNewStatics(_x, _y).ToArray();
var removeStatics = GetRemovedStatics(_x, _y).ToArray();
List<int> removedIds = new List<int>();
foreach (var i in removeStatics)
{
removedIds.Add(Owner.Map[i.X, i.Y].ObjId);
clientStatic.Remove(i);
}
if (sendEntities.Count <= 0 && lis*****unt <= 0 && dropEntities.Length <= 0 && newStatics.Length <= 0 &&
removedIds.Count <= 0) return;
var packet = new UpdatePacket()
{
Tiles = list.ToArray(),
NewObjects = sendEntities.Select(_ => _.ToDefinition()).Concat(newStatics).ToArray(),
RemovedObjectIds = dropEntities.Concat(removedIds).ToArray()
};
Client.SendPacket(packet);
UpdatesSend++;
}
void SendNewTick(RealmTime time)
{
var sendEntities = new List<Entity>();
foreach (var i in clientEntities)
if (i.UpdateCount > lastUpdate[i])
{
sendEntities.Add(i);
lastUpdate[i] = i.UpdateCount;
}
if (Quest != null && (!lastUpdate.ContainsKey(Quest) || Quest.UpdateCount > lastUpdate[Quest]))
{
sendEntities.Add(Quest);
lastUpdate[Quest] = Quest.UpdateCount;
}
var p = new NewTickPacket();
tickId++;
p.TickId = tickId;
p.TickTime = time.thisTickTimes;
p.UpdateStatuses = sendEntities.Select(_ => _.ExportStats()).ToArray();
Client.SendPacket(p);
SightTiles.Clear();
}
}
}
using System;
using System.Collections.Generic;
using wServer.realm.entities.player;
using wServer.realm.terrain;
namespace wServer.realm
{
internal static class Sight
{
private static readonly Dictionary<int, IntPoint[]> points = new Dictionary<int, IntPoint[]>();
public static IntPoint[] GetSightCircle(Player player, int radius)
{
IntPoint[] ret;
if (!points.TryGetValue(radius, out ret))
{
List<IntPoint> pts = new List<IntPoint>();
for (int y = -radius; y <= radius; y++)
for (int x = -radius; x <= radius; x++)
{
if (x * x + y * y <= radius * radius)
pts.Add(new IntPoint(x + (int)player.X, y + (int)player.Y));
}
ret = points[radius] = pts.ToArray();
}
return ret;
}
public static List<IntPoint> RayCast(Player player, int radius)
{
var map = player.Owner.Map;
var Tiles = new List<IntPoint>();
for (var x = -radius; x <= radius; x++)
for (var y = -radius; y <= radius; y++)
if (x * x + y * y <= radius * radius)
{
var lineData = castLine((int)player.X, (int)player.Y, (int)player.X + x, (int)player.Y + y, player);
if (lineData.Item1)
Tiles.Add(new IntPoint(x + (int)player.X, y + (int)player.Y));
else
Tiles.Add(lineData.Item2);
}
for (var x = -1; x <= 1; x++)
for (var y = -1; y <= 1; y++)
Tiles.Add(new IntPoint(x + (int)player.X, y + (int)player.Y));
return Tiles;
}
private static Tuple<bool, IntPoint> castLine(int x, int y, int x2, int y2, Player player)
{
int w = x2 - x;
int h = y2 - y;
int dx1 = 0, dy1 = 0, dx2 = 0, dy2 = 0;
if (w < 0)
dx1 = -1;
else if (w > 0)
dx1 = 1;
if (h < 0)
dy1 = -1;
else if (h > 0)
dy1 = 1;
if (w < 0)
dx2 = -1;
else if (w > 0)
dx2 = 1;
int longest = Math.Abs(w);
int shortest = Math.Abs(h);
if (!(longest > shortest))
{
longest = Math.Abs(h);
shortest = Math.Abs(w);
if (h < 0) dy2 = -1; else if (h > 0) dy2 = 1;
dx2 = 0;
}
int numerator = longest >> 1;
for (int i = 0; i <= longest; i++)
{
var desc = player.Owner.Map[x, y].ObjectDesc;
if (desc != null && desc.BlocksSight)
return Tuple.Create(false, new IntPoint(x, y));
numerator += shortest;
if (!(numerator < longest))
{
numerator -= longest;
x += dx1;
y += dy1;
}
else
{
x += dx2;
y += dy2;
}
}
return Tuple.Create(true, new IntPoint(x, y));
}
}
}

ret = points[radius] = pts.ToArray();