fab selection tool
Some checks reported errors
studiorailgun/Renderer/pipeline/head Something is wrong with the build of this commit

This commit is contained in:
austin 2025-04-26 11:38:50 -04:00
parent 42e6e1aae8
commit 383a3b6ac3
10 changed files with 338 additions and 18 deletions

View File

@ -126,6 +126,37 @@
"offsetZ" : 0
},
"iconPath" : "Textures/icons/itemIconItemGeneric.png"
},
{
"id" : "fabTool",
"tokens" : [
"GRAVITY",
"TARGETABLE",
"CURSOR"
],
"equipData": {
"equipClass" : "tool"
},
"graphicsTemplate": {
"model": {
"path" : "Models/basic/geometry/unitvector.glb"
}
},
"clientSideSecondary": "SELECT_FAB",
"collidable": {
"type" : "CUBE",
"dimension1" : 0.1,
"dimension2" : 0.1,
"dimension3" : 0.35,
"rotX": 0,
"rotY": 0,
"rotZ": 0,
"rotW": 1,
"offsetX" : 0,
"offsetY" : 0.05,
"offsetZ" : 0
},
"iconPath" : "Textures/icons/itemIconItemGeneric.png"
}
],
"files" : [

View File

@ -46,5 +46,11 @@ export const clientHooks: Hook[] = [
callback: (engine: Engine) => {
engine.classes.voxelUtils.static.dig()
}
},
{
signal: "SELECT_FAB",
callback: (engine: Engine) => {
engine.classes.menuUtils.static.openFabSelection()
}
}
]

View File

@ -13,4 +13,9 @@ export interface MenuUtils {
*/
readonly openSpawnSelection: () => void
/**
* Opens the menu to select what fab to use
*/
readonly openFabSelection: () => void
}

View File

@ -1542,6 +1542,7 @@ Block area selection
(04/26/2025)
Exporting block prefabs to compressed files
Minor block fab improvements
Fab selection tool

View File

