Files
RobustToolbox/Robust.Shared/Input/Binding/InputCmdHandler.cs

215 lines
8.7 KiB
C#

using System;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Player;
namespace Robust.Shared.Input.Binding
{
public delegate void StateInputCmdDelegate(ICommonSession? session);
public abstract class InputCmdHandler
{
public virtual bool FireOutsidePrediction => false;
public virtual void Enabled(ICommonSession? session)
{
}
public virtual void Disabled(ICommonSession? session)
{
}
public abstract bool HandleCmdMessage(IEntityManager entManager, ICommonSession? session, IFullInputCmdMessage message);
/// <summary>
/// Makes a quick input command from enabled and disabled delegates.
/// </summary>
/// <param name="enabled">The delegate to be ran when this command is enabled.</param>
/// <param name="disabled">The delegate to be ran when this command is disabled.</param>
/// <returns>The new input command.</returns>
public static InputCmdHandler FromDelegate(StateInputCmdDelegate? enabled = null,
StateInputCmdDelegate? disabled = null, bool handle=true, bool outsidePrediction=true)
{
return new StateInputCmdHandler
{
EnabledDelegate = enabled,
DisabledDelegate = disabled,
Handle = handle,
OutsidePrediction = outsidePrediction
};
}
private sealed class StateInputCmdHandler : InputCmdHandler
{
public StateInputCmdDelegate? EnabledDelegate;
public StateInputCmdDelegate? DisabledDelegate;
public bool Handle { get; set; }
public bool OutsidePrediction;
public override bool FireOutsidePrediction => OutsidePrediction;
public override void Enabled(ICommonSession? session)
{
EnabledDelegate?.Invoke(session);
}
public override void Disabled(ICommonSession? session)
{
DisabledDelegate?.Invoke(session);
}
public override bool HandleCmdMessage(IEntityManager entManager, ICommonSession? session, IFullInputCmdMessage message)
{
switch (message.State)
{
case BoundKeyState.Up:
Disabled(session);
return Handle;
case BoundKeyState.Down:
Enabled(session);
return Handle;
}
//Client Sanitization: unknown key state, just ignore
return false;
}
}
}
public delegate bool PointerInputCmdDelegate(ICommonSession? session, EntityCoordinates coords, EntityUid uid);
public delegate bool PointerInputCmdDelegate2(in PointerInputCmdHandler.PointerInputCmdArgs args);
public sealed class PointerInputCmdHandler : InputCmdHandler
{
private PointerInputCmdDelegate2 _callback;
private bool _ignoreUp;
public override bool FireOutsidePrediction { get; }
/// <summary>
/// Handler which will handle the command using the indicated callback
/// </summary>
/// <param name="callback">callback to handle the command</param>
/// <param name="ignoreUp">whether keyup actions will be ignored by this handler (like lifting a key or releasing
/// mouse button)</param>
public PointerInputCmdHandler(PointerInputCmdDelegate callback, bool ignoreUp = true, bool outsidePrediction = false)
: this((in PointerInputCmdArgs args) =>
callback(args.Session, args.Coordinates, args.EntityUid), ignoreUp, outsidePrediction) { }
/// <summary>
/// Handler which will handle the command using the indicated callback
/// </summary>
/// <param name="callback">callback to handle the command</param>
/// <param name="ignoreUp">whether keyup actions will be ignored by this handler (like lifting a key or releasing
/// mouse button)</param>
public PointerInputCmdHandler(PointerInputCmdDelegate2 callback, bool ignoreUp = true, bool outsidePrediction = false)
{
_callback = callback;
_ignoreUp = ignoreUp;
FireOutsidePrediction = outsidePrediction;
}
public override bool HandleCmdMessage(IEntityManager entManager, ICommonSession? session, IFullInputCmdMessage message)
{
if ((_ignoreUp && message.State != BoundKeyState.Down))
return false;
switch (message)
{
case ClientFullInputCmdMessage clientInput:
{
var handled = _callback?.Invoke(new PointerInputCmdArgs(session, clientInput.Coordinates,
clientInput.ScreenCoordinates, clientInput.Uid, message.State, message));
return handled.HasValue && handled.Value;
}
case FullInputCmdMessage fullInput:
{
var handled = _callback?.Invoke(new PointerInputCmdArgs(session, entManager.GetCoordinates(fullInput.Coordinates),
fullInput.ScreenCoordinates, entManager.GetEntity(fullInput.Uid), fullInput.State, message));
return handled.HasValue && handled.Value;
}
default:
throw new ArgumentOutOfRangeException();
}
}
public readonly struct PointerInputCmdArgs
{
public readonly ICommonSession? Session;
public readonly EntityCoordinates Coordinates;
public readonly ScreenCoordinates ScreenCoordinates;
public readonly EntityUid EntityUid;
public readonly BoundKeyState State;
public readonly IFullInputCmdMessage OriginalMessage;
public PointerInputCmdArgs(ICommonSession? session, EntityCoordinates coordinates,
ScreenCoordinates screenCoordinates, EntityUid entityUid, BoundKeyState state,
IFullInputCmdMessage originalMessage)
{
Session = session;
Coordinates = coordinates;
ScreenCoordinates = screenCoordinates;
EntityUid = entityUid;
State = state;
OriginalMessage = originalMessage;
}
}
}
public sealed class PointerStateInputCmdHandler : InputCmdHandler
{
private PointerInputCmdDelegate _enabled;
private PointerInputCmdDelegate _disabled;
public override bool FireOutsidePrediction { get; }
public PointerStateInputCmdHandler(PointerInputCmdDelegate enabled, PointerInputCmdDelegate disabled, bool outsidePrediction = false)
{
_enabled = enabled;
_disabled = disabled;
FireOutsidePrediction = outsidePrediction;
}
/// <inheritdoc />
public override bool HandleCmdMessage(IEntityManager entManager, ICommonSession? session, IFullInputCmdMessage message)
{
switch (message)
{
case ClientFullInputCmdMessage clientInput:
switch (clientInput.State)
{
case BoundKeyState.Up:
return _disabled?.Invoke(session, clientInput.Coordinates, clientInput.Uid) == true;
case BoundKeyState.Down:
return _enabled?.Invoke(session, clientInput.Coordinates, clientInput.Uid) == true;
}
break;
case FullInputCmdMessage fullInput:
switch (fullInput.State)
{
case BoundKeyState.Up:
return _disabled?.Invoke(session, entManager.GetCoordinates(fullInput.Coordinates), entManager.GetEntity(fullInput.Uid)) == true;
case BoundKeyState.Down:
return _enabled?.Invoke(session, entManager.GetCoordinates(fullInput.Coordinates), entManager.GetEntity(fullInput.Uid)) == true;
}
break;
}
//Client Sanitization: unknown key state, just ignore
return false;
}
}
/// <summary>
/// Consumes both up and down states without calling any handler delegates. Primarily used on the client to
/// prevent an input message from being sent to the server.
/// </summary>
public sealed class NullInputCmdHandler : InputCmdHandler
{
/// <inheritdoc />
public override bool HandleCmdMessage(IEntityManager entManager, ICommonSession? session, IFullInputCmdMessage message)
{
return true;
}
}
}