BaseWireInputComponent.cs
namespace Sandbox
{
public class WireInput
{
public object value = 0;
public float asFloat { get => Convert.ToSingle( value ); }
public bool asBool { get => Convert.ToBoolean( value ); }
public Vector3 asVector3
{
get
{
if ( value is Vector3 valueVec3 )
return valueVec3;
else if ( value is float valueFloat )
return new Vector3( valueFloat, valueFloat, valueFloat );
else if ( value is int valueInt )
return new Vector3( valueInt, valueInt, valueInt );
else if ( value is Angles valueAng )
return valueAng.Forward;
else if ( value is Rotation valueRot )
return valueRot.Forward;
else
return Vector3.Zero;
}
}
public GameObject entity;
public string inputName;
public string type;
public WireOutput connectedOutput;
public WireCable AttachRope { get; set; }
public WireInput( GameObject entity, string inputName, string type, object def = null )
{
this.entity = entity;
this.inputName = inputName;
this.type = type;
value = def ?? IWireComponent.GetDefaultValueFromType( type );
}
}
public interface IWireInputComponent : IWireComponent
{
public void WireTriggerInput<T>( string inputName, T value )
{
if ( !WirePorts.inputsInitialized )
{ // these get cleared by hot reloading
WirePorts.inputsInitialized = true;
WireInitialize();
}
WirePorts.inputs[inputName].value = value;
WirePorts.inputHandlers[inputName]( value );
}
public abstract void WireInitialize();
public WireInput GetInput( string inputName )
{
if ( !WirePorts.inputsInitialized )
{
WireInitialize();
WirePorts.inputsInitialized = true;
}
return WirePorts.inputs[inputName];
}
public string[] GetInputNames( bool withValues = false )
{
if ( !WirePorts.inputsInitialized )
{
WireInitialize();
WirePorts.inputsInitialized = true;
}
return !withValues
? WirePorts.inputs.Keys.ToArray()
: WirePorts.inputs.Keys.Select( ( string key ) =>
{
var type = WirePorts.inputs[key].type;
if ( type == "string" )
return $"{key} [{type}]: \"{WirePorts.inputs[key].value}\"";
return $"{key} [{type}]: {WirePorts.inputs[key].value}";
} ).ToArray();
}
// Rpc.Broadcast version is over in the BaseWireComponent class
public void DisconnectInput( string inputName, bool destroyRope = true );
internal void _DisconnectInput( string inputName, bool destroyRope = true )
{
_DisconnectInput( GetInput( inputName ), destroyRope );
}
internal void _DisconnectInput( WireInput input, bool destroyRope = true )
{
if ( input.connectedOutput != null )
{
input.connectedOutput.connected.Remove( input );
input.connectedOutput = null;
}
if ( input.AttachRope != null )
{
if ( destroyRope ) input.AttachRope.Destroy();
input.AttachRope = null;
}
if ( WirePorts.inputs.ContainsKey( input.inputName ) ) // it might have been removed eg. when switching gate type
{
WireTriggerInput( input.inputName, IWireComponent.GetDefaultValueFromType( input.type ) );
}
}
}
public abstract class BaseWireInputComponent : BaseWireComponent, IWireInputComponent
{
public abstract void WireInitialize();
public virtual string GetOverlayText() { return ""; }
}
// Extension methods to allow calling the interface methods without explicit casting
public static class BaseWireInputComponentUtils
{
public static void RegisterInputHandler( this IWireInputComponent instance, string inputName, Action<float> handler, float def = 0f )
{
instance.WirePorts.inputHandlers[inputName] = (( value ) =>
{
if ( value is bool valueBool )
{
handler( valueBool ? 1.0f : 0.0f );
}
else if ( value is Vector3 valueVec3 )
{
handler( valueVec3.Length );
}
else
{
handler( Convert.ToSingle( value ) );
}
});
instance.WirePorts.inputs[inputName] = new WireInput( ((BaseWireComponent)instance).GameObject, inputName, "float", def );
}
public static void RegisterInputHandler( this IWireInputComponent instance, string inputName, Action<bool> handler, bool def = false )
{
instance.WirePorts.inputHandlers[inputName] = (( value ) =>
{
if ( value is int valueInt )
{
handler( valueInt != 0 );
}
else if ( value is float valueFloat )
{
handler( valueFloat.AlmostEqual( 0.0f ) );
}
else if ( value is Vector3 valueVec3 )
{
handler( valueVec3.IsNearZeroLength );
}
else
{
handler( (bool)value );
}
});
instance.WirePorts.inputs[inputName] = new WireInput( ((BaseWireComponent)instance).GameObject, inputName, "bool", def );
}
public static void RegisterInputHandler( this IWireInputComponent instance, string inputName, Action<int> handler, int def = 0 )
{
instance.WirePorts.inputHandlers[inputName] = (( value ) =>
{
if ( value is Vector3 valueVec3 )
{
handler( (int)valueVec3.Length );
}
else if ( value is bool valueBool )
{
handler( valueBool ? 1 : 0 );
}
else
{
handler( (int)value );
}
});
instance.WirePorts.inputs[inputName] = new WireInput( ((BaseWireComponent)instance).GameObject, inputName, "int", def );
}
public static void RegisterInputHandler( this IWireInputComponent instance, string inputName, Action<string> handler, string def = "" )
{
instance.WirePorts.inputHandlers[inputName] = (( value ) =>
{
if ( value is GameObject valueEnt )
{
handler( $"GameObject" ); // todo is there something more useful like $"{valueEnt.ClassName} [{valueEnt.NetworkIdent}]" we can do?
}
else if ( value is Vector3 valueVec3 )
{
handler( $"[{valueVec3.x:0.#},{valueVec3.y:0.#},{valueVec3.z:0.#}]" );
}
else if ( value is float valueFloat )
{
handler( valueFloat.ToString( "0.###" ) );
}
else
{
handler( value.ToString() );
}
});
instance.WirePorts.inputs[inputName] = new WireInput( ((BaseWireComponent)instance).GameObject, inputName, "string", def );
}
public static void RegisterInputHandler( this IWireInputComponent instance, string inputName, Action<Vector3> handler, Vector3 def = new Vector3() )
{
instance.WirePorts.inputHandlers[inputName] = (( value ) =>
{
if ( value is Angles ang )
{
handler( ang.Forward );
}
else
{
handler( (Vector3)value );
}
});
instance.WirePorts.inputs[inputName] = new WireInput( ((BaseWireComponent)instance).GameObject, inputName, "vector3", def );
}
public static void RegisterInputHandler( this IWireInputComponent instance, string inputName, Action<Angles> handler, Angles def = new Angles() )
{
instance.WirePorts.inputHandlers[inputName] = (( value ) =>
{
if ( value is Vector3 vec3 )
{
handler( vec3.EulerAngles );
}
else
{
handler( (Angles)value );
}
});
instance.WirePorts.inputs[inputName] = new WireInput( ((BaseWireComponent)instance).GameObject, inputName, "angle", def );
}
// Todo: C# won't seem to let me make `def = Rotation.Identity`, so lets just have a second function for now
public static void RegisterInputHandler( this IWireInputComponent instance, string inputName, Action<Rotation> handler )
{
RegisterInputHandler( instance, inputName, handler, Rotation.Identity );
}
public static void RegisterInputHandler( this IWireInputComponent instance, string inputName, Action<Rotation> handler, Rotation def )
{
instance.WirePorts.inputHandlers[inputName] = (( value ) =>
{
handler( (Rotation)value );
});
instance.WirePorts.inputs[inputName] = new WireInput( ((BaseWireComponent)instance).GameObject, inputName, "rotation", def );
}
public static void RegisterInputHandler( this IWireInputComponent instance, string inputName, Action<GameObject> handler, GameObject def = null )
{
instance.WirePorts.inputHandlers[inputName] = (( value ) =>
{
if ( value is GameObject valueGo )
{
handler( valueGo );
}
else
{
handler( null );
}
});
instance.WirePorts.inputs[inputName] = new WireInput( ((BaseWireComponent)instance).GameObject, inputName, "gameobject", def );
}
public static void RegisterInputHandler( this IWireInputComponent instance, string inputName, Action<object> handler, object def = null )
{
instance.WirePorts.inputHandlers[inputName] = handler;
instance.WirePorts.inputs[inputName] = new WireInput( ((BaseWireComponent)instance).GameObject, inputName, "any", def );
}
}
}