@ -0,0 +1,168 @@
package electrosphere.client.ui.components;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import org.joml.Vector4f;
import electrosphere.client.ui.menu.WindowStrings;
import electrosphere.client.ui.menu.YogaUtils;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.renderer.ui.elements.Button;
import electrosphere.renderer.ui.elements.Div;
import electrosphere.renderer.ui.elements.ImagePanel;
import electrosphere.renderer.ui.elements.Label;
import electrosphere.renderer.ui.elements.TextInput;
import electrosphere.renderer.ui.elements.VirtualScrollable;
import electrosphere.renderer.ui.elementtypes.ClickableElement.ClickEventCallback;
import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaAlignment;
import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaFlexDirection;
import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaJustification;
import electrosphere.renderer.ui.elementtypes.Element;
import electrosphere.renderer.ui.elementtypes.HoverableElement.HoverEventCallback;
import electrosphere.renderer.ui.elementtypes.KeyEventElement.KeyboardEventCallback;
import electrosphere.renderer.ui.events.ClickEvent;
import electrosphere.renderer.ui.events.HoverEvent;
import electrosphere.renderer.ui.events.KeyboardEvent;
/**
* Panel for selecting fab files
*/
public class FabSelectionPanel {
//text input
static final int TEXT_INPUT_HEIGHT = 50;
static final int TEXT_INPUT_WIDTH = 200;
//single fab button
static final int FAB_BUTTON_WIDTH = 90;
static final int FAB_BUTTON_HEIGHT = 90;
static final int FAB_BUTTON_TEXTURE_DIM = 70;
static final int MARGIN_EACH_SIDE = 5;
//fab selection
static final int FAB_SCROLLABLE_WIDTH = FAB_BUTTON_WIDTH * 5;
static final int FAB_SCROLLABLE_HEIGHT = FAB_BUTTON_HEIGHT * 5;
/**
* The color of the select fab type
*/
static final Vector4f ELEMENT_COLOR_SELECTED = new Vector4f(1,0,0,1);
/**
* Creates the fab selection panel component
* @return The top level element of the panel component
*/
public static Div createFabSelectionPanel(Consumer<File> onSelectType){
//setup window
Div rVal = Div.createDiv();
rVal.setAlignContent(YogaAlignment.Center);
rVal.setAlignItems(YogaAlignment.Center);
rVal.setJustifyContent(YogaJustification.Center);
rVal.setFlexDirection(YogaFlexDirection.Column);
//scrollable that contains all the fab types
VirtualScrollable scrollable = new VirtualScrollable(FAB_SCROLLABLE_WIDTH, FAB_SCROLLABLE_HEIGHT);
scrollable.setFlexDirection(YogaFlexDirection.Column);
scrollable.setAlignItems(YogaAlignment.Start);
//search input
TextInput searchInput = TextInput.createTextInput();
searchInput.setWidth(TEXT_INPUT_WIDTH);
searchInput.setMinWidth(TEXT_INPUT_WIDTH);
searchInput.setMinHeight(20);
searchInput.setOnPress(new KeyboardEventCallback() {public boolean execute(KeyboardEvent event){
boolean rVal = searchInput.defaultKeyHandling(event);
FabSelectionPanel.fillInFabSelectors(scrollable, searchInput.getText(), onSelectType);
return rVal;
}});
rVal.addChild(searchInput);
//attach scrollable after search input for organzation purposes
rVal.addChild(scrollable);
//final step
FabSelectionPanel.fillInFabSelectors(scrollable, searchInput.getText(), onSelectType);
return rVal;
}
/**
* Fills in the fab files to display based on the contents of the search string
* @param scrollable the scrollable to drop selection buttons in to
* @param searchString the string to search based on
*/
static void fillInFabSelectors(VirtualScrollable scrollable, String searchString, Consumer<File> onSelectType){
Element containingWindow = null;
if(Globals.elementService.getWindow(WindowStrings.FAB_SELECTION) != null){
containingWindow = Globals.elementService.getWindow(WindowStrings.FAB_SELECTION);
} else if(Globals.elementService.getWindow(WindowStrings.WINDOW_MENU_MAIN) != null){
containingWindow = Globals.elementService.getWindow(WindowStrings.WINDOW_MENU_MAIN);
}
YogaUtils.refreshComponent(containingWindow, () -> {
scrollable.clearChildren();
Div currentRow = null;
int incrementer = 0;
//generate fab file buttons
List<File> fabFiles = Arrays.asList(new File("./assets/Data/fab").listFiles());
for(File fabFile : fabFiles){
if(incrementer % 4 == 0){
currentRow = Div.createRow();
currentRow.setJustifyContent(YogaJustification.Evenly);
scrollable.addChild(currentRow);
}
Div containerDiv = Div.createDiv();
containerDiv.setMinWidthPercent(25.0f);
currentRow.addChild(containerDiv);
Button newButton = new Button();
newButton.setAlignItems(YogaAlignment.Center);
//dimensions
newButton.setMinWidth(FAB_BUTTON_WIDTH);
newButton.setMinHeight(FAB_BUTTON_HEIGHT);
//margin
newButton.setMarginBottom(MARGIN_EACH_SIDE);
newButton.setMarginLeft(MARGIN_EACH_SIDE);
newButton.setMarginRight(MARGIN_EACH_SIDE);
newButton.setMarginTop(MARGIN_EACH_SIDE);
//label
Label fabLabel = Label.createLabel(fabFile.getName());
//icon/model
ImagePanel texturePanel = ImagePanel.createImagePanel(AssetDataStrings.TEXTURE_DEFAULT);
texturePanel.setWidth(FAB_BUTTON_TEXTURE_DIM);
texturePanel.setHeight(FAB_BUTTON_TEXTURE_DIM);
texturePanel.setMarginBottom(MARGIN_EACH_SIDE);
texturePanel.setMarginLeft(MARGIN_EACH_SIDE);
texturePanel.setMarginRight(MARGIN_EACH_SIDE);
texturePanel.setMarginTop(MARGIN_EACH_SIDE);
newButton.addChild(texturePanel);
texturePanel.setAlignSelf(YogaAlignment.Center);
//causes the texture panel to also behave as if the button was hovered
texturePanel.setOnHoverCallback(new HoverEventCallback() {public boolean execute(HoverEvent event) {
return newButton.handleEvent(event);
}});
//button handling
newButton.addChild(fabLabel);
newButton.setOnClick(new ClickEventCallback() {public boolean execute(ClickEvent event){
//accept the selected file
onSelectType.accept(fabFile);
FabSelectionPanel.fillInFabSelectors(scrollable, searchString, onSelectType);
return false;
}});
containerDiv.addChild(newButton);
incrementer++;
}
for(int i = incrementer; i % 4 != 0; i++){
Div spacerDiv = Div.createDiv();
spacerDiv.setMinWidthPercent(25.0f);
currentRow.addChild(spacerDiv);
}
});
}
}

