S&box Wiki

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;⤶ }⤶ }⤶ ```