S&box Wiki

Revision Difference

Usable_Entities#548389

<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; if ( !Game.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; } } ```