View File

@ -5,42 +5,71 @@ package electrosphere.client.ui.menu;
*/
public class WindowStrings {
//the main menu
/**
* the main menu
*/
public static final String WINDOW_MENU_MAIN = "windowMenuMain";
//the ingame main menu
/**
* the ingame main menu
*/
public static final String WINDOW_MENU_INGAME_MAIN = "windowMenuInGameMain";
//the string used to generate inventory menus
/**
* the string used to generate inventory menus
*/
public static final String WINDOW_MENU_INVENTORY = "windowMenuInventory";
//a window that shows the text 'loading'
/**
* a window that shows the text 'loading'
*/
public static final String WINDOW_LOADING = "windowLoading";
//the window used to receive drag events for dropping items
/**
* the window used to receive drag events for dropping items
*/
public static final String WINDDOW_ITEM_DROP = "itemDrop";
//the window used as a container for item icons for drawing dragging them around the screen
/**
* the window used as a container for item icons for drawing dragging them around the screen
*/
public static final String WINDOW_ITEM_DRAG_CONTAINER = "itemDragContainer";
//the window for displaying information about the character
/**
* the window for displaying information about the character
*/
public static final String WINDOW_CHARACTER = "windowCharacter";
//the debug menu
/**
* the debug menu
*/
public static final String WINDOW_DEBUG = "windowDebug";
//the level editor menu
/**
* the level editor menu
*/
public static final String LEVEL_EDTIOR_SIDE_PANEL = "levelEditor";
//the voxel type selection menu
/**
* the voxel type selection menu
*/
public static final String VOXEL_TYPE_SELECTION = "voxelTypeSelection";
//the voxel type selection menu
/**
* the voxel type selection menu
*/
public static final String SPAWN_TYPE_SELECTION = "spawnTypeSelection";
//the tutorial popup
/**
* the tutorial popup
*/
public static final String TUTORIAL_POPUP = "tutorialPopup";
/**
* The fab selection menu
*/
public static final String FAB_SELECTION = "fabSelection";
/**
* Window for displaying tooltip elements
*/

View File

@ -0,0 +1,65 @@
package electrosphere.client.ui.menu.ingame;
import java.io.File;
import electrosphere.client.ui.components.FabSelectionPanel;
import electrosphere.client.ui.menu.WindowStrings;
import electrosphere.client.ui.menu.WindowUtils;
import electrosphere.controls.ControlHandler.ControlsState;
import electrosphere.engine.Globals;
import electrosphere.engine.signal.Signal.SignalType;
import electrosphere.renderer.ui.elements.Window;
import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaAlignment;
import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaFlexDirection;
import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaJustification;
import electrosphere.renderer.ui.elementtypes.NavigableElement.NavigationEventCallback;
import electrosphere.renderer.ui.events.NavigationEvent;
/**
* Menus to deal with fab files
*/
public class FabMenus {
/**
* The fab selection window
*/
static Window fabSelectionWindow;
//width of the panel
static final int WINDOW_WIDTH = 550;
static final int WINDOW_HEIGHT = 550;
/**
* Creates the level editor side panel window
* @return
*/
public static Window createVoxelTypeSelectionPanel(){
//setup window
Window fabSelectionPanelWindow = Window.create(Globals.renderingEngine.getOpenGLState(), 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, true);
fabSelectionPanelWindow.setParentAlignContent(YogaAlignment.Center);
fabSelectionPanelWindow.setParentJustifyContent(YogaJustification.Center);
fabSelectionPanelWindow.setParentAlignItem(YogaAlignment.Center);
fabSelectionPanelWindow.setAlignContent(YogaAlignment.Center);
fabSelectionPanelWindow.setAlignItems(YogaAlignment.Center);
fabSelectionPanelWindow.setJustifyContent(YogaJustification.Center);
fabSelectionPanelWindow.setFlexDirection(YogaFlexDirection.Column);
//nav logic
fabSelectionPanelWindow.setOnNavigationCallback(new NavigationEventCallback() {public boolean execute(NavigationEvent event){
WindowUtils.closeWindow(WindowStrings.FAB_SELECTION);
Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME);
MenuGeneratorsLevelEditor.voxelWindowOpen = false;
return false;
}});
//attach scrollable after search input for organzation purposes
fabSelectionPanelWindow.addChild(FabSelectionPanel.createFabSelectionPanel((File selectedFile) -> {
System.out.println(selectedFile);
}));
Globals.signalSystem.post(SignalType.YOGA_APPLY,fabSelectionPanelWindow);
return fabSelectionPanelWindow;
}
}

