Quote:
Originally Posted by Arcо
Without seeing any code that relates to this, it'll be hard for us to help pinpoint the cause of the issue.
|
Well, the base Redux source has the issue (or albetros) - it's hard to pinpoint the exact piece of code that's causing the problem.
It could be a Network/Synch issue, or something wrong in the logic.. If UpdateSurroundings in the Entity class is set (true) it will constantly reset visibility - but respawning the entities on every jump is certainly not appropriate. I can't increase the visible range more than 18 in map class. I've tried handling corners (unless I did it wrong). I've tried adding a visibility buffer > 18 to force a reset.. I dunno, I can't see what I haven't tried or what I'm missing :D
Player.cs
Code:
public void HandleJump(GeneralActionPacket packet)
{
if (Life <= 0)
{
return;
}
if (Common.MapService.Valid((ushort)Map.ID, X, Y, packet.Data1Low, packet.Data1High))
{
X = packet.Data1Low;
Y = packet.Data1High;
OnMove();
SendToScreen(packet, true);
UpdateSurroundings();
if (Pet != null && Common.Clock - Pet.LastMove > 900)
Pet.LastMove = Common.Clock + 300;
}
else
Send(new GeneralActionPacket()
{
UID = this.UID,
Data1 = Map.ID,
Data2Low = X,
Data2High = Y,
Action = DataAction.NewCoordinates,
});
}
Entity.cs:
Code:
public void UpdateSurroundings(bool clear = false)
{
if (clear)
VisibleObjects = new ConcurrentDictionary<uint, uint>();
List<uint> newObjects = new List<uint>();
foreach (var target in Map.QueryScreen(this))
if (target.UID != UID)
newObjects.Add(target.UID);
//Remove existing objects if they are no longer visible
var visibleObjectsToRemove = VisibleObjects.Keys.Except(newObjects).ToList();
foreach (var id in visibleObjectsToRemove)
MapManager.DespawnByUID(this, id);
//Remove new objects if they exist already
foreach (var id in VisibleObjects.Keys)
if (newObjects.Contains(id))
newObjects.Remove(id);
//Spawn new objects
foreach (var id in newObjects)
MapManager.SpawnByUID(this, id);
}
MapManager.cs:
Code:
public static void DespawnByUID(Entity p, uint id)
{
var t = p.Map.Search(id);
if (t == null || t == p)
return;
if (p is Player && t is Monster)//Player can no longer see monster
{
var m = (Monster)t;
var found = false;
foreach (var objID in m.VisibleObjects)
if (objID.Key > 1000000)
{ found = true; break; }
if (found)
m.IsActive = true;
else
{
var isSpawnActive = false;
foreach (var spawnMember in m.Owner.AliveMembers.Values)
if (spawnMember.IsActive)
{ isSpawnActive = true; break; }
m.Owner.IsActive = isSpawnActive;
}
m.IsActive = found;
}
if (t is Entity)
{
var target = t as Entity;
if (target.VisibleObjects != null && target.VisibleObjects.ContainsKey(p.UID))
{
uint x;
target.VisibleObjects.TryRemove(p.UID, out x);
}
}
if (p.VisibleObjects != null && p.VisibleObjects.ContainsKey(t.UID))
{
uint x;
p.VisibleObjects.TryRemove(t.UID, out x);
}
}
/// <summary>
/// Spawn entities to eachother as well as spawning basic objects (items, npcs, sobs, traps) to players
/// </summary>
/// <param name="p">player to see spawned objects</param>
/// <param name="id">uid of object to spawn</param>
public static void SpawnByUID(Entity p, uint id)
{
var sob = p.Map.Search<SOB>(id);
if (sob != null)
{
if (p is Player && !p.VisibleObjects.ContainsKey(sob.UID))
{
((Player)p).Send(Packets.Game.SpawnSob.Create(sob));
p.VisibleObjects.TryAdd(sob.UID, sob.UID);
}
return;
}
var target = p.Map.Search<Entity>(id);
if (target != sob && target != null && target != p)
{
if (!p.VisibleObjects.ContainsKey(target.UID))
{
p.VisibleObjects.TryAdd(target.UID, target.UID);
p.Send(target.SpawnPacket);
}
if (!target.VisibleObjects.ContainsKey(p.UID))
{
if (p is Player && target is Monster)
{
var m = (Monster)target;
if (m.Owner != null)
{
m.IsActive = true;
m.Owner.IsActive = true;
}
}
target.VisibleObjects.TryAdd(p.UID, p.UID);
if (p is Player && target is Player)
{
if (!p.VisibleObjects.ContainsKey(target.UID))
{
p.VisibleObjects.TryAdd(target.UID, target.UID);
p.Send(target.SpawnPacket);
}
}
target.Send(p.SpawnPacket);
if (target is Player && p is Player)
if ((target as Player).Shop != null && (target as Player).Shop.Vending && (target as Player).Shop.HawkMsg.Words.Length > 1)
p.Send((target as Player).Shop.HawkMsg);
}
return;
}
var npc = p.Map.Search<Npc>(id);
if (npc != null)
{
if (p is Player && !p.VisibleObjects.ContainsKey(npc.UID))
{
((Player)p).Send(npc.SpawnPacket);
p.VisibleObjects.TryAdd(npc.UID, npc.UID);
}
return;
}
var item = p.Map.Search<GroundItem>(id);
if (item != null)
{
if (p is Player && !p.VisibleObjects.ContainsKey(item.UID))
{
((Player)p).Send(item.SpawnPacket);
p.VisibleObjects.TryAdd(item.UID, item.UID);
}
return;
}
}
Map.cs:
Code:
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using Redux.Utility;
using Redux.Database;
using Redux.Database.Domain;
using Redux.Game_Server;
using Redux.Managers;
using Redux.Enum;
namespace Redux.Space
{
#region Map Class
public class Map
{
#region Variables
public bool IsActive = true;
private List<DbDropRule> _mineRules;
public List<DbDropRule> MineRules { get { return _mineRules; } }
public uint ID { get; private set; }
public uint DynamicID { get; private set; }
public DbMap MapInfo { get; private set; }
public ConcurrentDictionary<uint, ILocatableObject> Objects { get; private set; }
public List<SpawnManager> Spawns { get; private set; }
public ThreadSafeCounter ItemCounter, MobCounter, SobCounter, PetCounter;
#endregion
#region Constructor
/// <summary>
/// Initialize a new Map
/// </summary>
/// <param name="dynamicID">Key to identify map</param>
/// <param name="id">Dmap value of map. Used for all movement checks</param>
public Map(uint _dynamicID, uint _id)
{
Objects = new ConcurrentDictionary<uint, ILocatableObject>();
ItemCounter = new ThreadSafeCounter(100000, 150000);
SobCounter = new ThreadSafeCounter(150000, 200000);
MobCounter = new ThreadSafeCounter(400000, 500000);
PetCounter = new ThreadSafeCounter(500000, 600000);
MapInfo = ServerDatabase.Context.Maps.GetById(_id);
ID = _id;
DynamicID = _dynamicID;
var dNpcs = ServerDatabase.Context.Npcs.GetNpcsByMap((ushort)_dynamicID);
if (dNpcs.Count > 0)
foreach (var dNpc in dNpcs)
Insert(new Npc(dNpc, this));
var dSpawns = ServerDatabase.Context.Spawns.GetSpawnsByMap((ushort)_dynamicID);
Spawns = new List<SpawnManager>();
if (dSpawns.Count > 0)
foreach (var dSpawn in dSpawns)
Spawns.Add(new SpawnManager(dSpawn, this));
foreach (var dSob in ServerDatabase.Context.SOB.GetSOBByMap((ushort)_dynamicID))
Insert(new SOB(dSob));
if (MapInfo.Type.HasFlag(MapTypeFlags.MineEnable))
_mineRules = ServerDatabase.Context.DropRules.GetRulesByMonsterType(ID).ToList();
Console.WriteLine("Map ID {0} loaded {1} npcs and {2} spawns", _dynamicID, dNpcs.Count, dSpawns.Count);
}
#endregion
#region Functions
public bool IsTGMap { get { return ID == 1039; } }
public bool IsNoScrollEnabled { get { return MapInfo.Type.HasFlag(Enum.MapTypeFlags.TeleportDisable); } }
public bool IsFlyEnabled { get { return !MapInfo.Type.HasFlag(Enum.MapTypeFlags.FlyDisable); } }
public bool IsPKEnabled { get { return !MapInfo.Type.HasFlag(Enum.MapTypeFlags.PkDisable); } }
public bool IsNeverWound { get { return MapInfo.Type.HasFlag(Enum.MapTypeFlags.NeverWound); } }
public bool IsFreePK { get { return MapInfo.Type.HasFlag(Enum.MapTypeFlags.PkField) || MapInfo.Type.HasFlag(Enum.MapTypeFlags.FreePk); } }
public bool IsGuildMap { get { return MapInfo.Type.HasFlag(Enum.MapTypeFlags.GuildMap); } }
public IEnumerable<ILocatableObject> QueryScreen(ILocatableObject objCenter)
{
var area = GetEntityScreenArea(objCenter);
var query = from x in Objects.Values
where area.AreaContains(x.Location)
select x;
return query;
}
public IEnumerable<T> QueryScreen<T>(ILocatableObject objCenter)
{
var area = GetEntityScreenArea(objCenter);
var query = from x in Objects.Values
where area.AreaContains(x.Location) && x is T
select (T)x;
return query;
}
public IEnumerable<T> QueryBox<T>(ILocatableObject _objCenter, int _size)
{
var area = new Rectangle(new Point(_objCenter.Location.X - _size, _objCenter.Location.Y - _size), _size * 2, _size * 2);
var query = from x in Objects.Values
where area.AreaContains(x.Location) && x is T
select (T)x;
return query;
}
public IEnumerable<Entity> QueryBox(int _x, int _y, int _width, int _height)
{
var area = new Rectangle(_x, _y, _width, _height);
var query = from x in Objects.Values
where area.AreaContains(x.Location) && x is Entity
select x as Entity;
return query;
}
public IEnumerable<Game_Server.Player> QueryPlayers(ILocatableObject objCenter)
{
var area = GetEntityScreenArea(objCenter);
var query = from x in Objects.Values
where area.AreaContains(x.Location) && x is Game_Server.Player
select x as Game_Server.Player;
return query;
}
public Rectangle GetEntityScreenArea(ILocatableObject objCenter)
{
int visibilityRange = 18; // This can be adjusted
return new Rectangle(new Point(objCenter.Location.X - visibilityRange, objCenter.Location.Y - visibilityRange), 2 * visibilityRange, 2 * visibilityRange);
}
public bool Insert(ILocatableObject obj)
{
if (obj == null)
return false;
if (Objects.ContainsKey(obj.UID))
return false;
obj.Map = this;
Objects.TryAdd(obj.UID, obj);
return true;
}
public bool Remove(ILocatableObject obj, bool updatelocal = true)
{
if (updatelocal)
{
if (obj is Entity)
{
var entity = obj as Entity;
entity.SendToScreen(new Packets.Game.GeneralActionPacket() { UID = entity.UID, Action = Enum.DataAction.RemoveEntity });
foreach (var id in entity.VisibleObjects.Keys)
Managers.MapManager.DespawnByUID(entity, id);
}
}
return Objects.TryRemove(obj.UID, out obj);
}
public ILocatableObject Search(uint uid)
{
lock (Objects)
{
var query = from x in Objects.Values
where x.UID == uid
select x;
return query.FirstOrDefault();
}
}
public T Search<T>(uint id)
where T : ILocatableObject
{
if (id != 0)
foreach (var target in Objects)
if (target.Value is T)
if (target.Key == id)
return (T)target.Value;
return default(T);
}
public IEnumerable<KeyValuePair<uint, ILocatableObject>> Select(Func<KeyValuePair<uint, ILocatableObject>, bool> predicate)
{
return Objects.Where(predicate);
}
public bool IsValidMonsterLocation(Point location)
{
return Common.MapService.Valid((ushort)ID, (ushort)location.X, (ushort)location.Y) && !Common.MapService.HasFlag((ushort)ID, (ushort)location.X, (ushort)location.Y, TinyMap.TileFlag.Monster);
}
public bool IsValidItemLocation(Point location)
{
return Common.MapService.Valid((ushort)ID, (ushort)location.X, (ushort)location.Y) && !Common.MapService.HasFlag((ushort)ID, (ushort)location.X, (ushort)location.Y, TinyMap.TileFlag.Item);
}
public bool IsValidPlayerLocation(Point location)
{
return Common.MapService.Valid((ushort)ID, (ushort)location.X, (ushort)location.Y);
}
#endregion
}
#endregion
}