display dialog on button interact with human
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-05-05 18:11:20 -04:00
parent 800c45033b
commit f1b27c631b
9 changed files with 164 additions and 44 deletions

View File

@ -683,7 +683,10 @@
"Leg.R", "LowerLeg.R", "Foot.R"
]
}
]
],
"buttonInteraction" : {
"onInteract" : "dialog"
}
}
],
"files" : []

View File

@ -0,0 +1,70 @@
package electrosphere.client.interact;
import org.joml.Vector3d;
import electrosphere.client.entity.camera.CameraEntityUtils;
import electrosphere.client.entity.crosshair.Crosshair;
import electrosphere.client.ui.menu.WindowUtils;
import electrosphere.client.ui.menu.dialog.DialogMenuGenerator;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.entity.types.common.CommonEntityFlags;
import electrosphere.entity.types.common.CommonEntityUtils;
import electrosphere.game.data.common.interact.InteractionData;
import electrosphere.net.parser.net.message.EntityMessage;
/**
* Stores logic for interaction button
*/
public class ButtonInteraction {
/**
* Handles a button interaction event
*/
public static void handleButtonInteraction(){
if(Globals.playerEntity != null && Globals.playerCamera != null){
Entity camera = Globals.playerCamera;
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera)).mul(-1.0);
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
Entity target = ClientInteractionEngine.rayCast(centerPos, eyePos);
if(target != null && CommonEntityFlags.isInteractable(target)){
Globals.interactionTarget = target;
ButtonInteraction.performInteraction(target);
} else if(ClientEquipState.hasEquipState(Globals.playerEntity) && Crosshair.hasTarget()){
if(InventoryUtils.hasNaturalInventory(Globals.playerEntity)){
InventoryUtils.clientAttemptStoreItem(Globals.playerEntity, Crosshair.getTarget());
}
}
}
}
/**
* Performs a button interaction
* @param target The targeted entity
*/
private static void performInteraction(Entity target){
InteractionData interactionData = CommonEntityUtils.getCommonData(target).getButtonInteraction();
switch(interactionData.getOnInteract()){
case InteractionData.ON_INTERACT_MENU: {
WindowUtils.openInteractionMenu(interactionData.getWindowTarget(), interactionData.getWindowData());
} break;
case InteractionData.ON_INTERACT_HARVEST: {
int serverEntityId = Globals.clientSceneWrapper.mapClientToServerId(target.getId());
Globals.clientConnection.queueOutgoingMessage(EntityMessage.constructinteractMessage(serverEntityId, InteractionData.ON_INTERACT_HARVEST));
} break;
case InteractionData.ON_INTERACT_DOOR: {
int serverEntityId = Globals.clientSceneWrapper.mapClientToServerId(target.getId());
Globals.clientConnection.queueOutgoingMessage(EntityMessage.constructinteractMessage(serverEntityId, InteractionData.ON_INTERACT_DOOR));
} break;
case InteractionData.ON_INTERACT_DIALOG: {
DialogMenuGenerator.displayDialog(target);
} break;
default: {
throw new Error("Unhandled interaction signal " + interactionData.getOnInteract());
}
}
}
}

View File

@ -90,4 +90,9 @@ public class WindowStrings {
*/
public static final String TOOLBAR_PREVIEW = "toolbarPreview";
/**
* The npc dialog window
*/
public static final String NPC_DIALOG = "npcDialog";
}

View File