View File

@ -4,6 +4,7 @@ import org.graalvm.polyglot.HostAccess.Export;
import electrosphere.client.ui.menu.WindowStrings;
import electrosphere.client.ui.menu.WindowUtils;
import electrosphere.client.ui.menu.ingame.FabMenus;
import electrosphere.client.ui.menu.ingame.MenuGeneratorsTerrainEditing;
import electrosphere.controls.ControlHandler.ControlsState;
import electrosphere.engine.Globals;
@ -31,4 +32,13 @@ public class ScriptMenuUtils {
Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_MAIN_MENU);
}
/**
* Opens the menu to select what fab to use
*/
@Export
public static void openFabSelection(){
WindowUtils.replaceWindow(WindowStrings.FAB_SELECTION,FabMenus.createVoxelTypeSelectionPanel());
Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_MAIN_MENU);
}
}

View File

@ -26,6 +26,7 @@ import electrosphere.net.server.ServerConnectionHandler;
import electrosphere.net.server.player.Player;
import electrosphere.net.server.protocol.CharacterProtocol;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerWorldData;
import electrosphere.server.simulation.MicroSimulation;
/**
@ -167,6 +168,7 @@ public class LoadingUtils {
template.getCreatureToolbarData().setSlotItem("1", new ToolbarItem(72, "spawningPalette"));
template.getCreatureToolbarData().setSlotItem("2", new ToolbarItem(73, "entityinspector"));
template.getCreatureToolbarData().setSlotItem("3", new ToolbarItem(74, "waterSpawner"));
template.getCreatureToolbarData().setSlotItem("4", new ToolbarItem(75, "fabTool"));
//set player character template
serverPlayerConnection.setCreatureTemplate(template);
Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructRequestSpawnCharacterMessage(CharacterProtocol.SPAWN_EXISTING_TEMPLATE + ""));
@ -176,9 +178,9 @@ public class LoadingUtils {
Realm realm = Globals.realmManager.getRealms().iterator().next();
Vector3d spawnPoint = realm.getSpawnPoint();
playerObject.setWorldPos(new Vector3i(
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.x),
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.y),
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.z)
ServerWorldData.convertRealToChunkSpace(spawnPoint.x),
ServerWorldData.convertRealToChunkSpace(spawnPoint.y),
ServerWorldData.convertRealToChunkSpace(spawnPoint.z)
));
}

View File

@ -26,6 +26,7 @@ import electrosphere.net.template.ServerProtocolTemplate;
import electrosphere.server.character.CharacterService;
import electrosphere.server.character.PlayerCharacterCreation;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerWorldData;
import electrosphere.util.Utilities;
/**
@ -101,9 +102,9 @@ public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessag
//set client initial discrete position
connectionHandler.addMessagetoOutgoingQueue(
PlayerMessage.constructSetInitialDiscretePositionMessage(
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.x),
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.y),
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.z)
ServerWorldData.convertRealToChunkSpace(spawnPoint.x),
ServerWorldData.convertRealToChunkSpace(spawnPoint.y),
ServerWorldData.convertRealToChunkSpace(spawnPoint.z)
)
);
return rVal;
@ -141,6 +142,7 @@ public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessag
template.getCreatureToolbarData().setSlotItem("1", new ToolbarItem(72, "spawningPalette"));
template.getCreatureToolbarData().setSlotItem("2", new ToolbarItem(73, "entityinspector"));
template.getCreatureToolbarData().setSlotItem("3", new ToolbarItem(74, "waterSpawner"));
template.getCreatureToolbarData().setSlotItem("4", new ToolbarItem(75, "fabTool"));
//set player character template
connectionHandler.setCreatureTemplate(template);
} else {
@ -162,6 +164,7 @@ public class CharacterProtocol implements ServerProtocolTemplate<CharacterMessag
template.getCreatureToolbarData().setSlotItem("1", new ToolbarItem(72, "spawningPalette"));
template.getCreatureToolbarData().setSlotItem("2", new ToolbarItem(73, "entityinspector"));
template.getCreatureToolbarData().setSlotItem("3", new ToolbarItem(74, "waterSpawner"));
template.getCreatureToolbarData().setSlotItem("4", new ToolbarItem(75, "fabTool"));
//set player character template
connectionHandler.setCreatureTemplate(template);
}