Blocked Sight V2 Tutorial
The code below is made from the source kithio released so if you are using fsod or sd then be sure to take your time adding it in without full on copy and paste as it will not work
Link: http://www.mpgh.net/forum/showthread.php?t=893883
I will be posting the whole file as its easier for people to use.
Files modified were :
Player.Update.cs Located - wServer\realm\entities\player
Sight.cs Located - wServer\realm
World.cs Located - wServer\realm
Wmap.cs Located - wServer\realm\terrain
Note you will need to replace the entire file with the code below
Note this was made with Bresenham line algorithm - https://en.wikipedia.org/wiki/Bresen...line_algorithm, also replace the entire file with the code below
This file you wont need to fully replace but i did add a bool to check if the world is a dungeon
under
To use this inside the world file like Nexus.cs you will do this
This file you will need to replace the entire file as i have modified it to allow for the destructible walls to block the sight as previously i never released a tut on how to do it
Any issues send me a private message on mpgh
Link: http://www.mpgh.net/forum/showthread.php?t=893883
I will be posting the whole file as its easier for people to use.
Files modified were :
Player.Update.cs Located - wServer\realm\entities\player
Sight.cs Located - wServer\realm
World.cs Located - wServer\realm
Wmap.cs Located - wServer\realm\terrain
Player.Update.cs
Note you will need to replace the entire file with the code below
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using wServer.networking.svrPackets;
using wServer.realm.terrain;
namespace wServer.realm.entities
{
public partial class Player
{
public const int RADIUS = 15;
const int APPOX_AREA_OF_SIGHT = (int)(Math.PI * RADIUS * RADIUS + 1);
int mapWidth, mapHeight;
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)
if (clientEntities.Add(i.Value))
yield return i.Value;
foreach (var i in Owner.PlayersCollision.HitTest(X, Y, RADIUS))
if (i is Decoy)
if (clientEntities.Add(i))
yield return i;
foreach (var i in Owner.EnemiesCollision.HitTest(X, Y, RADIUS))
{
if (i is Container)
{
int[] owners = (i as Container).BagOwners;
if (owners.Length > 0 && Array.IndexOf(owners, AccountId) == -1) continue;
}
if (MathsUtils.DistSqr(i.X, i.Y, X, Y) <= RADIUS * RADIUS)
if (clientEntities.Add(i))
yield return i;
}
if (questEntity != null && clientEntities.Add(questEntity))
yield return questEntity;
}
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 != questEntity)
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)tile.TileId
});
tiles[x, y] = tile.UpdateCount;
sent++;
}
fames.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 || list.Count > 0 || dropEntities.Length > 0 || newStatics.Length > 0 || removedIds.Count > 0)
{
client.SendPacket(new UpdatePacket()
{
Tiles = list.ToArray(),
NewObjects = sendEntities.Select(_ => _.ToDefinition()).Concat(newStatics).ToArray(),
RemovedObjectIds = dropEntities.Concat(removedIds).ToArray()
});
}
SendNewTick(time);
}
int tickId = 0;
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 (questEntity != null && (!lastUpdate.ContainsKey(questEntity) || questEntity.UpdateCount > lastUpdate[questEntity]))
{
sendEntities.Add(questEntity);
lastUpdate[questEntity] = questEntity.UpdateCount;
}
client.SendPacket(new NewTickPacket()
{
TickId = tickId++,
TickTime = time.thisTickTimes,
UpdateStatuses = sendEntities.Select(_ => _.ExportStats()).ToArray()
});
SightTiles.Clear();
}
}
}
Sight.cs
Note this was made with Bresenham line algorithm - https://en.wikipedia.org/wiki/Bresen...line_algorithm, also replace the entire file with the code below
Code:
using System;
using System.Collections.Generic;
using wServer.realm.entities;
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));
}
}
}
World.cs
This file you wont need to fully replace but i did add a bool to check if the world is a dungeon
Code:
public bool Dungeon { get; set; }
Code:
public int Background { get; protected set; }
Code:
public Nexus()
{
Id = NEXUS_ID;
Name = "Nexus";
Dungeon = true; // <---- this was added
}
Wmap.cs
This file you will need to replace the entire file as i have modified it to allow for the destructible walls to block the sight as previously i never released a tut on how to do it
Code:
using System;
using System.Collections.Generic;
using System.(IO); // remove the () as mpgh turns it to ****
using Ionic.Zlib;
using wServer.realm.entities;
namespace wServer.realm.terrain
{
public enum TileRegion : byte
{
None,
Spawn,
Realm_Portals,
Store_1,
Store_2,
Store_3,
Store_4,
Store_5,
Store_6,
Store_7,
Store_8,
Store_9,
Vault,
Loot,
Defender,
Hallway,
Hallway_1,
Hallway_2,
Hallway_3,
Enemy,
}
public enum WmapTerrain : byte
{
None,
Mountains,
HighSand,
HighPlains,
HighForest,
MidSand,
MidPlains,
MidForest,
LowSand,
LowPlains,
LowForest,
ShoreSand,
ShorePlains,
}
public struct WmapTile
{
public byte UpdateCount;
public ushort TileId;
public string Name;
public ushort ObjType;
public WmapTerrain Terrain;
public TileRegion Region;
public byte Elevation;
public int ObjId;
public ObjectDesc ObjectDesc;
public ObjectDef ToDef(int x, int y)
{
List<KeyValuePair<StatsType, object>> stats = new List<KeyValuePair<StatsType, object>>();
if (!string.IsNullOrEmpty(Name))
foreach (var item in Name.Split(';'))
{
string[] kv = item.Split(':');
switch (kv[0])
{
case "name":
stats.Add(new KeyValuePair<StatsType, object>(StatsType.Name, kv[1])); break;
case "size":
stats.Add(new KeyValuePair<StatsType, object>(StatsType.Size, Utils.FromString(kv[1]))); break;
case "eff":
stats.Add(new KeyValuePair<StatsType, object>(StatsType.Effects, Utils.FromString(kv[1]))); break;
case "conn":
stats.Add(new KeyValuePair<StatsType, object>(StatsType.ObjectConnection, Utils.FromString(kv[1]))); break;
}
}
return new ObjectDef()
{
ObjectType = ObjType,
Stats = new ObjectStats()
{
Id = ObjId,
Position = new Position()
{
X = x + 0.5f,
Y = y + 0.5f
},
Stats = stats.ToArray()
}
};
}
public WmapTile Clone()
{
return new WmapTile()
{
UpdateCount = (byte)(UpdateCount + 1),
TileId = TileId,
Name = Name,
ObjType = ObjType,
Terrain = Terrain,
Region = Region,
ObjId = ObjId,
ObjectDesc = ObjectDesc
};
}
}
public class Wmap
{
XmlData dat;
public Wmap(XmlData dat)
{
this.dat = dat;
}
public int Width { get; set; }
public int Height { get; set; }
WmapTile[,] tiles;
public WmapTile this[int x, int y]
{
get { return tiles[x, y]; }
set { tiles[x, y] = value; }
}
Tuple<IntPoint, ushort, string>[] entities;
public int Load(Stream stream, int idBase)
{
int ver = stream.ReadByte();
using (BinaryReader rdr = new BinaryReader(new ZlibStream(stream, CompressionMode.Decompress)))
{
if (ver == 0) return LoadV0(rdr, idBase);
else if (ver == 1) return LoadV1(rdr, idBase);
else if (ver == 2) return LoadV2(rdr, idBase);
else throw new NotSupportedException("WMap version " + ver);
}
}
int LoadV0(BinaryReader reader, int idBase)
{
List<WmapTile> dict = new List<WmapTile>();
short c = reader.ReadInt16();
for (short i = 0; i < c; i++)
{
WmapTile tile = new WmapTile();
tile.TileId = reader.ReadUInt16();
string obj = reader.ReadString();
tile.ObjType = string.IsNullOrEmpty(obj) ? (ushort)0 : dat.IdToObjectType[obj];
tile.Name = reader.ReadString();
tile.Terrain = (WmapTerrain)reader.ReadByte();
tile.Region = (TileRegion)reader.ReadByte();
dat.ObjectDescs.TryGetValue(tile.ObjType, out tile.ObjectDesc);
dict.Add(tile);
}
Width = reader.ReadInt32();
Height = reader.ReadInt32();
tiles = new WmapTile[Width, Height];
int enCount = 0;
List<Tuple<IntPoint, ushort, string>> entities = new List<Tuple<IntPoint, ushort, string>>();
for (int y = 0; y < Height; y++)
for (int x = 0; x < Width; x++)
{
WmapTile tile = dict[reader.ReadInt16()];
tile.UpdateCount = 1;
var desc = tile.ObjectDesc;
if (tile.ObjType != 0 && (desc == null || !desc.Static || desc.Enemy))
{
entities.Add(new Tuple<IntPoint, ushort, string>(new IntPoint(x, y), tile.ObjType, tile.Name));
tile.ObjType = 0;
}
if (tile.ObjType != 0)
{
enCount++;
tile.ObjId = idBase + enCount;
}
tiles[x, y] = tile;
}
this.entities = entities.ToArray();
return enCount;
}
int LoadV1(BinaryReader reader, int idBase)
{
List<WmapTile> dict = new List<WmapTile>();
short c = reader.ReadInt16();
for (short i = 0; i < c; i++)
{
WmapTile tile = new WmapTile();
tile.TileId = reader.ReadUInt16();
string obj = reader.ReadString();
tile.ObjType = string.IsNullOrEmpty(obj) ? (ushort)0 : dat.IdToObjectType[obj];
tile.Name = reader.ReadString();
tile.Terrain = (WmapTerrain)reader.ReadByte();
tile.Region = (TileRegion)reader.ReadByte();
tile.Elevation = reader.ReadByte();
dat.ObjectDescs.TryGetValue(tile.ObjType, out tile.ObjectDesc);
dict.Add(tile);
}
Width = reader.ReadInt32();
Height = reader.ReadInt32();
tiles = new WmapTile[Width, Height];
int enCount = 0;
List<Tuple<IntPoint, ushort, string>> entities = new List<Tuple<IntPoint, ushort, string>>();
for (int y = 0; y < Height; y++)
for (int x = 0; x < Width; x++)
{
WmapTile tile = dict[reader.ReadInt16()];
tile.UpdateCount = 1;
var desc = tile.ObjectDesc;
if (tile.ObjType != 0 && (desc == null || !desc.Static || desc.Enemy))
{
entities.Add(new Tuple<IntPoint, ushort, string>(new IntPoint(x, y), tile.ObjType, tile.Name));
tile.ObjType = 0;
}
if (tile.ObjType != 0)
{
enCount++;
tile.ObjId = idBase + enCount;
}
tiles[x, y] = tile;
}
this.entities = entities.ToArray();
return enCount;
}
int LoadV2(BinaryReader reader, int idBase)
{
List<WmapTile> dict = new List<WmapTile>();
short c = reader.ReadInt16();
for (short i = 0; i < c; i++)
{
WmapTile tile = new WmapTile();
tile.TileId = reader.ReadUInt16();
string obj = reader.ReadString();
tile.ObjType = string.IsNullOrEmpty(obj) ? (ushort)0 : dat.IdToObjectType[obj];
tile.Name = reader.ReadString();
tile.Terrain = (WmapTerrain)reader.ReadByte();
tile.Region = (TileRegion)reader.ReadByte();
dat.ObjectDescs.TryGetValue(tile.ObjType, out tile.ObjectDesc);
dict.Add(tile);
}
Width = reader.ReadInt32();
Height = reader.ReadInt32();
tiles = new WmapTile[Width, Height];
int enCount = 0;
List<Tuple<IntPoint, ushort, string>> entities = new List<Tuple<IntPoint, ushort, string>>();
for (int y = 0; y < Height; y++)
for (int x = 0; x < Width; x++)
{
WmapTile tile = dict[reader.ReadInt16()];
tile.UpdateCount = 1;
tile.Elevation = reader.ReadByte();
var desc = tile.ObjectDesc;
if (tile.ObjType != 0 && (desc == null || !desc.Static || desc.Enemy))
{
entities.Add(new Tuple<IntPoint, ushort, string>(new IntPoint(x, y), tile.ObjType, tile.Name));
tile.ObjType = 0;
}
if (tile.ObjType != 0)
{
enCount++;
tile.ObjId = idBase + enCount;
}
tiles[x, y] = tile;
}
this.entities = entities.ToArray();
return enCount;
}
public IEnumerable<Entity> InstantiateEntities(RealmManager manager)
{
foreach (var i in entities)
{
var entity = Entity.Resolve(manager, i.Item2);
entity.Move(i.Item1.X + 0.5f, i.Item1.Y + 0.5f);
if (i.Item3 != null)
foreach (var item in i.Item3.Split(';'))
{
string[] kv = item.Split(':');
switch (kv[0])
{
case "name":
entity.Name = kv[1]; break;
case "size":
entity.Size = Utils.FromString(kv[1]); break;
case "eff":
entity.ConditionEffects = (ConditionEffects)Utils.FromString(kv[1]); break;
case "conn":
(entity as ConnectedObject).Connection = ConnectionInfo.Infos[(uint)Utils.FromString(kv[1])]; break;
}
}
yield return entity;
}
}
}
}
Any issues send me a private message on mpgh