@ -61,8 +61,8 @@ public class ImGuiUIFramework {
private static void printUITrees(){
int i = 0;
for(Element window : Globals.elementService.getWindowList()){
LoggerInterface.loggerUI.WARNING("Window " + i);
printUITree(window, 1);
LoggerInterface.loggerUI.WARNING("Window " + i + " " + Globals.elementService.getWindowId(window));
ImGuiUIFramework.printUITree(window, 1);
LoggerInterface.loggerUI.WARNING("----\n\n");
i++;
}

View File

@ -6,36 +6,77 @@ import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Node;
import electrosphere.client.ui.menu.WindowStrings;
import electrosphere.client.ui.menu.WindowUtils;
import electrosphere.client.ui.parsing.HtmlParser;
import electrosphere.controls.ControlHandler.ControlsState;
import electrosphere.engine.Globals;
import electrosphere.engine.signal.Signal.SignalType;
import electrosphere.entity.Entity;
import electrosphere.renderer.ui.elements.Div;
import electrosphere.renderer.ui.elementtypes.Element;
import electrosphere.renderer.ui.elements.Window;
import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaAlignment;
import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaJustification;
import electrosphere.renderer.ui.elementtypes.NavigableElement.NavigationEventCallback;
import electrosphere.renderer.ui.events.NavigationEvent;
import electrosphere.util.FileUtils;
/**
* Generates dialog menus
*/
public class DialogMenuGenerator {
/**
* Displays the appropriate dialog for opening a dialog window with a given entity
* @param target The entity
*/
public static void displayDialog(Entity target){
WindowUtils.replaceWindow(WindowStrings.NPC_DIALOG, DialogMenuGenerator.displayDialog("Data/menu/npcintro.html"));
Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_MAIN_MENU);
}
/**
* Displays a dialog menu
* @param path The path to the html
* @return The element that is the root for the window
*/
public static Element displayDialog(String path){
public static Window displayDialog(String path){
//
//Boilerplate for window itself
//
Window rVal = Window.createExpandableCenterAligned(Globals.renderingEngine.getOpenGLState());
rVal.setParentAlignItem(YogaAlignment.Center);
rVal.setParentJustifyContent(YogaJustification.Center);
rVal.setOnNavigationCallback(new NavigationEventCallback() {public boolean execute(NavigationEvent event){
WindowUtils.recursiveSetVisible(Globals.elementService.getWindow(WindowStrings.NPC_DIALOG), false);
return false;
}});
//
//main dialog ui logic
//
Div container = Div.createCol();
try {
String content = FileUtils.getAssetFileAsString(path);
Document doc = Jsoup.parseBodyFragment(content);
Node bodyNode = doc.getElementsByTag("body").first();
for(Node node : bodyNode.childNodes()){
container.addChild(
HtmlParser.recursivelyParseChildren(node));
container.addChild(HtmlParser.recursivelyParseChildren(node));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return container;
rVal.addChild(container);
//
//Final setup
//
Globals.signalSystem.post(SignalType.YOGA_APPLY, rVal);
return rVal;
}
}

View File

@ -40,7 +40,7 @@ public class HtmlParser {
throw new Error("Unsupported element type " + tag);
}
}
return Div.createDiv();
return rVal;
}
}

View File

@ -9,7 +9,7 @@ import org.lwjgl.glfw.GLFW;
import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType;
import electrosphere.client.entity.camera.CameraEntityUtils;
import electrosphere.client.entity.crosshair.Crosshair;
import electrosphere.client.interact.ClientInteractionEngine;
import electrosphere.client.interact.ButtonInteraction;
import electrosphere.client.interact.ItemActions;
import electrosphere.client.ui.components.PlayerInventoryWindow;
import electrosphere.client.ui.menu.WindowStrings;
@ -40,12 +40,8 @@ import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.M
import electrosphere.entity.state.movement.jump.ClientJumpTree;
import electrosphere.entity.state.movement.sprint.ClientSprintTree;
import electrosphere.entity.state.movement.walk.ClientWalkTree;
import electrosphere.entity.types.common.CommonEntityFlags;
import electrosphere.entity.types.common.CommonEntityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.game.data.common.interact.InteractionData;
import electrosphere.game.data.item.Item;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.renderer.ui.elements.Window;
import electrosphere.renderer.ui.events.MouseEvent;
import electrosphere.renderer.ui.events.ScrollEvent;
@ -654,36 +650,7 @@ public class ControlCategoryMainGame {
*/
mainGameControlList.add(controlMap.get(INPUT_CODE_INTERACT));
controlMap.get(INPUT_CODE_INTERACT).setOnPress(new ControlMethod(){public void execute(MouseState mouseState){
if(Globals.playerEntity != null && Globals.playerCamera != null){
Entity camera = Globals.playerCamera;
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera)).mul(-1.0);
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
Entity target = ClientInteractionEngine.rayCast(centerPos, eyePos);
if(target != null && CommonEntityFlags.isInteractable(target)){
Globals.interactionTarget = target;
InteractionData interactionData = CommonEntityUtils.getCommonData(target).getButtonInteraction();
switch(interactionData.getOnInteract()){
case InteractionData.ON_INTERACT_MENU: {
WindowUtils.openInteractionMenu(interactionData.getWindowTarget(), interactionData.getWindowData());
} break;
case InteractionData.ON_INTERACT_HARVEST: {
int serverEntityId = Globals.clientSceneWrapper.mapClientToServerId(target.getId());
Globals.clientConnection.queueOutgoingMessage(EntityMessage.constructinteractMessage(serverEntityId, InteractionData.ON_INTERACT_HARVEST));
} break;
case InteractionData.ON_INTERACT_DOOR: {
int serverEntityId = Globals.clientSceneWrapper.mapClientToServerId(target.getId());
Globals.clientConnection.queueOutgoingMessage(EntityMessage.constructinteractMessage(serverEntityId, InteractionData.ON_INTERACT_DOOR));
} break;
default: {
throw new Error("Unhandled interaction signal " + interactionData.getOnInteract());
}
}
} else if(ClientEquipState.hasEquipState(Globals.playerEntity) && Crosshair.hasTarget()){
if(InventoryUtils.hasNaturalInventory(Globals.playerEntity)){
InventoryUtils.clientAttemptStoreItem(Globals.playerEntity, Crosshair.getTarget());
}
}
}
ButtonInteraction.handleButtonInteraction();
}});
/*

View File

@ -21,6 +21,11 @@ public class InteractionData {
* Try opening/closing a door
*/
public static final String ON_INTERACT_DOOR = "door";
/**
* A dialog interaction
*/
public static final String ON_INTERACT_DIALOG = "dialog";
/**
* The function to run on interaction
@ -42,6 +47,11 @@ public class InteractionData {
*/
CollidableTemplate interactionShape;
/**
* Configures the interaction to be client-side only
*/
Boolean clientOnly;
/**
* Gets the function to run on interaction
* @return The function to run on interaction

View File

@ -4,6 +4,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap;
@ -124,6 +125,25 @@ public class ElementService extends SignalServiceImpl {
lock.unlock();
}
/**
* Gets the id of a window
* @param window The window
* @return The id if it has an assigned id, null otherwise
*/
public String getWindowId(Element window){
for(Entry<String,Element> windowEntry : this.elementMap.entrySet()){
if(windowEntry.getValue().equals(window)){
return windowEntry.getKey();
}
}
return null;
}
/**
* Checks if the element service contains a window
* @param name The name of the window
* @return true if the service contains the window, false otheriwse
*/
public boolean containsWindow(String name){
lock.lock();
boolean rVal = elementMap.containsKey(name);
@ -131,6 +151,10 @@ public class ElementService extends SignalServiceImpl {
return rVal;
}
/**
* Pushes a window to the front of the drawing stack
* @param window The window
*/
public void pushWindowToFront(Window window){
lock.lock();
elementList.remove(window);