public static IMechanicalPowerDevice getNeighbourDevice(IWorldAccessor world, BlockPos pos, BlockFacing facing, bool connected) { if (facing == null) { return(null); } BlockEntity te = world.BlockAccessor.GetBlockEntity(pos.Offset(facing)); if (te is IMechanicalPowerDevice) { IMechanicalPowerDevice mechdevice = (IMechanicalPowerDevice)te; if (!mechdevice.exists()) { return(null); } if (!connected && mechdevice.hasConnectorAt(facing.GetOpposite())) { return(mechdevice); } if (connected && mechdevice.isConnectedAt(facing.GetOpposite())) { return(mechdevice); } } return(null); }
internal void OnNodeRemoved(IMechanicalPowerDevice device) { if (device.Network != null) { RebuildNetwork(device.Network, device); } }
public void trySetNetwork(long networkId, BlockFacing localFacing) { if (hasConnectorAt(localFacing)) { this.networkId = networkId; IMechanicalPowerDevice device = getNeighbourDevice(localFacing, true); if (device != null) { if (getNetwork(localFacing).getDirection() != 0) { clockwise = device.isClockWiseDirection(localFacing.GetOpposite()); setDirectionFromFacing(localFacing.GetOpposite()); } } else { throw new Exception("Eh, a network coming from " + localFacing + ", but there is no device, instead " + api.World.BlockAccessor.GetBlock(pos.AddCopy(localFacing)) + "?!"); } getNetwork(localFacing).register(this); api.World.BlockAccessor.MarkBlockEntityDirty(pos); } else { directionFromFacing = null; this.networkId = 0; } }
public bool tryConnect(BlockFacing toFacing) { MechanicalNetwork newNetwork; BlockPos pos = Position.AddCopy(toFacing); IMechanicalPowerBlock connectedToBlock = Api.World.BlockAccessor.GetBlock(pos) as IMechanicalPowerBlock; if (DEBUG) { Api.Logger.Notification("tryConnect at " + this.Position + " towards " + toFacing + " " + pos); } if (connectedToBlock == null || !connectedToBlock.HasMechPowerConnectorAt(Api.World, pos, toFacing.Opposite)) { return(false); } newNetwork = connectedToBlock.GetNetwork(Api.World, pos); if (newNetwork != null) { IMechanicalPowerDevice node = Api.World.BlockAccessor.GetBlockEntity(pos).GetBehavior <BEBehaviorMPBase>() as IMechanicalPowerDevice; connectedToBlock.DidConnectAt(Api.World, pos, toFacing.Opposite); //do this first to set the new Angled Gear block correctly prior to getting propagation direction BlockFacing newTurnDir = node.GetPropagationDirectionInput(); MechPowerPath curPath = new MechPowerPath(toFacing, node.GetGearedRatio(toFacing), pos, !node.IsPropagationDirection(Position, toFacing)); SetPropagationDirection(curPath); MechPowerPath[] paths = GetMechPowerExits(curPath); JoinNetwork(newNetwork); for (int i = 0; i < paths.Length; i++) { //if (paths[i].OutFacing == toFacing) continue; if (DEBUG) { Api.Logger.Notification("== spreading path " + (paths[i].invert ? "-" : "") + paths[i].OutFacing + " " + paths[i].gearingRatio); } BlockPos exitPos = Position.AddCopy(paths[i].OutFacing); bool chunkLoaded = spreadTo(Api, newNetwork, exitPos, paths[i], out _); if (!chunkLoaded) { LeaveNetwork(); return(true); } } return(true); } else if (this.network != null) { BEBehaviorMPBase node = Api.World.BlockAccessor.GetBlockEntity(pos)?.GetBehavior <BEBehaviorMPBase>(); if (node != null) { return(node.tryConnect(toFacing.Opposite)); } } return(false); }
public MechanicalNetwork CreateNetwork(IMechanicalPowerDevice powerProducerNode) { MechanicalNetwork nw = new MechanicalNetwork(this, data.nextNetworkId); nw.fullyLoaded = true; data.networksById[data.nextNetworkId] = nw; data.nextNetworkId++; return(nw); }
public void register(IMechanicalPowerDevice device) { if (device is IMechanicalPowerNetworkNode && !powerNodes.Contains(device)) { powerNodes.Add((IMechanicalPowerNetworkNode)device); } if (device is IMechanicalPowerNetworkRelay && !powerRelays.Contains(device)) { powerRelays.Add((IMechanicalPowerNetworkRelay)device); } }
public void RebuildNetwork(MechanicalNetwork network, IMechanicalPowerDevice nowRemovedNode = null) { network.Valid = false; if (Api.Side == EnumAppSide.Server) { DeleteNetwork(network); } if (network.nodes.Values.Count == 0) { if (Api.Side == EnumAppSide.Server) { Api.Logger.Notification("Network with id " + network.networkId + " had zero nodes?"); } return; } var nnodes = network.nodes.Values.ToArray(); foreach (var nnode in nnodes) { nnode.LeaveNetwork(); } foreach (var nnode in nnodes) { if (!(nnode is IMechanicalPowerDevice)) { continue; } IMechanicalPowerDevice newnode = Api.World.BlockAccessor.GetBlockEntity((nnode as IMechanicalPowerDevice).Position)?.GetBehavior <BEBehaviorMPBase>() as IMechanicalPowerDevice; if (newnode == null) { continue; } BlockFacing oldTurnDir = newnode.GetPropagationDirection(); if (newnode.OutFacingForNetworkDiscovery != null && (nowRemovedNode == null || newnode.Position != nowRemovedNode.Position)) { MechanicalNetwork newnetwork = newnode.CreateJoinAndDiscoverNetwork(newnode.OutFacingForNetworkDiscovery); bool reversed = newnode.GetPropagationDirection() == oldTurnDir.Opposite; newnetwork.Speed = reversed ? -network.Speed : network.Speed; newnetwork.AngleRad = network.AngleRad; newnetwork.TotalAvailableTorque = reversed ? -network.TotalAvailableTorque : network.TotalAvailableTorque; newnetwork.NetworkResistance = network.NetworkResistance; if (Api.Side == EnumAppSide.Server) { newnetwork.broadcastData(); } } } }
public void unregister(IMechanicalPowerDevice device) { if (device is IMechanicalPowerNetworkNode) { powerNodes.Remove((IMechanicalPowerNetworkNode)device); } if (device is IMechanicalPowerNetworkRelay) { powerRelays.Remove((IMechanicalPowerNetworkRelay)device); } rebuildNetwork(); }
// connected = true => get connected devices // connected = false => get connectible devices (= devices that could potentially connect to our own device) public Dictionary <BlockFacing, IMechanicalPowerDevice> getNeighbourDevices(bool connected) { Dictionary <BlockFacing, IMechanicalPowerDevice> connectibleNeighbours = new Dictionary <BlockFacing, IMechanicalPowerDevice>(); foreach (BlockFacing facing in BlockFacing.ALLFACES) { IMechanicalPowerDevice neib = getNeighbourDevice(facing, connected); if (neib == null) { continue; } connectibleNeighbours[facing] = neib; } return(connectibleNeighbours); }
internal float RotationNeighbour(int side, bool allowIndirect) { BlockPos pos = Position.AddCopy(orients[side]); IMechanicalPowerBlock block = Api.World.BlockAccessor.GetBlock(pos) as IMechanicalPowerBlock; if (block?.HasMechPowerConnectorAt(Api.World, pos, orients[side].Opposite) != true) { block = null; } BlockEntity be = block == null ? null : Api.World.BlockAccessor.GetBlockEntity(pos); IMechanicalPowerDevice node = be?.GetBehavior <BEBehaviorMPBase>() as IMechanicalPowerDevice; if (node is BEBehaviorMPTransmission trans && !trans.engaged) { node = null; } float rot; if (node == null || node.Network == null) { if (this.engaged && allowIndirect) { rot = this.RotationNeighbour(1 - side, false); rotPrev[side] = rot; } else { rot = rotPrev[side]; } } else { rot = node.Network.AngleRad * node.GearedRatio; bool invert = node.GetPropagationDirection() != orients[side]; if (side == 1) { invert = !invert; } if (invert) { rot = GameMath.TWOPI - rot; } rotPrev[side] = rot; } return(rot); }
public virtual MechanicalNetwork CreateJoinAndDiscoverNetwork(BlockFacing powerOutFacing) { BlockPos neibPos = Position.AddCopy(powerOutFacing); IMechanicalPowerBlock neibMechBlock = null; neibMechBlock = Api.World.BlockAccessor.GetBlock(neibPos) as IMechanicalPowerBlock; MechanicalNetwork neibNetwork = neibMechBlock == null ? null : neibMechBlock.GetNetwork(Api.World, neibPos); if (neibNetwork == null || !neibNetwork.Valid) { MechanicalNetwork newNetwork = this.network; if (newNetwork == null) { newNetwork = manager.CreateNetwork(this); JoinNetwork(newNetwork); if (DEBUG) { Api.Logger.Notification("===setting inturn at " + Position + " " + powerOutFacing); } SetPropagationDirection(new MechPowerPath(powerOutFacing, 1)); } Vec3i missingChunkPos; bool chunksLoaded = spreadTo(Api, newNetwork, neibPos, new MechPowerPath(GetPropagationDirection(), this.gearedRatio), out missingChunkPos); if (network == null) { if (DEBUG) { Api.Logger.Notification("Incomplete chunkloading, possible issues with mechanical network around block " + neibPos); } return(null); } if (!chunksLoaded) { network.AwaitChunkThenDiscover(missingChunkPos); manager.testFullyLoaded(network); // To trigger that allFullyLoaded gets false return(network); } else { IMechanicalPowerDevice node = Api.World.BlockAccessor.GetBlockEntity(neibPos)?.GetBehavior <BEBehaviorMPBase>() as IMechanicalPowerDevice; if (node != null) { BlockFacing facing = node.GetPropagationDirectionInput(); SetPropagationDirection(new MechPowerPath(facing, node.GetGearedRatio(facing), neibPos)); } } } else { BEBehaviorMPBase neib = Api.World.BlockAccessor.GetBlockEntity(neibPos).GetBehavior <BEBehaviorMPBase>(); if (OutFacingForNetworkDiscovery != null) { if (tryConnect(OutFacingForNetworkDiscovery)) { this.gearedRatio = neib.GetGearedRatio(OutFacingForNetworkDiscovery); //no need to set propagationDir, it's already been set by tryConnect } } else { JoinNetwork(neibNetwork); SetPropagationDirection(new MechPowerPath(neib.propagationDir, neib.GetGearedRatio(neib.propagationDir), neibPos)); } } return(network); }
public virtual MechanicalNetwork GetNetwork(IWorldAccessor world, BlockPos pos) { IMechanicalPowerDevice be = world.BlockAccessor.GetBlockEntity(pos)?.GetBehavior <BEBehaviorMPBase>() as IMechanicalPowerDevice; return(be?.Network); }
// Default behavior: Device is connected to all neighbor devices public bool isConnectedAt(BlockFacing facing) { IMechanicalPowerDevice device = getNeighbourDevice(facing, false); return(device != null && (device is IMechanicalPowerDevice)); }
public void handleMechanicalRelayPlacement() { Dictionary <BlockFacing, MechanicalNetwork> networks = new Dictionary <BlockFacing, MechanicalNetwork>(); List <BlockFacing> nullnetworks = new List <BlockFacing>(); foreach (BlockFacing facing in BlockFacing.ALLFACES) { IMechanicalPowerDevice neib = getNeighbourDevice(facing, true); if (neib == null) { continue; } MechanicalNetwork network = neib.getNetwork(facing.GetOpposite()); if (network != null && !networks.ContainsValue(network)) { networks[facing] = network; } if (network == null) { nullnetworks.Add(facing); } } //System.out.println(worldObj.isRemote + " found " + networks.size() + " networks "); if (networks.Count == 1) { BlockFacing facing = networks.Keys.ToArray()[0]; trySetNetwork(networks[facing].networkId, facing); foreach (BlockFacing nullnetworkfacing in nullnetworks) { getNeighbourDevice(nullnetworkfacing, true).propagateNetworkToNeighbours( MechNetworkManagerRegistry.ManagersByWorld[api.World].getUniquePropagationId(), networkId, nullnetworkfacing ); } } if (networks.Count > 1 && api.World is IClientWorldAccessor) { float maxSpeedDifference = 0; MechanicalNetwork dominantNetwork = null; foreach (MechanicalNetwork network in networks.Values) { if (dominantNetwork == null) { dominantNetwork = network; continue; } maxSpeedDifference = Math.Max(maxSpeedDifference, Math.Abs(network.getSpeed() - dominantNetwork.getSpeed())); if (Math.Abs(network.getSpeed()) > Math.Abs(dominantNetwork.getSpeed())) { dominantNetwork = network; } } // Here we could disallow connecting of networks if // maxSpeedDifference is larger than 1 // e.g. immediately break the placed block again because it cannot handle // the large torque difference. But implementation will be somewhat complicated foreach (MechanicalNetwork network in networks.Values) { if (network != dominantNetwork) { network.isDead = true; MechNetworkManagerRegistry.ManagersByWorld[api.World].discardNetwork(network); } } dominantNetwork.rebuildNetwork(); api.World.BlockAccessor.MarkBlockEntityDirty(pos); } }
public void DidUnload(IMechanicalPowerDevice node) { fullyLoaded = false; }