Maintenance Interaction Screens

Florian

Active Member
Contributor
Architecture
Tutorial available in the GitHub wiki

For some blocks or entities, an screen is necessary for the user to interact with it. For example a NPC could have a trade menu or a furnace a dialog where you can put materials in and out fo the furnace. The core module already contains such a dialog already: a default dialog for viewing chests.

As user you expect these interaction screens to have certain properties: For example you would except that the interaction dialog closes, when the interaction target gets out of reach. Vice versa you would except that the closing of the interaction dialog will terminate the interaction.

So I started working on a way to create a generic way of making interactions.

This patch series allows you to make Terasology to open an interaction dialog automatically when you press E, by just adding a simple component to an entity which should offer an interaction screen:

Code:
  "InteractionTarget": {},
  "InteractionScreen": {
    "screen": "engine:containerScreen"
  },
The first component specifies that an interaction can be started with E with the entity. The second component allows you to link an user interface to the interaction. It gets opened automatically when the transaction starts and when you close it the interaction will automatically terminated for you.

Because of network delay, there can be a difference between the request to start an interaction on the client and the confirmation of the server that the interaction is valid. To provide the user with an responsive UI, the clients predicts the start of the interaction and shows the UI instantly. This predicted start of an interaction gets signaled with an InteractionStartPredicted event which gets sent to the target entity. Likewise there is an InteractionEndPredicted event when the client predicts an interaction end.

For interaction screens it is important to know with which object the character is interacting with. The predicted interaction target can be obtained from the character via a predictedInteractionTarget field in the CharacterComponent. The character can be obtained from the local player which can be obtained via dependency injection. For an example have a look at the ContainerScreen class (on a branch with my patches):
Code:
    @In
    private LocalPlayer localPlayer;
// ...
        containerInventory.bindTargetEntity(new ReadOnlyBinding<EntityRef>() {
            @Override
            public EntityRef get() {
                EntityRef characterEntity = localPlayer.getCharacterEntity();
                CharacterComponent characterComponent = characterEntity.getComponent(CharacterComponent.class);
                return characterComponent.predictedInteractionTarget;
            }
        });
For user actions that get validated by the authority (server), there is a authorizedInteractionTarget field in the CharacterComponent which describes the confirmed interaction status of the character. Confirming actions on the server is important to prevent cheating. Otherwise a cheater may fake the button press on an interaction screen even when he isn't even close enough for an interaction.
 
Last edited by a moderator:

Josharias

Conjurer of Grimoires
Contributor
World
SpecOps
I started messing around with this PR and Workstations/Machines. It seems to work very well and fixes the multiplayer problems the original Workstation events had. Nice work Florian!
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
Merged! Feel free to wikify some stuff or enhance further first :)
 

Josharias

Conjurer of Grimoires
Contributor
World
SpecOps
Florian, what is the best way to use this system for a screen that is not dependent on a block? I noticed the normal inventory screen does not use it at all. This also pertains to my TerraTech module where I attempted to fake my way through with this code...

Code:
    @ReceiveEvent
    public void onPlayerProcessingButton(PlayerProcessingButton event, EntityRef player, CharacterComponent characterComponent) {
        if (event.getState() == ButtonState.DOWN) {
            TheHumanMachineComponent theHumanMachine = player.getComponent(TheHumanMachineComponent.class);
            characterComponent.predictedInteractionTarget = theHumanMachine.machineEntity;
            nuiManager.toggleScreen("Machines:DefaultMachine");
            event.consume();
        }
    }
Should I be using the events somehow instead? It looked like the events were mainly for the server side.
 

Florian

Active Member
Contributor
Architecture
The LocalPlayer has now a activateOwnedEntityAsClient method, which can be used to initiate an activation like this:
Code:
    @In
    LocalPlayer localPlayer;

    @ReceiveEvent
    public void onPlayerProcessingButton(PlayerProcessingButton event, EntityRef player, CharacterComponent characterComponent) {
        if (event.getState() == ButtonState.DOWN) {
            TheHumanMachineComponent theHumanMachine = player.getComponent(TheHumanMachineComponent.class);
            localPlayer.activateOwnedEntityAsClient(theHumanMachine.machineEntity);
            event.consume();
        }
    }
This will also trigger then an interaction, if the passed entity has InteractionTarget component. If the entity passed to activateOwnedEntityAsClient has also an InteractionScreen component, then the specified screen will be opened.

I created a pull requests which performs this change: https://github.com/Terasology/TerraTech/pull/31
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
Thanks a lot for the tutorial :) Don't forget to edit it into the top post here!

I know you're busy with auto save right now, but looking forward to more tutorials later, like an intro to inventory manipulation :3
 

Cervator

Org Co-Founder & Project Lead
Contributor
Design
Logistics
SpecOps
Edited top post a bit to add tutorial link and renamed thread to plain "Interaction Screens" :)

@Florian - would you say this is stable and in "Maintenance" now rather than the still-work-to-do "Tweaking" ?
 
Top