static void DetachBlock(IMySlimBlock block, IMyAngleGrinder grinder) { if (!MyAPIGateway.Session.IsServer) { return; } MyCubeBlockDefinition blockDef = (MyCubeBlockDefinition)block.BlockDefinition; string blockName = blockDef.DisplayNameText; string gridName = $"(Detached {blockName})"; IMyCubeGrid detachFrom = block.CubeGrid; MyObjectBuilder_CubeBlock blockOb = block.GetObjectBuilder(); MyObjectBuilder_CubeGrid gridOb = CreateNewGridOB(block.CubeGrid, blockOb, gridName); block.CubeGrid.RemoveBlock(block, true); MyCubeGrid createdGrid = MyAPIGateway.Entities.CreateFromObjectBuilderAndAdd(gridOb) as MyCubeGrid; if (createdGrid == null) { Log.Error($"Failed to create a new grid! obj={gridOb}; new entId={gridOb.EntityId.ToString()}"); MyVisualScriptLogicProvider.SendChatMessageColored($"Failed to create detached block grid!", Color.Red, Log.ModName, grinder.OwnerIdentityId, MyFontEnum.Debug); return; } Log.Info($"Detached '{blockName}' from '{detachFrom.CustomName}' ({detachFrom.EntityId.ToString()}); new grid id={createdGrid.EntityId.ToString()}"); // sending "to server" so that it happens serverside too if server is a player (or singleplayer). DetachEffectsPacket packet = new DetachEffectsPacket(createdGrid.GetBlocks().First()); AdvancedWeldingMod.Instance.Networking.SendToServer(packet); }
void EquippedGrinderChanged(IMyAngleGrinder grinder) { if (grinder != null && !InformedAboutFeature && MyAPIGateway.Session?.Player != null) { InformedAboutFeature = true; MyVisualScriptLogicProvider.SendChatMessageColored("Type /detach in chat to see grinder features.", Color.Green, Log.ModName, MyAPIGateway.Session.Player.IdentityId); } }
void Local_EquippedGrinderChanged(IMyAngleGrinder grinder) { SetUpdate(this, grinder != null); if (grinder == null) { SetLocalDetach(false); } }
void Local_EquippedGrinderChanged(IMyAngleGrinder grinder) { SetUpdate(this, grinder != null); if (grinder == null) { SetLocalTarget(null); } }
void IUpdatable.Update() { IMyCharacter chr = MyAPIGateway.Session?.ControlledObject as IMyCharacter; IMyAngleGrinder grinder = chr?.EquippedTool as IMyAngleGrinder; if (EquippedGrinder != grinder) { EquippedGrinder = grinder; GrinderChanged?.Invoke(grinder); } }
void Server_GrindingBlock(IMySlimBlock block, ref MyDamageInformation info, IMyAngleGrinder grinder, ulong attackerSteamId) { PrecisionData data; if (!Server_PrecisionData.TryGetValue(attackerSteamId, out data) || data.GridEntId == 0) { return; } if (data.GridEntId != block.CubeGrid.EntityId || data.BlockPos != block.Min) { info.Amount = 0; // prevent grinding untargetted block } }
void BeforeDamage(object target, ref MyDamageInformation info) { try { if (info.IsDeformation || info.Amount <= 0 || info.Type != MyDamageType.Grind) { return; } IMySlimBlock block = target as IMySlimBlock; IMyFloatingObject fo = (block == null ? target as IMyFloatingObject : null); if (block == null && fo == null) { return; } MyEntity attacker = MyEntities.GetEntityById(info.AttackerId); IMyAngleGrinder grinder = attacker as IMyAngleGrinder; IMyCharacter attackerChar = (grinder == null ? attacker as IMyCharacter : null); if (grinder == null && attackerChar == null) { return; } ulong attackerSteamId; if (grinder != null) { attackerSteamId = MyAPIGateway.Players.TryGetSteamId(grinder.OwnerIdentityId); } else { attackerSteamId = MyAPIGateway.Players.TryGetSteamId(attackerChar.ControllerInfo.ControllingIdentityId); } if (block != null) { GrindingBlock?.Invoke(block, ref info, grinder, attackerSteamId); } else { GrindingFloatingObject?.Invoke(fo, ref info, attackerSteamId); } } catch (Exception e) { Log.Error(e); } }
void IUpdatable.Update() { IMyAngleGrinder grinder = Main.GrinderHandler?.EquippedGrinder; if (grinder == null) { return; } bool inputReadable = !MyAPIGateway.Gui.IsCursorVisible && !MyAPIGateway.Gui.ChatEntryVisible; if (TargetBlock == null && inputReadable && MyAPIGateway.Input.IsGameControlPressed(MyControlsSpace.SECONDARY_TOOL_ACTION)) { MyCasterComponent casterComp = grinder?.Components?.Get <MyCasterComponent>(); IMySlimBlock target = casterComp?.HitBlock as IMySlimBlock; if (target != null) { SetLocalTarget(target); } } if (TargetBlock != null && (!inputReadable || MyAPIGateway.Input.IsNewGameControlReleased(MyControlsSpace.SECONDARY_TOOL_ACTION))) { SetLocalTarget(null); } if (TargetBlock != null) { bool finishedGrinding = TargetBlock.IsFullyDismounted; // TODO: some targetting sprite? //Vector3D blockCenterPos = Vector3D.Transform(BlockLocalCenter, TargetBlock.CubeGrid.WorldMatrix); //float blockSize = (TargetBlock.Max - TargetBlock.Min + Vector3I.One).AbsMin() * TargetBlock.CubeGrid.GridSize; //Vector4 color = (finishedGrinding ? Color.Lime : Color.Blue); //MyTransparentGeometry.AddPointBillboard(MyStringId.GetOrCompute("WhiteDot"), color, blockCenterPos, blockSize, 0, blendType: BlendTypeEnum.AdditiveTop); if (finishedGrinding) { Main.Notifications.Print(Channel.Precision, $"Precision Grind: target was grinded!", MyFontEnum.Green, 16); } else { Main.Notifications.Print(Channel.Precision, $"Precision Grind: locked to {TargetBlock.BlockDefinition.DisplayNameText}", MyFontEnum.Debug, 16); } } }
void IUpdatable.Update() { if (MyAPIGateway.Utilities.IsDedicated) { return; } IMyAngleGrinder grinder = Main.GrinderHandler.EquippedGrinder; if (grinder == null) { return; } bool shouldDetach = !MyAPIGateway.Gui.IsCursorVisible && !MyAPIGateway.Gui.ChatEntryVisible && MyAPIGateway.Input.IsKeyPress(MyKeys.Control); if (shouldDetach != Local_DetachData.DetachMode) { SetLocalDetach(shouldDetach); } }
void Server_GrindingBlock(IMySlimBlock block, ref MyDamageInformation info, IMyAngleGrinder grinder, ulong attackerSteamId) { DetachData data = Server_DetachData.GetValueOrDefault(attackerSteamId); if (data == null || !data.DetachMode) { return; } float grindAmount = info.Amount; // store grinder speed for later use info.Amount = 0; // prevent grinding while detach mode is enabled MyCubeBlockDefinition blockDef = (MyCubeBlockDefinition)block.BlockDefinition; if (!blockDef.IsStandAlone || !blockDef.HasPhysics) { ProgressPacket.Send(attackerSteamId, DetachState.NoStandalone); return; } if (grindAmount == 0) { ProgressPacket.Send(attackerSteamId, DetachState.ZeroGrindAmount); return; } long owner = block.OwnerId; if (owner == 0 && block.CubeGrid.BigOwners != null && block.CubeGrid.BigOwners.Count > 0) { owner = block.CubeGrid.BigOwners[0]; } if (owner == 0) { owner = block.BuiltBy; } if (owner != 0) { MyRelationsBetweenPlayerAndBlock relation = MyIDModule.GetRelationPlayerBlock(owner, grinder.OwnerIdentityId, MyOwnershipShareModeEnum.Faction); if (relation == MyRelationsBetweenPlayerAndBlock.Enemies) { ProgressPacket.Send(attackerSteamId, DetachState.EnemyBlock); return; } } MyCubeGrid grid = (MyCubeGrid)block.CubeGrid; if (grid.BlocksCount <= 1) { if (grid.DisplayName.StartsWith("(Detached")) { ProgressPacket.Send(attackerSteamId, DetachState.DetachComplete); } else { ProgressPacket.Send(attackerSteamId, DetachState.SingleBlock); } return; } // checking safezones doesn't seem necessary, as you cannot grind to begin with... if (data.GrindedBlock != block) { data.GrindedBlock = block; data.GrindedTimes = 0; data.GrindExpiresAtTick = 0; } int tick = MyAPIGateway.Session.GameplayFrameCounter; if (data.GrindExpiresAtTick == 0 || data.GrindExpiresAtTick > tick) { data.GrindedTimes++; } else { data.GrindedTimes = 0; } data.GrindExpiresAtTick = tick + 30; // make it require as much time as it normally would to grind to critical line float divideBy = (block.FatBlock != null ? block.FatBlock.DisassembleRatio : blockDef.DisassembleRatio); float finalDamage = (grindAmount / divideBy) * blockDef.IntegrityPointsPerSec; int grindTimesToDetach = (int)((block.MaxIntegrity * blockDef.CriticalIntegrityRatio) / finalDamage); grindTimesToDetach = Math.Max(grindTimesToDetach, (int)(1000 / GrinderCooldownMs)); // at least one second if (data.GrindedTimes >= grindTimesToDetach) { data.GrindedTimes = 0; ProgressPacket.Send(attackerSteamId, DetachState.DetachComplete); DetachBlock(block, grinder); } else { int progress = (data.GrindedTimes * 100) / grindTimesToDetach; ProgressPacket.Send(attackerSteamId, DetachState.Detaching, progress); } }