001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package org.wpilib.command2; 006 007import static org.wpilib.util.ErrorMessages.requireNonNullParam; 008 009import java.util.function.Supplier; 010import org.wpilib.util.sendable.SendableBuilder; 011 012/** 013 * Schedules a given command when this command is initialized and ends when it ends, but does not 014 * directly run it. Use this for including a command in a composition without adding its 015 * requirements, <strong>but only if you know what you are doing. If you are unsure, see <a 016 * href="https://docs.wpilib.org/en/stable/docs/software/commandbased/command-compositions.html#scheduling-other-commands">the 017 * WPILib docs</a> for a complete explanation of proxy semantics.</strong> Do not proxy a command 018 * from a subsystem already required by the composition, or else the composition will cancel itself 019 * when the proxy is reached. If this command is interrupted, it will cancel the command. 020 * 021 * <p>This class is provided by the Commands v2 VendorDep 022 */ 023public class ProxyCommand extends Command { 024 private final Supplier<Command> m_supplier; 025 private Command m_command; 026 027 /** 028 * Creates a new ProxyCommand that schedules the given command when initialized, and ends when it 029 * is no longer scheduled. 030 * 031 * @param command the command to run by proxy 032 */ 033 @SuppressWarnings("this-escape") 034 public ProxyCommand(Command command) { 035 Command nullCheckedCommand = requireNonNullParam(command, "command", "ProxyCommand"); 036 m_supplier = () -> nullCheckedCommand; 037 setName("Proxy(" + nullCheckedCommand.getName() + ")"); 038 } 039 040 @Override 041 public void initialize() { 042 m_command = m_supplier.get(); 043 CommandScheduler.getInstance().schedule(m_command); 044 } 045 046 @Override 047 public void end(boolean interrupted) { 048 if (interrupted) { 049 m_command.cancel(); 050 } 051 m_command = null; 052 } 053 054 @Override 055 public void execute() {} 056 057 @Override 058 public boolean isFinished() { 059 // because we're between `initialize` and `end`, `m_command` is necessarily not null 060 // but if called otherwise and m_command is null, 061 // it's UB, so we can do whatever we want -- like return true. 062 return m_command == null || !m_command.isScheduled(); 063 } 064 065 /** 066 * Whether the given command should run when the robot is disabled. Override to return true if the 067 * command should run when disabled. 068 * 069 * @return true. Otherwise, this proxy would cancel commands that do run when disabled. 070 */ 071 @Override 072 public boolean runsWhenDisabled() { 073 return true; 074 } 075 076 @Override 077 public void initSendable(SendableBuilder builder) { 078 super.initSendable(builder); 079 builder.addStringProperty( 080 "proxied", () -> m_command == null ? "null" : m_command.getName(), null); 081 } 082}