Revision Difference
Usable_Entities#548129
<cat>Code.Entity</cat>⤶
<title>Usable Entities</title>⤶
⤶
Entities can be made usable by players (as well as NPCs and anything else should the game developers choose to do so) via the [IUse](https://asset.party/api/Sandbox.IUse) interface.⤶
⤶
# Example usage⤶
⤶
Marking entity as usable is very easy, by simply implementing the aforementioned **IUse** interface:⤶
⤶
```⤶
public partial class MyEntity: ModelEntity, IUse⤶
{⤶
// Other entity code...⤶
⤶
public bool OnUse( Entity user )⤶
{⤶
// Do something when entity is used...⤶
⤶
Log.Info( $"{this} has been used by {user}!" );⤶
⤶
return false;⤶
}⤶
⤶
public bool IsUsable( Entity user )⤶
{⤶
// Disallow using the entity when some condition is or is not met⤶
if ( SomeCondition == false ) return false;⤶
return true;⤶
}⤶
}⤶
```⤶
⤶
Full documentation about **IUse** can be found on⤶
[the API documentation website](https://asset.party/api/Sandbox.IUse) and in your IDE.⤶
⤶
# Game implementation⤶
⤶
Once you have your entities set up, you might need to set up your game to use the **IUse** interface if it doesn't do this already.⤶
⤶
Example implementation might look something like this:⤶
⤶
```csharp⤶
public partial class Player⤶
{⤶
/// <summary>⤶
/// Entity the player is currently using via their interaction key.⤶
/// </summary>⤶
public Entity Using { get; protected set; }⤶
⤶
/// <summary>⤶
/// This should be called somewhere in your player's tick to allow them to use entities,⤶
/// for example the Simulate callback method of the player pawn entity.⤶
/// </summary>⤶
protected virtual void TickPlayerUse()⤶
{⤶
// This is serverside only⤶
if ( !Host.IsServer ) return;⤶
⤶
// Turn prediction off⤶
using ( Prediction.Off() )⤶
{⤶
if ( Input.Pressed( InputButton.Use ) )⤶
{⤶
Using = FindUsable();⤶
⤶
if ( Using == null )⤶
{⤶
UseFail();⤶
return;⤶
}⤶
}⤶
⤶
if ( !Input.Down( InputButton.Use ) )⤶
{⤶
StopUsing();⤶
return;⤶
}⤶
⤶
if ( !Using.IsValid() )⤶
return;⤶
⤶
// If we move too far away or something we should probably ClearUse()?⤶
⤶
//⤶
// If use returns true then we can keep using it⤶
//⤶
if ( Using is IUse use && use.OnUse( this ) )⤶
return;⤶
⤶
StopUsing();⤶
}⤶
}⤶
⤶
/// <summary>⤶
/// Player tried to use something but there was nothing there.⤶
/// Tradition is to give a disappointed boop.⤶
/// </summary>⤶
protected virtual void UseFail()⤶
{⤶
PlaySound( "player_use_fail" );⤶
}⤶
⤶
/// <summary>⤶
/// If we're using an entity, stop using it⤶
/// </summary>⤶
protected virtual void StopUsing()⤶
{⤶
Using = null;⤶
}⤶
⤶
/// <summary>⤶
/// Returns if the entity is a valid usable entity⤶
/// </summary>⤶
protected bool IsValidUseEntity( Entity e )⤶
{⤶
if ( e == null ) return false;⤶
if ( e is not IUse use ) return false;⤶
if ( !use.IsUsable( this ) ) return false;⤶
⤶
return true;⤶
}⤶
⤶
/// <summary>⤶
/// Find a usable entity for this player to use⤶
/// </summary>⤶
protected virtual Entity FindUsable()⤶
{⤶
// First try a direct 0 width line⤶
var tr = Trace.Ray( EyePosition, EyePosition + EyeRotation.Forward * 85 )⤶
.Ignore( this )⤶
.Run();⤶
⤶
// See if any of the parent entities are usable if we ain't.⤶
var ent = tr.Entity;⤶
while ( ent.IsValid() && !IsValidUseEntity( ent ) )⤶
{⤶
ent = ent.Parent;⤶
}⤶
⤶
// Nothing found, try a wider search⤶
if ( !IsValidUseEntity( ent ) )⤶
{⤶
tr = Trace.Ray( EyePosition, EyePosition + EyeRotation.Forward * 85 )⤶
.Radius( 2 )⤶
.Ignore( this )⤶
.Run();⤶
⤶
// See if any of the parent entities are usable if we ain't.⤶
ent = tr.Entity;⤶
while ( ent.IsValid() && !IsValidUseEntity( ent ) )⤶
{⤶
ent = ent.Parent;⤶
}⤶
}⤶
⤶
// Still no good? Bail.⤶
if ( !IsValidUseEntity( ent ) ) return null;⤶
⤶
return ent;⤶
}⤶
}⤶
```