diff --git a/assets/Data/entity/items.json b/assets/Data/entity/items.json index 506696f4..7188af79 100644 --- a/assets/Data/entity/items.json +++ b/assets/Data/entity/items.json @@ -7,6 +7,7 @@ "Data/entity/items/debug_tools.json", "Data/entity/items/hand_tools.json", "Data/entity/items/clothing.json", - "Data/entity/items/materials.json" + "Data/entity/items/materials.json", + "Data/entity/items/fabs.json" ] } \ No newline at end of file diff --git a/assets/Data/entity/items/fabs.json b/assets/Data/entity/items/fabs.json new file mode 100644 index 00000000..4a9fd0d2 --- /dev/null +++ b/assets/Data/entity/items/fabs.json @@ -0,0 +1,7 @@ +{ + "items" : [ + ], + "files" : [ + "Data/entity/items/fabs/floors.json" + ] +} \ No newline at end of file diff --git a/assets/Data/entity/items/fabs/floors.json b/assets/Data/entity/items/fabs/floors.json new file mode 100644 index 00000000..7147b09d --- /dev/null +++ b/assets/Data/entity/items/fabs/floors.json @@ -0,0 +1,40 @@ +{ + "items" : [ + { + "id" : "woodfloor", + "tokens" : [ + "GRAVITY", + "TARGETABLE" + ], + "fabData" : { + "fabPath" : "Data/fab/wood_refined_floor.block" + }, + "clientSideSecondary" : "PLACE_FAB", + "itemAudio": { + "uiGrabAudio" : "Audio/ui/items/specific/Pick Up Wood A.wav", + "uiReleaseAudio" : "Audio/ui/items/specific/Drop Wood A.wav" + }, + "graphicsTemplate": { + "model": { + "path" : "Models/items/minicrate.glb" + } + }, + "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" : [ + ] +} \ No newline at end of file diff --git a/assets/Models/items/minicrate.glb b/assets/Models/items/minicrate.glb new file mode 100644 index 00000000..df6f1f24 Binary files /dev/null and b/assets/Models/items/minicrate.glb differ diff --git a/assets/Models/items/woodplanks1.png b/assets/Models/items/woodplanks1.png new file mode 100644 index 00000000..cb3584aa Binary files /dev/null and b/assets/Models/items/woodplanks1.png differ diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index ae8ff32b..a7ba3e18 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1602,6 +1602,7 @@ Flower foliage item Texture loading from model files (ie can load texture path from model file) Clean up material class a bit Cleaning up dead code +Fab items diff --git a/src/main/java/electrosphere/engine/assetmanager/AssetDataStrings.java b/src/main/java/electrosphere/engine/assetmanager/AssetDataStrings.java index 07789589..92727090 100644 --- a/src/main/java/electrosphere/engine/assetmanager/AssetDataStrings.java +++ b/src/main/java/electrosphere/engine/assetmanager/AssetDataStrings.java @@ -48,6 +48,11 @@ public class AssetDataStrings { public static final String UI_FRAME_TEXTURE_DEFAULT_2 = "Textures/ui/uiFrame2.png"; public static final String UI_FRAME_TEXTURE_DEFAULT_3 = "Textures/ui/panel-001.png"; + /** + * UI icon textures + */ + public static final String UI_TEXTURE_ITEM_ICON_GENERIC = "Textures/icons/itemIconItemGeneric.png"; + /** * UI generic audio */ diff --git a/src/main/java/electrosphere/entity/EntityDataStrings.java b/src/main/java/electrosphere/entity/EntityDataStrings.java index 74a58509..1ec70124 100644 --- a/src/main/java/electrosphere/entity/EntityDataStrings.java +++ b/src/main/java/electrosphere/entity/EntityDataStrings.java @@ -211,6 +211,11 @@ public class EntityDataStrings { public static final String ITEM_CONTAINING_PARENT = "itemContainingParent"; public static final String TREE_SERVERCHARGESTATE = "treeServerChargeState"; public static final String TREE_CLIENTCHARGESTATE = "treeClientChargeState"; + + /** + * Data for placing fabs with an item + */ + public static final String ITEM_FAB_DATA = "itemFabData"; /* diff --git a/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java b/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java index 231227f0..1412b1b1 100644 --- a/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java +++ b/src/main/java/electrosphere/entity/state/equip/ClientToolbarState.java @@ -9,6 +9,7 @@ import electrosphere.entity.state.inventory.InventoryUtils; import electrosphere.entity.state.inventory.RelationalInventoryState; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.item.ItemUtils; +import electrosphere.game.data.block.BlockFab; import electrosphere.game.data.common.treedata.TreeDataAnimation; import electrosphere.game.data.creature.type.equip.EquipPoint; import electrosphere.game.data.creature.type.equip.ToolbarData; @@ -31,6 +32,7 @@ import electrosphere.entity.EntityUtils; import electrosphere.net.synchronization.enums.BehaviorTreeIdEnums; import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.ActorMeshMask; +import electrosphere.util.FileUtils; import electrosphere.net.parser.net.message.InventoryMessage; import electrosphere.net.parser.net.message.NetworkMessage; import electrosphere.net.synchronization.annotation.SyncedField; @@ -191,6 +193,10 @@ public class ClientToolbarState implements BehaviorTree { } else if(itemData.getTokens().contains(CursorState.CURSOR_BLOCK_TOKEN)) { Globals.cursorState.setClampToExistingBlock(true); CursorState.makeBlockVisible(AssetDataStrings.TEXTURE_RED_TRANSPARENT); + } else if(itemData.getFabData() != null){ + Globals.cursorState.setSelectedFab(BlockFab.read(FileUtils.getAssetFile(itemData.getFabData().getFabPath()))); + Globals.cursorState.setSelectedFabPath(FileUtils.getAssetFileString(itemData.getFabData().getFabPath())); + CursorState.makeFabVisible(); } } } diff --git a/src/main/java/electrosphere/entity/types/item/ItemUtils.java b/src/main/java/electrosphere/entity/types/item/ItemUtils.java index 5a0131d1..e6ed07bc 100644 --- a/src/main/java/electrosphere/entity/types/item/ItemUtils.java +++ b/src/main/java/electrosphere/entity/types/item/ItemUtils.java @@ -7,9 +7,9 @@ import org.joml.Vector3d; import org.ode4j.ode.DBody; import electrosphere.collision.PhysicsEntityUtils; -import electrosphere.collision.PhysicsUtils; import electrosphere.collision.collidable.Collidable; import electrosphere.engine.Globals; +import electrosphere.engine.assetmanager.AssetDataStrings; import electrosphere.entity.ClientEntityUtils; import electrosphere.entity.Entity; import electrosphere.entity.EntityCreationUtils; @@ -47,9 +47,11 @@ import electrosphere.server.entity.poseactor.PoseActor; */ public class ItemUtils { - //generic item icon filepath - static final String genericItemIconPath = "Textures/icons/itemIconItemGeneric.png"; - + /** + * Spawns an item on the client + * @param name The name of the item type + * @return The item entity + */ public static Entity clientSpawnBasicItem(String name){ Item item = Globals.gameConfigCurrent.getItemMap().getItem(name); Entity rVal = EntityCreationUtils.createClientSpatialEntity(); @@ -81,7 +83,7 @@ public class ItemUtils { if(item.getIconPath() != null && !item.getIconPath().equals("")){ rVal.putData(EntityDataStrings.ITEM_ICON,item.getIconPath()); } else { - rVal.putData(EntityDataStrings.ITEM_ICON,genericItemIconPath); + rVal.putData(EntityDataStrings.ITEM_ICON,AssetDataStrings.UI_TEXTURE_ITEM_ICON_GENERIC); } if(item.getItemAudio() != null){ ItemAudio audio = item.getItemAudio(); @@ -108,6 +110,14 @@ public class ItemUtils { } } rVal.putData(EntityDataStrings.ITEM_IS_IN_INVENTORY, false); + + + // + // Fab data + // + if(item.getFabData() != null){ + rVal.putData(EntityDataStrings.ITEM_FAB_DATA, item.getFabData()); + } Globals.clientSceneWrapper.getScene().registerEntityToTag(rVal, EntityTags.ITEM); return rVal; @@ -174,7 +184,7 @@ public class ItemUtils { if(item.getIconPath() != null && !item.getIconPath().equals("")){ rVal.putData(EntityDataStrings.ITEM_ICON,item.getIconPath()); } else { - rVal.putData(EntityDataStrings.ITEM_ICON,genericItemIconPath); + rVal.putData(EntityDataStrings.ITEM_ICON,AssetDataStrings.UI_TEXTURE_ITEM_ICON_GENERIC); } // // @@ -191,6 +201,14 @@ public class ItemUtils { } } rVal.putData(EntityDataStrings.ITEM_IS_IN_INVENTORY, false); + + // + // Fab data + // + if(item.getFabData() != null){ + rVal.putData(EntityDataStrings.ITEM_FAB_DATA, item.getFabData()); + } + } /** diff --git a/src/main/java/electrosphere/game/data/item/Item.java b/src/main/java/electrosphere/game/data/item/Item.java index dceb9304..d6530947 100644 --- a/src/main/java/electrosphere/game/data/item/Item.java +++ b/src/main/java/electrosphere/game/data/item/Item.java @@ -81,6 +81,11 @@ public class Item extends CommonEntityType { * The usage logic for a secondary usage of this item */ ItemUsage secondaryUsage; + + /** + * Item fab data + */ + ItemFabData fabData; /** * Creates item data from a spawn item description @@ -261,4 +266,12 @@ public class Item extends CommonEntityType { this.primaryUsage = primaryUsage; } + /** + * Gets the fab data for this item + * @return The fab data + */ + public ItemFabData getFabData(){ + return fabData; + } + } diff --git a/src/main/java/electrosphere/game/data/item/ItemFabData.java b/src/main/java/electrosphere/game/data/item/ItemFabData.java new file mode 100644 index 00000000..348fdeca --- /dev/null +++ b/src/main/java/electrosphere/game/data/item/ItemFabData.java @@ -0,0 +1,29 @@ +package electrosphere.game.data.item; + +/** + * Data for placing fabs + */ +public class ItemFabData { + + /** + * The path for the fab to place when this item is consumed + */ + String fabPath; + + /** + * Gets the path for the corresponding fab file + * @return The path for the corresponding fab file + */ + public String getFabPath() { + return fabPath; + } + + /** + * Sets the path for the corresponding fab file + * @param fabPath The path for the corresponding fab file + */ + public void setFabPath(String fabPath) { + this.fabPath = fabPath; + } + +} diff --git a/src/main/java/electrosphere/renderer/model/Material.java b/src/main/java/electrosphere/renderer/model/Material.java index 42cdd396..77212d73 100644 --- a/src/main/java/electrosphere/renderer/model/Material.java +++ b/src/main/java/electrosphere/renderer/model/Material.java @@ -8,6 +8,7 @@ import electrosphere.util.FileUtils; import org.lwjgl.PointerBuffer; import org.lwjgl.assimp.AIMaterial; +import org.lwjgl.assimp.AIMaterialProperty; import org.lwjgl.assimp.AIScene; import org.lwjgl.assimp.AIString; import org.lwjgl.assimp.AITexture; @@ -94,6 +95,7 @@ public class Material { texPaths[i] = tex.mFilename().dataString(); } //discover diffuse + boolean foundDiffuse = false; int textureCount = Assimp.aiGetMaterialTextureCount(input, Assimp.aiTextureType_DIFFUSE); if(textureCount > 0){ //for the time being, only load the first diffuse @@ -118,6 +120,7 @@ public class Material { rVal.usesFetch = true; rVal.diffuse = resolved; Globals.assetManager.addTexturePathtoQueue(rVal.diffuse); + foundDiffuse = true; } } else { String resolved = Material.resolveTexturePath(path, texturePath); @@ -125,6 +128,45 @@ public class Material { rVal.usesFetch = true; rVal.diffuse = resolved; Globals.assetManager.addTexturePathtoQueue(rVal.diffuse); + foundDiffuse = true; + } + } + } + if(!foundDiffuse){ + textureCount = Assimp.aiGetMaterialTextureCount(input, Assimp.aiTextureType_BASE_COLOR); + if(textureCount > 0){ + //for the time being, only load the first diffuse + int textureIndex = 0; + int retCode = Assimp.aiGetMaterialTexture(input, Assimp.aiTextureType_BASE_COLOR, textureIndex, aiPathString, (IntBuffer)null, null, null, null, null, null); + if(retCode != Assimp.aiReturn_SUCCESS){ + throw new Error("Failed to read diffuse! " + textureCount + " " + Assimp.aiGetErrorString()); + } + String texturePath = aiPathString.dataString(); + if(texturePath == null || texturePath.length() <= 0){ + throw new Error("Texture path is empty " + texturePath); + } + if(texturePath.length() == 2 && texturePath.startsWith("*")){ + //older versions of Assimp require you to read the INDEX of the texture from the material, then look up that texture in the scene itself + //format looks like "*" ie "*0" + int indexInLoadedTexturePaths = Integer.parseInt(texturePath.substring(1)); + if(indexInLoadedTexturePaths >= texPaths.length){ + throw new Error("Index discovered is outside the array's length " + indexInLoadedTexturePaths + " " + texPaths.length); + } + String resolved = Material.resolveTexturePath(path, texPaths[indexInLoadedTexturePaths]); + if(resolved != null && resolved.length() > 0){ + rVal.usesFetch = true; + rVal.diffuse = resolved; + Globals.assetManager.addTexturePathtoQueue(rVal.diffuse); + foundDiffuse = true; + } + } else { + String resolved = Material.resolveTexturePath(path, texturePath); + if(resolved != null && resolved.length() > 0){ + rVal.usesFetch = true; + rVal.diffuse = resolved; + Globals.assetManager.addTexturePathtoQueue(rVal.diffuse); + foundDiffuse = true; + } } } } @@ -135,6 +177,25 @@ public class Material { return rVal; } + /** + * Describes the properties of a material + * @param material The material + */ + public static void listMaterialProps(AIMaterial material){ + LoggerInterface.loggerRenderer.WARNING("Describing material"); + for(int i = 0; i < material.mNumProperties(); i++){ + AIMaterialProperty prop = AIMaterialProperty.create(material.mProperties().get(i)); + String key = prop.mKey().dataString(); + int propType = prop.mSemantic(); + if(propType == Assimp.aiTextureType_NONE){ + //non-texture prop + LoggerInterface.loggerRenderer.WARNING("Prop \"" + key + "\" is not a texture"); + } else { + LoggerInterface.loggerRenderer.WARNING("Prop \"" + key + "\" is a texture"); + } + } + } + /** * Resolves the filepath of the texture * @param path The path of the ai scene itself diff --git a/src/main/java/electrosphere/util/FileUtils.java b/src/main/java/electrosphere/util/FileUtils.java index 3ba203f2..22fd35de 100644 --- a/src/main/java/electrosphere/util/FileUtils.java +++ b/src/main/java/electrosphere/util/FileUtils.java @@ -209,6 +209,16 @@ public class FileUtils { return targetFile; } + /** + * Gets an assets file + * @param pathName The relative path in the assets folder + * @return The file + */ + public static String getAssetFileString(String pathName){ + String sanitizedFilePath = sanitizeFilePath(pathName); + return "./assets" + sanitizedFilePath; + } + /** * Gets an assets file as a byte buffer * @param pathName The relative path in the assets folder