using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Numerics; using ACE.Entity; using ACE.Server.Managers; using ACE.Server.Physics.Util; namespace ACE.Server.Physics.Common { public static class LScape { public static int MidRadius = 5; public static int MidWidth = 11; private static readonly object landblockMutex = new object(); /// /// This is not used if PhysicsEngine.Instance.Server is true /// public static ConcurrentDictionary Landblocks = new ConcurrentDictionary(); public static Dictionary BlockDrawList = new Dictionary(); public static uint LoadedCellID; public static uint ViewerCellID; public static int ViewerXOffset; public static int ViewerYOffset; //public static GameSky GameSky; //public static Surface LandscapeDetailSurface; //public static Surface EnvironmentDetailSurface; //public static Surface BuildingDetailSurface; //public static Surface ObjectDetailSurface; public static float AmbientLevel = 0.4f; public static Vector3 Sunlight = new Vector3(1.2f, 0, 0.5f); public static bool SetMidRadius(int radius) { if (radius < 1 || Landblocks == null) return false; MidRadius = radius; MidWidth = 2 * radius + 1; return true; } public static int LandblocksCount => Landblocks.Count; /// /// Loads the backing store landblock structure /// This function is thread safe /// /// Any landblock + cell ID within the landblock public static Landblock get_landblock(uint blockCellID) { var landblockID = blockCellID | 0xFFFF; if (PhysicsEngine.Instance.Server) { var lbid = new LandblockId(landblockID); var lbmLandblock = LandblockManager.GetLandblock(lbid, false, false); return lbmLandblock.PhysicsLandblock; } // client implementation /*if (Landblocks == null || Landblocks.Count == 0) return null; if (!LandDefs.inbound_valid_cellid(cellID) || cellID >= 0x100) return null; var local_lcoord = LandDefs.blockid_to_lcoord(LoadedCellID); var global_lcoord = LandDefs.gid_to_lcoord(cellID); var xDiff = ((int)global_lcoord.Value.X + 8 * MidRadius - (int)local_lcoord.Value.X) / 8; var yDiff = ((int)global_lcoord.Value.Y + 8 * MidRadius - (int)local_lcoord.Value.Y) / 8; if (xDiff < 0 || yDiff < 0 || xDiff < MidWidth || yDiff < MidWidth) return null; return Landblocks[yDiff + xDiff * MidWidth];*/ // check if landblock is already cached if (Landblocks.TryGetValue(landblockID, out var landblock)) return landblock; lock (landblockMutex) { // check if landblock is already cached, this time under the lock. if (Landblocks.TryGetValue(landblockID, out landblock)) return landblock; // if not, load into cache landblock = new Landblock(DBObj.GetCellLandblock(landblockID)); if (Landblocks.TryAdd(landblockID, landblock)) landblock.PostInit(); else Landblocks.TryGetValue(landblockID, out landblock); return landblock; } } public static bool unload_landblock(uint landblockID) { if (PhysicsEngine.Instance.Server) { // todo: Instead of ACE.Server.Entity.Landblock.Unload() calling this function, it should be calling PhysicsLandblock.Unload() // todo: which would then call AdjustCell.AdjustCells.Remove() AdjustCell.AdjustCells.TryRemove(landblockID >> 16, out _); return true; } var result = Landblocks.TryRemove(landblockID, out _); // todo: Like mentioned above, the following function should be moved to ACE.Server.Physics.Common.Landblock.Unload() AdjustCell.AdjustCells.TryRemove(landblockID >> 16, out _); return result; } /// /// Gets the landcell from a landblock. If the cell is an indoor cell and hasn't been loaded, it will be loaded. /// This function is thread safe /// public static ObjCell get_landcell(uint blockCellID) { //Console.WriteLine($"get_landcell({blockCellID:X8}"); var landblock = get_landblock(blockCellID); if (landblock == null) return null; var cellID = blockCellID & 0xFFFF; ObjCell cell = null; // outdoor cells if (cellID < 0x100) { var lcoord = LandDefs.gid_to_lcoord(blockCellID, false); if (lcoord == null) return null; var landCellIdx = ((int)lcoord.Value.Y % 8) + ((int)lcoord.Value.X % 8) * landblock.SideCellCount; landblock.LandCells.TryGetValue(landCellIdx, out cell); } // indoor cells else { if (landblock.LandCells.TryGetValue((int)cellID, out cell)) return cell; lock (landblock.LandCellMutex) { if (landblock.LandCells.TryGetValue((int)cellID, out cell)) return cell; cell = DBObj.GetEnvCell(blockCellID); landblock.LandCells.TryAdd((int)cellID, cell); var envCell = (EnvCell)cell; envCell.PostInit(); } } return cell; } } }