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 edu.wpi.first.wpilibj2.command; 006 007import static edu.wpi.first.util.ErrorMessages.requireNonNullParam; 008 009import edu.wpi.first.util.sendable.SendableBuilder; 010import java.util.function.Supplier; 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 NewCommands 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 supplied command when initialized, and ends when 029 * it is no longer scheduled. Use this for lazily creating <strong>proxied</strong> commands at 030 * runtime. Proxying should only be done to escape from composition requirement semantics, so if 031 * only initialization time command construction is needed, use {@link DeferredCommand} instead. 032 * 033 * @param supplier the command supplier 034 * @deprecated This constructor's similarity to {@link DeferredCommand} is confusing and opens 035 * potential footguns for users who do not fully understand the semantics and implications of 036 * proxying, but who simply want runtime construction. Users who do know what they are doing 037 * and need a supplier-constructed proxied command should instead defer a proxy command. 038 * @see DeferredCommand 039 */ 040 @Deprecated(since = "2025", forRemoval = true) 041 public ProxyCommand(Supplier<Command> supplier) { 042 m_supplier = requireNonNullParam(supplier, "supplier", "ProxyCommand"); 043 } 044 045 /** 046 * Creates a new ProxyCommand that schedules the given command when initialized, and ends when it 047 * is no longer scheduled. 048 * 049 * @param command the command to run by proxy 050 */ 051 @SuppressWarnings("this-escape") 052 public ProxyCommand(Command command) { 053 Command nullCheckedCommand = requireNonNullParam(command, "command", "ProxyCommand"); 054 m_supplier = () -> nullCheckedCommand; 055 setName("Proxy(" + nullCheckedCommand.getName() + ")"); 056 } 057 058 @Override 059 public void initialize() { 060 m_command = m_supplier.get(); 061 m_command.schedule(); 062 } 063 064 @Override 065 public void end(boolean interrupted) { 066 if (interrupted) { 067 m_command.cancel(); 068 } 069 m_command = null; 070 } 071 072 @Override 073 public void execute() {} 074 075 @Override 076 public boolean isFinished() { 077 // because we're between `initialize` and `end`, `m_command` is necessarily not null 078 // but if called otherwise and m_command is null, 079 // it's UB, so we can do whatever we want -- like return true. 080 return m_command == null || !m_command.isScheduled(); 081 } 082 083 /** 084 * Whether the given command should run when the robot is disabled. Override to return true if the 085 * command should run when disabled. 086 * 087 * @return true. Otherwise, this proxy would cancel commands that do run when disabled. 088 */ 089 @Override 090 public boolean runsWhenDisabled() { 091 return true; 092 } 093 094 @Override 095 public void initSendable(SendableBuilder builder) { 096 super.initSendable(builder); 097 builder.addStringProperty( 098 "proxied", () -> m_command == null ? "null" : m_command.getName(), null); 099 } 100}