using System.Collections.Generic; using System.Linq; using Global.Patches; using Global.Shared.API; using Global.Shared.Events; using Global.Shared.OcTree.Data; using Global.Shared.Plugin; using Sandbox.Game.Entities; using VRage.Game.Components; using VRage.Game.Entity; using VRage.Game.ModAPI; namespace Global.Shared.OcTree { public class OcTreeHandler { public GenericOcTree GridTree { get; private set; } public GenericOcTree CharacterTree { get; private set; } internal void Init() { var cfg = GlobalInstance.Config; var offset = cfg.CenterPosition; var x = cfg.Size; var y = cfg.Size; var z = cfg.Size; GridTree = new GenericOcTree(offset.X - x, offset.Y - y, offset.Z - z, x * 2, y * 2, z * 2, cfg.Capacity, cfg.MaxDepth); CharacterTree = new GenericOcTree(offset.X - x, offset.Y - y, offset.Z - z, x * 2, y * 2, z * 2, cfg.Capacity, cfg.MaxDepth); BlockEvents.OnPlayerControlAcquired += AddControllableEntity; BlockEvents.OnPlayerControlReleased += RemoveControllableEntity; } public IGridData AddGrid(MyCubeGrid grid) { var bigOwner = grid.BigOwners.Count == 0 ? "No Owner!" : grid.BigOwners.First().ToString(); // check if grid is new subgrid if (MyMechanicalConnectionBlockBasePatch.IsCreatingSubPart) { GlobalInstance.Log.Trace( $"Grid is subgrid, ignoring {grid.DisplayName} {grid.PositionComp.GetPosition()} {bigOwner}"); return null; } if (!GridTree.Contains(grid.EntityId)) { var grids = grid.GetGridGroup(GridLinkTypeEnum.Mechanical).GetGrids(new List()); var largestGrid = grid; if (grids.Count > 1) foreach (var g in grids.Cast()) if (g.BlocksCount > largestGrid.BlocksCount) largestGrid = g; grid = largestGrid; //GlobalInstance.Log.Info( //$"Adding grid to OcTree: {grid.EntityId} {grid.DisplayName} {grid.PositionComp.GetPosition()}"); var data = new GridData(grid); grid.PositionComp.OnPositionChanged += Grid_OnPositionChanged; grid.OnMarkForClose += RemoveGrid; grid.OnTeleported += Grid_OnChanged; GridTree.Insert(data); grid.OnConnectionChanged += Grid_OnConnectionChanged; GridEvents.GridCreated?.Invoke(grid); return data; } GlobalInstance.Log.Debug( $"Attempted to add grid to OcTree that already exists, {grid.DisplayName} {grid.PositionComp.GetPosition()} {bigOwner}"); var existing = GridTree[grid.EntityId]; if (existing != null) return existing; GridTree.Remove(grid.EntityId); return AddGrid(grid); } public void AddControllableEntity(IMyControllableEntity entity) { if (entity.ControllerInfo?.Controller?.Player == null && !(entity is IMyCharacter)) //GlobalInstance.Log.Info($"Entity is not controlled {entity.Entity.EntityId} {entity.Entity.DisplayName}"); return; //GlobalInstance.Log.Debug($"AddControllableEntity {entity.Entity.EntityId} {entity.Entity.DisplayName}"); entity.Entity.OnMarkForClose += RemoveControllableEntity; var data = new ControllableEntityData(entity); if (!CharacterTree.Contains(entity.Entity.EntityId)) CharacterTree.Insert(data); } public void RemoveControllableEntity(IMyControllableEntity entity) { RemoveControllableEntity((MyEntity)entity); } public void RemoveControllableEntity(MyEntity entity) { //GlobalInstance.Log.Debug("RemoveControllableEntity"); CharacterTree.Remove(entity.EntityId); } private void Grid_OnConnectionChanged(MyCubeGrid arg1, GridLinkTypeEnum arg2) { if (arg2 != GridLinkTypeEnum.Mechanical) return; GridTree.Update(arg1.EntityId); } internal void RemoveGrid(MyEntity grid) { GlobalInstance.Log.Debug($"Removing grid from OcTree: {grid.EntityId} {grid.DisplayName}"); GridEvents.GridRemoved?.Invoke(grid as MyCubeGrid); grid.PositionComp.OnPositionChanged -= Grid_OnPositionChanged; grid.OnMarkForClose -= RemoveGrid; grid.OnTeleported -= Grid_OnChanged; GridTree.Remove(grid.EntityId); } private void Grid_OnChanged(MyEntity obj) { GridTree.Update(obj.EntityId); } private void Grid_OnPositionChanged(MyPositionComponentBase obj) { if (!(obj.Entity is MyCubeGrid grid)) return; if (grid.Closed || grid.MarkedForClose) return; GridTree.Update(grid.EntityId); } } }