private void Actual_OnBlockRemoved(IMySlimBlock obj) { SeenHolo sh; if (!m_holoEntities.TryGetValue(obj.CubeGrid.EntityId, out sh)) { Log.DebugLog("failed lookup of grid: " + obj.CubeGrid.DisplayName, Logger.severity.ERROR); obj.CubeGrid.OnBlockAdded -= Actual_OnBlockAdded; obj.CubeGrid.OnBlockRemoved -= Actual_OnBlockRemoved; return; } Vector3I position = obj.Position; IMyCubeGrid holo = (IMyCubeGrid)sh.Holo; holo.RemoveBlock(holo.GetCubeBlock(position)); }
/// <summary> /// Updates the appearance of the block if the integrity has changed. Only used for welding/griding. /// </summary> private static void UpdateBlockModel(IMySlimBlock realBlock, IMyCubeGrid holoGrid) { IMySlimBlock holoBlock = holoGrid.GetCubeBlock(realBlock.Position); Logger.DebugLog("holoBlock == null", Logger.severity.FATAL, condition: holoBlock == null); float realIntegrityRatio = (realBlock.BuildIntegrity - realBlock.CurrentDamage) / realBlock.MaxIntegrity; float holoIntegrityRatio = (holoBlock.BuildIntegrity - holoBlock.CurrentDamage) / holoBlock.MaxIntegrity; if (realIntegrityRatio == holoIntegrityRatio) { return; } float min, max; if (realIntegrityRatio > holoIntegrityRatio) { max = realIntegrityRatio; min = holoIntegrityRatio; } else { max = holoIntegrityRatio; min = realIntegrityRatio; } if (((MyCubeBlockDefinition)realBlock.BlockDefinition).ModelChangeIsNeeded(min, max)) { holoGrid.RemoveBlock(holoBlock); MyObjectBuilder_CubeBlock objBuilder = realBlock.GetObjectBuilder(); objBuilder.EntityId = 0L; holoGrid.AddBlock(objBuilder, false); IMyCubeBlock cubeBlock = holoGrid.GetCubeBlock(realBlock.Position).FatBlock; if (cubeBlock != null) { SetupProjection(cubeBlock); } } }
/// <summary> /// Updates the appearance of the block if the integrity has changed. Only used for welding/griding. /// </summary> private static void UpdateBlockModel(IMySlimBlock realBlock, IMyCubeGrid holoGrid) { IMySlimBlock holoBlock = holoGrid.GetCubeBlock(realBlock.Position); Static.logger.debugLog(holoBlock == null, "holoBlock == null", Logger.severity.FATAL); float realIntegrityRatio = (realBlock.BuildIntegrity - realBlock.CurrentDamage) / realBlock.MaxIntegrity; float holoIntegrityRatio = (holoBlock.BuildIntegrity - holoBlock.CurrentDamage) / holoBlock.MaxIntegrity; if (realIntegrityRatio == holoIntegrityRatio) return; float min, max; if (realIntegrityRatio > holoIntegrityRatio) { max = realIntegrityRatio; min = holoIntegrityRatio; } else { max = holoIntegrityRatio; min = realIntegrityRatio; } if (((MyCubeBlockDefinition)realBlock.BlockDefinition).ModelChangeIsNeeded(min, max)) { holoGrid.RemoveBlock(holoBlock); MyObjectBuilder_CubeBlock objBuilder = realBlock.GetObjectBuilder(); objBuilder.EntityId = 0L; holoGrid.AddBlock(objBuilder, false); IMyCubeBlock cubeBlock = holoGrid.GetCubeBlock(realBlock.Position).FatBlock; if (cubeBlock != null) SetupProjection(cubeBlock); } }
// // == SessionComponent Hooks // public override void UpdateBeforeSimulation() { try { if (MyAPIGateway.Session == null || MyAPIGateway.Utilities == null || MyAPIGateway.Multiplayer == null) // exit if api is not ready { return; } if (!Inited) // init and set handlers { Init(); } if (Settings == null) // request or load setting { GetSettings(); // if server, settings will be set a this call, so it safe } if (!IsServer) // if client exit at this point. Cleaning works only on server side. { return; } if (Frame++ % 10 == 0) { HashSet <IMyEntity> entities = new HashSet <IMyEntity>(); MyAPIGateway.Entities.GetEntities(entities, x => x is IMyCubeGrid); foreach (IMyEntity entity in entities) { IMyCubeGrid grid = entity as IMyCubeGrid; if (grid == null) { continue; } // if this grid have an active BS, then turn off destructible for grid gridDestructible(grid, !isActiveBeaconSecurity(grid)); if (!eventedGrids.Contains(grid)) { // skip if already added actions grid.OnBlockAdded += BuildHandler.grid_OnBlockAdded; eventedGrids.Add(grid); Logger.Log.Debug("OnBlockAdded event added to {0} grids.", grid.EntityId); } } // Remove block from queues foreach (var block in queueRemoveBlocks) { IMyCubeGrid grid = block.CubeGrid as IMyCubeGrid; if (grid == null) { continue; } grid.RemoveBlock(block, true); if (block.FatBlock != null) { block.FatBlock.Close(); } } queueRemoveBlocks.Clear(); } if (Settings.CleaningFrequency == 0) { return; } #region Cleanup if ((DateTime.Now - m_cleaning).TotalSeconds > Settings.CleaningFrequency) // Cleaning by frequency { Logger.Log.Debug("Time for cleaning, from last {0} secs elapsed.", (DateTime.Now - m_cleaning).TotalSeconds); m_cleaning = DateTime.Now; HashSet <IMyEntity> entities = new HashSet <IMyEntity>(); MyAPIGateway.Entities.GetEntities(entities, x => x is IMyCubeGrid); int removed = 0; List <IMySlimBlock> ToRemove = new List <IMySlimBlock>(); HashSet <long> AlreadyCounted = new HashSet <long>(); Dictionary <long, long[]> PerFactionCount = new Dictionary <long, long[]>(); Dictionary <long, long[]> PerPlayerCount = new Dictionary <long, long[]>(); foreach (IMyCubeGrid grid in entities) { var blocks = new List <IMySlimBlock>(); grid.GetBlocks(blocks, x => x.FatBlock != null); foreach (IMySlimBlock block in blocks) { //Logger.Log.Debug("Check block {0} {1}", block.FatBlock.DisplayNameText, block.FatBlock.ToString()); BeaconSecurity bs = block.FatBlock.GameLogic as BeaconSecurity; if (bs == null || !bs.IsBeaconSecurity || bs.OwnerId == 0) { continue; } if (!AlreadyCounted.Contains(block.FatBlock.EntityId)) { AlreadyCounted.Add(block.FatBlock.EntityId); } else { continue; } // Priority for players limit. if (!PerPlayerCount.ContainsKey(bs.OwnerId)) // if there no counts, add it { PerPlayerCount[bs.OwnerId] = new long[] { 0, 0 } } ; PerPlayerCount[bs.OwnerId][0]++; if (bs.OwnerId != 0 && PerPlayerCount[bs.OwnerId][0] > Settings.LimitPerPlayer) { PerPlayerCount[bs.OwnerId][1]++; ToRemove.Add(block); continue; } IMyFaction faction = MyAPIGateway.Session.Factions.TryGetPlayerFaction(bs.OwnerId); if (faction != null) { if (!PerFactionCount.ContainsKey(faction.FactionId)) { PerFactionCount[faction.FactionId] = new long[] { 0, 0 } } ; PerFactionCount[faction.FactionId][0]++; if (PerFactionCount[faction.FactionId][0] > Settings.LimitPerFaction) { PerFactionCount[faction.FactionId][1]++; ToRemove.Add(block); } } } foreach (IMySlimBlock block in ToRemove) { grid.RemoveBlock(block, true); } removed += ToRemove.Count; ToRemove.Clear(); } List <IMyPlayer> players = new List <IMyPlayer>(); MyAPIGateway.Players.GetPlayers(players); // Send warn message about cleaning and restrictions! foreach (long ownerId in PerPlayerCount.Keys) { if (ownerId == 0 || PerPlayerCount[ownerId][1] == 0) { continue; } IMyPlayer player = players.FirstOrDefault(x => x.PlayerID == ownerId); if (player == null) { continue; } SyncPacket pckOut = new SyncPacket(); pckOut.proto = SyncPacket.Version; pckOut.command = (ushort)Command.MessageToChat; pckOut.message = string.Format("Removed {0} entity as a result of limitations on the amount {1} per player.", PerPlayerCount[ownerId][1], Settings.LimitPerPlayer); Core.SendMessage(pckOut, player.SteamUserId); } foreach (long factionId in PerFactionCount.Keys) { if (PerFactionCount[factionId][1] == 0) { continue; } IMyFaction faction = MyAPIGateway.Session.Factions.TryGetFactionById(factionId); if (faction == null) { continue; } foreach (var member in faction.Members) { IMyPlayer player = players.FirstOrDefault(x => x.PlayerID == member.Key); if (player == null) { continue; } SyncPacket pckOut = new SyncPacket(); pckOut.proto = SyncPacket.Version; pckOut.command = (ushort)Command.MessageToChat; pckOut.message = string.Format("Removed {0} entity as a result of limitations on the amount {1} per faction.", PerFactionCount[factionId][1], Settings.LimitPerFaction); Core.SendMessage(pckOut, player.SteamUserId); } } if (removed > 0) { Logger.Log.Info("Cleaning, totaly removed {0} entities.", removed); } } #endregion Cleanup } catch (Exception ex) { Logger.Log.Error("EXCEPTION at BeaconSecurity.UpdateBeforeSimulation(): {0} {1}", ex.Message, ex.StackTrace); } }
public override void UpdateAfterSimulation10() { try { BlocksInTheWay.Clear(); DeleteWeldPads.Clear(); if (Handler.Pads.Count <= 1) { return; } if (!ThisPad.IsWorking) { return; } if (OtherPad != null && (OtherPad.Closed || OtherPad.MarkedForClose || OtherPad.CubeGrid?.Physics == null || !OtherPad.IsWorking)) { OtherPad = null; return; } bool isMaster = (OtherPad == null ? true : ThisPad.EntityId > OtherPad.EntityId); if (!isMaster) { return; // only one pad 'thinks' } IMyCubeGrid padGrid = ThisPad.CubeGrid; MatrixD padMatrix = ThisPad.WorldMatrix; Vector3D padForward = padMatrix.GetDirectionVector(DirForward); Vector3D padPos = padMatrix.Translation + padForward * -(padGrid.GridSize / 2); //MyTransparentGeometry.AddPointBillboard(MyStringId.GetOrCompute("WhiteDot"), Color.Lime, padPos, 0.1f, 0, blendType: BlendTypeEnum.AdditiveTop); if (OtherPad == null) { double minDistance = (ThisPad.CubeGrid.GridSize * ThisPad.CubeGrid.GridSize); IMyCubeBlock closestPad = null; WeldPad closestLogic = null; double closestDistSq = double.MaxValue; foreach (IMyCubeBlock p in Handler.Pads) { if (p.EntityId == ThisPad.EntityId || p.CubeGrid == ThisPad.CubeGrid || p.CubeGrid?.Physics == null || p.CubeGrid.GridSizeEnum != padGrid.GridSizeEnum || (padGrid.IsStatic && p.CubeGrid.IsStatic) || !p.IsWorking) { continue; } Vector3D pForward = p.WorldMatrix.GetDirectionVector(DirForward); // not pointed at eachother, skip if (Vector3D.Dot(pForward, padForward) > -0.5) { continue; } WeldPad otherLogic = p.GameLogic.GetAs <WeldPad>(); if (otherLogic == null) { continue; } Vector3D otherPos = p.WorldMatrix.Translation + (pForward * -(p.CubeGrid.GridSize / 2)); double distSq = Vector3D.DistanceSquared(padPos, otherPos); //MyTransparentGeometry.AddPointBillboard(MyStringId.GetOrCompute("WhiteDot"), Color.Red, otherPos, 0.1f, 0, blendType: BlendTypeEnum.AdditiveTop); if (distSq < closestDistSq && distSq <= minDistance) { closestDistSq = distSq; closestPad = p; closestLogic = otherLogic; } } if (closestPad == null) { return; } OtherPad = closestPad; closestLogic.OtherPad = ThisPad; } Vector3D otherPadPos = OtherPad.WorldMatrix.Translation + (-OtherPad.WorldMatrix.GetDirectionVector(DirForward) * (OtherPad.CubeGrid.GridSize / 2)); double distanceSquared = Vector3D.DistanceSquared(padPos, otherPadPos); if (distanceSquared > OtherPad.CubeGrid.GridSize * OtherPad.CubeGrid.GridSize) { WeldPad otherLogic = OtherPad.GameLogic.GetAs <WeldPad>(); otherLogic.OtherPad = null; OtherPad = null; return; } IMyCubeGrid otherGrid = OtherPad.CubeGrid; double axisDot = Math.Round(Vector3D.Dot(ThisPad.WorldMatrix.Up, OtherPad.WorldMatrix.Up), 2); double rollDot = Math.Round(Vector3D.Dot(ThisPad.WorldMatrix.Right, OtherPad.WorldMatrix.GetDirectionVector(OtherPad.WorldMatrix.GetClosestDirection(ThisPad.WorldMatrix.Right))), 2); double distReq = (padGrid.GridSizeEnum == MyCubeSize.Large ? 0.5 : 0.25); double dist = Math.Sqrt(distanceSquared) - distReq; if (dist <= 0 && axisDot == -1.0 && rollDot == 1.0) { if (!CanMergeCubes(ThisPad, OtherPad, MergeHandler.CalculateOffset(ThisPad, OtherPad), BlocksInTheWay, DeleteWeldPads)) { //bool otherWeldPadsInTheWay = false; //foreach(IMySlimBlock block in DrawInTheWay) //{ // if(IsWeldPad(block.BlockDefinition.Id)) // { // otherWeldPadsInTheWay = true; // break; // } //} //if(otherWeldPadsInTheWay) // SetToolStatus("WeldPad: Can't merge, other weld pads in the way, use only one pair!", MyFontEnum.Red, 1000); //else SetPadStatus("WeldPad: Can't merge, some blocks would overlap!", MyFontEnum.Red, 1000); if (!Handler.PadDraw.Contains(this)) { Handler.PadDraw.Add(this); } return; } //if(MyAPIGateway.GridGroups.HasConnection(pad.CubeGrid, otherPad.CubeGrid, GridLinkTypeEnum.Physical)) //{ // SetToolStatus("WeldPad: Can't merge physically connected grids!", MyFontEnum.Red, 1000); // return; //} //SetToolStatus("WeldPad: Succesfully fake merged", MyFontEnum.Green, 1000); //return; if (!MyAPIGateway.Multiplayer.IsServer) { Log.Info("Merge checks out clientside, waiting for server..."); } else { Log.Info($"Queued for merge {padGrid} and {otherGrid}"); AdvancedWeldingMod.Instance.MergeHandler.ScheduleMerge(ThisPad, OtherPad); padGrid.RemoveBlock(ThisPad.SlimBlock); otherGrid.RemoveBlock(OtherPad.SlimBlock); // remove other weldpads that get in the way foreach (IMySlimBlock block in DeleteWeldPads) { block.CubeGrid.RemoveBlock(block); Log.Info($" removed weldpad that was in the way at {block.Position.ToString()} on {block.CubeGrid.ToString()}"); } } WeldPad otherLogic = OtherPad.GameLogic.GetAs <WeldPad>(); otherLogic.OtherPad = null; OtherPad = null; SetPadStatus("WeldPad: Succesfully merged", MyFontEnum.Green, 1000); } else { // double dist = Math.Abs(((distSq - distReq) - pad.CubeGrid.GridSize) / pad.CubeGrid.GridSize) * 100; double axisDist = 100 - ((Math.Abs(axisDot - -1.0) / 2) * 100); double rollDist = 100 - ((Math.Abs(rollDot - 1.0) / 2) * 100); SetPadStatus($"WeldPad: Distance = {Math.Max(dist, 0).ToString("0.00")}m, axis = {axisDist.ToString("0.00")}%, roll = {rollDist.ToString("0.00")}%", MyFontEnum.Blue); //MyAPIGateway.Utilities.ShowNotification("[debug] offset="+AdvancedWelding.CalculateOffset(padGrid, otherGrid, pad)+"; offset2="+AdvancedWelding.CalculateOffset(otherGrid, padGrid, otherPad), 160, MyFontEnum.Blue); //MyAPIGateway.Utilities.ShowNotification("[debug] offset="+AdvancedWelding.CalculateOffset(pad, otherPad)+"; offset2="+AdvancedWelding.CalculateOffset(otherPad, pad), 160, MyFontEnum.Blue); //MyAPIGateway.Utilities.ShowNotification("[debug] dist="+Math.Round(Math.Sqrt(distSq), 3), 160, MyFontEnum.Blue); //MyAPIGateway.Utilities.ShowNotification("[debug] distSq="+Math.Round(distSq, 2)+"; axis="+axisDot+"; rotation="+rotationDot, 160, MyFontEnum.Blue); // magnetism... //Vector3D dir = (otherPos - pos); //if(!padGrid.IsStatic) // padGrid.Physics.AddForce(MyPhysicsForceType.APPLY_WORLD_FORCE, dir * 5 * otherPad.Mass, pos, null); //if(!otherGrid.IsStatic) // otherGrid.Physics.AddForce(MyPhysicsForceType.APPLY_WORLD_FORCE, -dir * 5 * pad.Mass, otherPos, null); } } catch (Exception e) { Log.Error(e); } }