From 3D Asset to Working Worktable: Difference between revisions
| [unchecked revision] | [unchecked revision] |
m Added warning about WIP section |
mNo edit summary |
||
| (6 intermediate revisions by the same user not shown) | |||
| Line 49: | Line 49: | ||
[[File:Eco - Unity - View Modes.png|thumb|Underlined in red are the different draw mode buttons. <u>4/20/26</u>]] | [[File:Eco - Unity - View Modes.png|thumb|Underlined in red are the different draw mode buttons. <u>4/20/26</u>]] | ||
If something seems off, check the different draw modes and see if changing those allow the scene to render as expected (see picture). | If something seems off, check the different draw modes and see if changing those allow the scene to render as expected (see picture). | ||
= Creating The Worktable = | = Creating The Worktable = | ||
| Line 64: | Line 62: | ||
=== Item Icon === | === Item Icon === | ||
[[File:TeamstersStall - StallOnly - 256x256.png|thumb|A large (256x256px) icon created of Stall4 from the medieval assets.]] | [[File:TeamstersStall - StallOnly - 256x256.png|thumb|A large (256x256px) icon created of Stall4 from the medieval assets.]] | ||
# Open <u>Blender</u>. | # Open <u>Blender</u>. | ||
# Delete everything in the ''Scene Collection''. Find this section in the top-right of the application. | # Delete everything in the ''Scene Collection''. Find this section in the top-right of the application. | ||
| Line 71: | Line 67: | ||
# Hover ''Import'' to open the sub-menu. | # Hover ''Import'' to open the sub-menu. | ||
# Select the type of 3D asset. For those using medieval assets, select ''FBX (.fbx)''. | # Select the type of 3D asset. For those using medieval assets, select ''FBX (.fbx)''. | ||
# Find the asset on the computer... | # Find the asset on the computer...<br>'''Tip:''' Use Unity to find the <code>.fbx</code> asset. | ||
## For the medieval assets, that's in <code>Assets/PolyRonin/Medieval Market Stalls/Meshes/medieval-market-stalls-1.fbx</code>. | |||
## Right click on it and select ''Show in explorer''. | ## Right click on it and select ''Show in explorer''. | ||
## Now copy the address of that folder from Explorer. It might look like <code>C:\Users\Wug\EcoMod--WikiDemo\WikiDemo\Assets\PolyRonin\Medieval Market Stalls\Meshes</code>. | ## Now copy the address of that folder from Explorer. It might look like <code>C:\Users\Wug\EcoMod--WikiDemo\WikiDemo\Assets\PolyRonin\Medieval Market Stalls\Meshes</code>. | ||
## Paste that in the address bar of the <u>Blender</u> import pop-up. | ## Paste that in the address bar of the <u>Blender</u> import pop-up. | ||
# Select the blue ''Import FBX'' button''.'' | # Select the blue ''Import FBX'' button''.'' | ||
# | # Be in the ''Layout'' workspace (top toolbar) and in the ''Object Mode...'' | ||
## Find the drop down in the second toolbar from the top that has options like ''Object Mode, Edit Mode, Sculpt Mode,'' etc. | |||
## Select ''Object Mode'' from that drop down. | |||
# Change the Viewport Shading to Material Preview or Rendered. This is on the second toolbar down, far right of center, but before ''Scene Collection'' section. | |||
# If you see purple models, Blender will need help finding textures for these meshes... | # If you see purple models, Blender will need help finding textures for these meshes... | ||
## From the top toolbar, open the ''File'' drop down. | ## From the top toolbar, open the ''File'' drop down. | ||
| Line 85: | Line 84: | ||
## The proper textures/materials should have now loaded in. If it hasn't, consult Google because without the textures the following steps won't produce a usable icon. | ## The proper textures/materials should have now loaded in. If it hasn't, consult Google because without the textures the following steps won't produce a usable icon. | ||
# Add a source of light... | # Add a source of light... | ||
## | ## Still be in the ''Layout'' workspace (top toolbar) and in the ''Object Mode...'' | ||
### Find the drop down in the second toolbar from the top that has options like ''Object Mode, Edit Mode, Sculpt Mode,'' etc. | |||
### Select ''Object Mode'' from that drop down. | |||
## From the toolbar just under that one, find and open the ''Add'' drop down. | ## From the toolbar just under that one, find and open the ''Add'' drop down. | ||
## Hover ''Light'' to open that sub-menu. | ## Hover ''Light'' to open that sub-menu. | ||
## Click ''Sun''. | ## Click ''Sun''. | ||
# Add a camera... | # Add a camera... | ||
## | ## In the ''Layout'' workspace (top toolbar) and in the ''Object Mode...'' | ||
### Find the drop down in the second toolbar from the top that has options like ''Object Mode, Edit Mode, Sculpt Mode,'' etc. | |||
### Select ''Object Mode'' from that drop down. | |||
## From the second toolbar down, find and open the ''Add'' drop down. | ## From the second toolbar down, find and open the ''Add'' drop down. | ||
## Select ''Camera''. | ## Select ''Camera''. | ||
# Setup the scene with the object placement and lighting direction desired. | # Setup the scene with the object placement and lighting direction desired.<br>'''Tip:''' To reset the editor to something selected press the period key <u>on the numpad</u>. Without a numpad, use ''View'' (second toolbar from the top) and select ''Frame Selected'' from it. Alternatively, just set the zoom to zoom to the mouse position: ''Edit'' (top toolbar), ''Preferences'' (from drop down), ''Navigation'' (on left menu), ''Zoom to Mouse Position'' (In the zoom section). This makes moving around a lot more natural feeling. | ||
# Setup the rendering camera... | # Setup the rendering camera... | ||
## Go to ''Rendering'' tab on the top toolbar | ## Go to ''Rendering'' tab on the top toolbar | ||
| Line 105: | Line 108: | ||
# Center your view on the object (numpad period or ''View > Frame Selected''). Adjust it so that the object is how it should be for the icon. | # Center your view on the object (numpad period or ''View > Frame Selected''). Adjust it so that the object is how it should be for the icon. | ||
# Align the camera to the view... | # Align the camera to the view... | ||
## Make sure the editor is in ''Layout'' | ## Make sure the editor is in ''Layout'' workspace (top toolbar) and in the ''Object Mode...'' | ||
### Find the drop down in the second toolbar from the top that has options like ''Object Mode, Edit Mode, Sculpt Mode,'' etc. | |||
### Select ''Object Mode'' from that drop down. | |||
## Find ''View'' from the second from the top toolbar and open the drop down. | ## Find ''View'' from the second from the top toolbar and open the drop down. | ||
## Hover ''Align View'' to open the sub-menu. | ## Hover ''Align View'' to open the sub-menu. | ||
| Line 158: | Line 163: | ||
# Right click on the ''ItemTemplate'' object and select ''Rename''. Name this what you want the item to be called. Example: ''MedievalStallItem''. | # Right click on the ''ItemTemplate'' object and select ''Rename''. Name this what you want the item to be called. Example: ''MedievalStallItem''. | ||
# Set this item's background... | # Set this item's background... | ||
## Here's the default backgrounds (blue = item, brown = block, green = food): [[File:Eco - Item - Background.png|border|frameless]] [[File:Eco - Block - Background.png|frameless]] [[File:Eco - Food - Background.png|frameless]] | ## Here's the default backgrounds (blue = item, brown = block, green = food): <br>[[File:Eco - Item - Background.png|border|frameless]] [[File:Eco - Block - Background.png|frameless]] [[File:Eco - Food - Background.png|frameless]] | ||
## Download or prepare the background and add it to the <code>Assets</code> folder in Unity. | ## Download or prepare the background and add it to the <code>Assets</code> folder in Unity. | ||
### To follow along lockstep, put the background in a new <code>Assets/WikiDemo</code> folder. | ### To follow along lockstep, put the background in a new <code>Assets/WikiDemo</code> folder. | ||
| Line 207: | Line 212: | ||
# Open the ''File'' menu from the top toolbar. | # Open the ''File'' menu from the top toolbar. | ||
# Select ''Save.'' Save it to the <code>Assets/WikiDemo</code> folder. '''Note:''' Do not skip. The scene must be saved for the ModKit build to work properly. | # Select ''Save.'' Save it to the <code>Assets/WikiDemo</code> folder.<br>'''Note:''' Do not skip. The scene must be saved for the ModKit build to work properly. | ||
# Open the ''Eco Tools'' menu from the top toolbar. | # Open the ''Eco Tools'' menu from the top toolbar. | ||
# Hover ''Mod Kit'' to open the sub-menu. | # Hover ''Mod Kit'' to open the sub-menu. | ||
| Line 214: | Line 219: | ||
# Wait for this to build. This may take a few minutes. | # Wait for this to build. This may take a few minutes. | ||
=== | === Coding the Item === | ||
For a | For this guide, all code will be placed in a single <code>.cs</code> file and will not be compiled into a <code>.dll</code>. | ||
# Create a <code>.cs</code> file: <code>/Eco Server/Mods/UserCode/WikiDemo.cs</code> | # Create a <code>.cs</code> file: <code>/Eco Server/Mods/UserCode/WikiDemo.cs</code> | ||
| Line 229: | Line 234: | ||
[Serialized] // Tells the save/load system this object needs to be serialized. | [Serialized] // Tells the save/load system this object needs to be serialized. | ||
[LocDisplayName("Market Stall")] // Defines the localized name of the item. | [LocDisplayName("Market Stall")] // Defines the localized name of the item. | ||
[Weight(100)] // Defines how heavy | [Weight(100)] // Defines how heavy this is. | ||
[Ecopedia("Work Stations", "Craft Tables", createAsSubPage: true)] | [Ecopedia("Work Stations", "Craft Tables", createAsSubPage: true)] | ||
[LocDescription("A medieval market stall.")] //The tooltip description for the item. | [LocDescription("A medieval market stall.")] //The tooltip description for the item. | ||
| Line 238: | Line 243: | ||
'''Line 13:''' The implementation of <code>Item</code> means that Eco will find this and look for Unity assets that matching this class' name, <code>MedivalStallItem</code>. While this doesn't do anything fancy, it completes the first step towards a new workbench. | '''Line 13:''' The implementation of <code>Item</code> means that Eco will find this and look for Unity assets that matching this class' name, <code>MedivalStallItem</code>. While this doesn't do anything fancy, it completes the first step towards a new workbench. | ||
=== Checkpoint === | === Checkpoint #1 === | ||
[[File:Eco - Hotbar With Modded Icon.png|thumb|Shows the medieval stall as a modded icon in-game.]] | [[File:Eco - Hotbar With Modded Icon.png|thumb|Shows the medieval stall as a modded icon in-game.]] | ||
Make sure everything is running smoothly by doing the following: | |||
# Double-check that the <code>WikiDemo.unity3d</code> and the <code>WikiDemo.cs</code> files are in <code>/Eco Server/Mods/UserCode</code> folder. | # Double-check that the <code>WikiDemo.unity3d</code> and the <code>WikiDemo.cs</code> files are in <code>/Eco Server/Mods/UserCode</code> folder. | ||
# Start the server and connect to it. | # Start the server and connect to it. | ||
# Test it out by typing <code>/give MedievalStall</code> in chat | # Test it out by typing <code>/give MedievalStall</code> in chat. | ||
## It's also possible to do <code>/give Market Stall</code> to get the item. How? Line 10: of the the above code declares that name as this item's "common name". Neat. | ## It's also possible to do <code>/give Market Stall</code> to get the item. How? Line 10: of the the above code declares that name as this item's "common name". Neat. | ||
# The item should appear in the players inventory with a working icon. | # The item should appear in the players inventory with a working icon. | ||
== Code the Item's Recipe == | == Code the Item's Recipe == | ||
The following goes over how to add a new class and implement the <code>RecipeFamily</code> interface.<syntaxhighlight lang="c#" line="1">using Eco.Core.Items; | |||
using Eco.Gameplay.Components; | using Eco.Gameplay.Components; | ||
using Eco.Gameplay.Items; | using Eco.Gameplay.Items; | ||
| Line 282: | Line 283: | ||
ingredients: new List<IngredientElement> | ingredients: new List<IngredientElement> | ||
{ | { | ||
new IngredientElement("Wood", 40, typeof( | new IngredientElement("Wood", 40, typeof(CarpentrySkill)), | ||
new IngredientElement(typeof(CottonFabricItem), 30, typeof( | new IngredientElement(typeof(CottonFabricItem), 30, typeof(CarpentrySkill)), | ||
new IngredientElement(typeof(HempMooringRopeItem), 5, true) | new IngredientElement(typeof(HempMooringRopeItem), 5, true) | ||
}, | }, | ||
| Line 292: | Line 293: | ||
); | ); | ||
this.Recipes = new List<Recipe> { recipe }; | this.Recipes = new List<Recipe> { recipe }; | ||
this.LaborInCalories = CreateLaborInCaloriesValue(800, typeof( | this.LaborInCalories = CreateLaborInCaloriesValue(800, typeof(CarpentrySkill)); | ||
this.CraftMinutes = CreateCraftTimeValue(typeof(MedievalStallRecipe), 10f, typeof( | this.CraftMinutes = CreateCraftTimeValue(typeof(MedievalStallRecipe), 10f, typeof(CarpentrySkill)); | ||
// Perform pre/post initialization for user mods and initialize our recipe instance with the display name "Market Stall" | // Perform pre/post initialization for user mods and initialize our recipe instance with the display name "Market Stall" | ||
| Line 320: | Line 321: | ||
'''Line 21:''' <code>[SupportedOSPlatform("windows7.0")]</code> is here to silence some annoying warnings in Visual Studio. It's optional. | '''Line 21:''' <code>[SupportedOSPlatform("windows7.0")]</code> is here to silence some annoying warnings in Visual Studio. It's optional. | ||
'''Line 30-32:''' Declares the input ingredients used for crafting. | '''Line 30-32:''' Declares the input ingredients used for crafting. <code>CarpentrySkill</code> as defined by line 31. In this example the <code>HempMooringRope</code> is a static input. A static input will not be modified by skills, upgrade modules, or game settings.<br>'''Note:''' It seems that at the time of writing (4/21/2026, Eco v13.0.2) the only way to get an ingredient to be a dynamic value that is reduced by the table's upgrade is to pass <code>typeof(Skill)</code> to it; Passing either <code>true</code> or <code>false</code> makes the this input static. | ||
'''Line 34:''' The <code>items</code> list declares what items are <u>output</u> by this recipe. | '''Line 34:''' The <code>items</code> list declares what items are <u>output</u> by this recipe. | ||
| Line 328: | Line 329: | ||
'''Line 40:''' Amount of calories needed to craft this item. For a static value (not modified by upgrades or skill levels) change this line to: <code>this.LaborInCalories = CreateLaborInCaloriesValue(800);</code>. As it's written in the example, this item's calorie cost will be dynamic (modified by upgrades and skill levels). The skill level that will modify it is declared on line 16. | '''Line 40:''' Amount of calories needed to craft this item. For a static value (not modified by upgrades or skill levels) change this line to: <code>this.LaborInCalories = CreateLaborInCaloriesValue(800);</code>. As it's written in the example, this item's calorie cost will be dynamic (modified by upgrades and skill levels). The skill level that will modify it is declared on line 16. | ||
'''Line 41:''' Minutes needed to craft. Both static and dynamic values for crafting time can be modified by the world difficulty settings. For a static value change this line to: <code>this.CraftMinutes = CreateCraftTimeValue(10f);</code>. As it's written in the example, this item's craft time will be dynamic.'''Line 49:''' This line assigns the recipe to a workbench. <u>Do not assign</u> to itself because then the first table could never be made. It's recommend to use a preexisting vanilla table. | '''Line 41:''' Minutes needed to craft. Both static and dynamic values for crafting time can be modified by the world difficulty settings. For a static value change this line to: <code>this.CraftMinutes = CreateCraftTimeValue(10f);</code>. As it's written in the example, this item's craft time will be dynamic. | ||
=== Checkpoint === | |||
'''Line 49:''' This line assigns the recipe to a workbench. <u>Do not assign</u> to itself because then the first table could never be made. It's recommend to use a preexisting vanilla table. | |||
=== Checkpoint #2 === | |||
Check the functionality at this point -- it should be possible to see the recipe in the crafting table. | Check the functionality at this point -- it should be possible to see the recipe in the crafting table. | ||
| Line 336: | Line 339: | ||
# Type <code>/give Carpentry Table</code>. | # Type <code>/give Carpentry Table</code>. | ||
# Place the Carpentry Table down and interact to see the what can be crafted. | # Place the Carpentry Table down and interact to see the what can be crafted. | ||
# | # Find the newly added recipe under the name ''Market Stall.'' | ||
# Type <code>/give Basic Upgrade 4</code>. | # Type <code>/give Basic Upgrade 4</code>. | ||
# Put the basic upgrade into the table. | # Put the basic upgrade into the table. | ||
# Go back to the recipe for the ''Market Stall'' and make sure the Wood and the Cotton fabric inputs now require less, but the Hemp Mooring Rope still is the same. '''Note:''' In case the recipe hasn't changed close that table's window and interact with it again. It should for the recipes to refresh now that the upgrade is in it. | # Go back to the recipe for the ''Market Stall'' and make sure the Wood and the Cotton fabric inputs now require less, but the Hemp Mooring Rope still is the same.<br>'''Note:''' In case the recipe hasn't changed close that table's window and interact with it again. It should for the recipes to refresh now that the upgrade is in it. | ||
== Create the World Object == | == Create the World Object == | ||
=== Preparing the 3D Asset === | === Preparing the 3D Asset === | ||
# Open <u>Blender</u>. | # Open <u>Blender</u>. | ||
# Load the 3D object created earlier for icon rendering -- <code>Assets/WikiDemo/MedievalStall - Icon Scene.blend</code>. | # Load the 3D object created earlier for icon rendering -- <code>Assets/WikiDemo/MedievalStall - Icon Scene.blend</code>. | ||
# Cleanup the scene... | # Cleanup the scene... | ||
## Use the | ## Delete any light source. Use the ''Scene Collection'' panel on the top-right side of the screen. These will have a 💡 icon and by default are named something like "sun", "point", "spot" or "area".<br>'''Note:''' If your model is a light source or has one in it, you can leave that light source. The point here is to remove the ambient lights used for icon rendering. | ||
## | ## Delete any camera(s). Again, use the ''Scene Collection'' panel. These have a 🎥 icon and by default are named something like "camera". | ||
# <u>If there are multiple different 3D assets in the scene</u> (like bags, crates, jars, ect.), join them all together... | # <u>If there are multiple different 3D assets in the scene</u> (like bags, crates, jars, ect.), join them all together... | ||
## Select all of the meshes by holding ''Shift'' and clicking on each one in the ''Scene Collection'' panel (right side of window). '''Tip:''' Quickly select a group of them by selecting one near the top. Then hold ''Shift'', ''Ctrl,'' and click on one near the bottom. This will both the one at the top and the one at the bottom, but also every item in between. Neat! | ## Select all of the meshes by holding ''Shift'' and clicking on each one in the ''Scene Collection'' panel (right side of window).<br>'''Tip:''' Quickly select a group of them by selecting one near the top. Then hold ''Shift'', ''Ctrl,'' and click on one near the bottom. This will both the one at the top and the one at the bottom, but also every item in between. Neat! | ||
## Be in ''Layout'' | ## Be in ''Layout'' workspace (top toolbar) and in the ''Object Mode...'' | ||
### Find the drop down in the second toolbar from the top that has options like ''Object Mode, Edit Mode, Sculpt Mode,'' etc. | |||
### Select ''Object Mode'' from that drop down. | |||
## Find and open the ''Object'' menu (second toolbar down from the top). | ## Find and open the ''Object'' menu (second toolbar down from the top). | ||
## Select ''Join''. | ## Select ''Join''. | ||
## In the ''Scene Collection'' panel, double click on the name of the newly joined mesh. | ## In the ''Scene Collection'' panel, double click on the name of the newly joined mesh. | ||
# Rename the joined mesh to <code>MedievalStallMesh</code>. | |||
# Add and position a reference cube... | # Add and position a reference cube... | ||
## Make sure the editor is in ''Layout'' view (top toolbar). | ## Make sure the editor is in ''Layout'' view (top toolbar) and in the ''Object Mode...'' | ||
### Find the drop down in the second toolbar from the top that has options like ''Object Mode, Edit Mode, Sculpt Mode,'' etc. | |||
### Select ''Object Mode'' from that drop down. | |||
## Then, add a reference cube. Open the ''Add'' menu (second top toolbar down). | ## Then, add a reference cube. Open the ''Add'' menu (second top toolbar down). | ||
## Hover ''Mesh''. | ## Hover ''Mesh''. | ||
## Select ''Cube.'' | ## Select ''Cube.'' | ||
## | ## Open the ''View'' menu (second toolbar down). | ||
## | ## Select ''Sidebar''. | ||
## A new panel will have expanded. | |||
## | ## Along the right side of that panel there's buttons (''Item, Tool, View, Animation''). Find and click the ''Item'' button. | ||
## Find and expand the ''Transform'' section | ## Find and expand the ''Transform'' section | ||
## Set ''Location X'' to ''1''. | ## Set the ''Location...'' | ||
## | ### ''X'' to ''1''. | ||
## | ### ''Y'' to ''1''. | ||
## The bottom corner of the cube | ### ''Z'' to ''1''. | ||
## The bottom corner of the cube should be touching the where green and red axis lines meet. | |||
# Move the reference cube's origin to <code>(0, 0, 0)</code>... | # Move the reference cube's origin to <code>(0, 0, 0)</code>... | ||
## Be in ''Layout'' | ## Be in ''Layout'' workspace (top toolbar) and in the ''Object Mode...'' | ||
### Find the drop down in the second toolbar from the top that has options like ''Object Mode, Edit Mode, Sculpt Mode,'' etc. | |||
### Select ''Object Mode'' from that drop down. | |||
## Open the ''View'' menu (second toolbar down). | ## Open the ''View'' menu (second toolbar down). | ||
## Select ''Sidebar''. | ## Select ''Sidebar''. | ||
| Line 377: | Line 386: | ||
## Along the right side of that panel there's buttons (''Item, Tool, View, Animation''). Find and click the ''View'' button. | ## Along the right side of that panel there's buttons (''Item, Tool, View, Animation''). Find and click the ''View'' button. | ||
## Find and expand the ''3D Cursor'' section. | ## Find and expand the ''3D Cursor'' section. | ||
## | ## Set the 3D cursor's ''Location''... | ||
## ''Y'' to 0. | ### ''X'' to ''0''. | ||
## ''Z'' to 0. | ### ''Y'' to ''0''. | ||
## Now in the ''Scene Collection'' panel, | ### ''Z'' to ''0.'' | ||
## Now in the ''Scene Collection'' panel, click on the ''Cube'' mesh to highlight and select it. | |||
## Open the ''Object'' menu from the second toolbar down from the top. | ## Open the ''Object'' menu from the second toolbar down from the top. | ||
## Hover ''Set Origin''. | ## Hover ''Set Origin''. | ||
## Select ''Origin to 3D Cursor''. | ## Select ''Origin to 3D Cursor''. | ||
# Set the reference cube's dimensions... | # Set the reference cube's dimensions... | ||
## Be in ''Layout'' | ## Be in ''Layout'' workspace (top toolbar) and in the ''Object Mode...'' | ||
## To the right of the | ### Find the drop down in the second toolbar from the top that has options like ''Object Mode, Edit Mode, Sculpt Mode,'' etc. | ||
### Select ''Object Mode'' from that drop down. | |||
## Open the ''View'' menu (second toolbar down). | |||
## Select and check the ''Sidebar'' option''.'' | |||
## The ''Sidebar'' menu just expanded over on the right side of the screen. | |||
## To the right of the ''Sidebar'', find and click the ''Item'' button. | |||
## Expand the ''Transform'' section. | ## Expand the ''Transform'' section. | ||
## | ## Set the ''Dimensions...'''''<br>Note:''' These dimensions only make sense for the asset being used for this guide. If using a different one, set the dimensions to the size of the box that model should fit in. | ||
### ''X'' to ''4''. | |||
### ''Y'' to ''3''. | |||
# Adjust the position and scale to fit inside a box | ### ''Z'' to ''3''. | ||
## Be in ''Layout'' | # Adjust the position and scale of the ''MedievalStallMesh'' to fit inside a box. | ||
## Find the drop down in the second toolbar from the top that has options like ''Object Mode, Edit Mode, Sculpt Mode,'' etc. | ## Be in ''Layout'' workspace (top toolbar) and in the ''Object Mode...'' | ||
## Select ''Object Mode'' from that drop down. | ### Find the drop down in the second toolbar from the top that has options like ''Object Mode, Edit Mode, Sculpt Mode,'' etc. | ||
### Select ''Object Mode'' from that drop down. | |||
## On the left side of the screen there's a column of icons. Hover over them to see their names. | ## On the left side of the screen there's a column of icons. Hover over them to see their names. | ||
## Select the ''Move'' tool. | ## Select the ''Move'' tool. | ||
## Click on the Medieval Stall to select it. Zoom out and reposition the camera so that the blue, green, and red arrows are visible. | ## Click on the Medieval Stall to select it. Zoom out and reposition the camera so that the blue, green, and red arrows are visible.<br>'''Tip:''' By holding the middle-mouse button and dragging the scene will rotate. By holding the middle-mouse button and the ''Shift'' key, the scene will pan.<br>'''Tip:''' If panning or rotating the scene becomes slow or frustrating (especially after zooming), try selecting 3D asset from the ''Scene Collection'' panel, opening the ''View'' menu (second toolbar from top), and selecting ''Frame Selected''. This will reset the view onto that object and controls should feel normal again. | ||
## Click and hold one of the arrows. Move the mouse to drag the 3D asset towards the box. | ## Click and hold one of the arrows. Move the mouse to drag the 3D asset towards the box. | ||
## Move the 3D asset around till it's <u>completely inside the box</u>. If it cannot fit and is too big, continue to the next step. | ## Move the 3D asset around till it's <u>completely inside the box</u>. If it cannot fit and is too big, continue to the next step.<br>'''Tip:''' To select the 3D asset once it disappears, use the ''Scene Collection'' panel. Click on it there and the blue, green, and red arrows will show up again for it.<br>'''Tip:''' There are preset views. To use them go to the ''View'' menu (second toolbar from top)'','' hover ''Viewpoint'', and select the view that would be most helpful. | ||
## Find the ''Scale'' tool from the left side of the screen. | ## Find the ''Scale'' tool from the left side of the screen. | ||
## Now the blue, green, and red "arrows" don't really look like arrows anymore. They are lines with boxes at the end. | ## Now the blue, green, and red "arrows" don't really look like arrows anymore. They are lines with boxes at the end. | ||
## Click and hold on those lines to adjust the scale of the 3D asset to make it fit inside the box. | ## Click and hold on those lines to adjust the scale of the 3D asset to make it fit inside the box.<br>'''Tip:''' There are little colored boxes in between the lines that can be dragged to scale the 3D asset more proportionally. | ||
## Continue using the ''Move'' and ''Scale'' tools till the model fits. This will take patience and time. | ## Continue using the ''Move'' and ''Scale'' tools till the model fits. This will take patience and time.<br>'''Tip:''' Hide the reference cube to see what is happening with the 3D asset. Go to the ''Scene Collections'' panel and click the 👁 button to hide it. Click that button again to show it. | ||
# | # Move the reference cube's origin to <code>(0.5, 0.5, 0.5)</code>... | ||
## Be in ''Layout'' workspace (top toolbar) and in the ''Object Mode...'' | |||
## Select the | ### Find the drop down in the second toolbar from the top that has options like ''Object Mode, Edit Mode, Sculpt Mode,'' etc. | ||
### Select ''Object Mode'' from that drop down. | |||
## Open the ''View'' menu (second toolbar down). | |||
## Select ''Sidebar''. | |||
## A new panel will have expanded. | |||
## Along the right side of that panel there's buttons (''Item, Tool, View, Animation''). Find and click the ''View'' button. | |||
## Find and expand the ''3D Cursor'' section. | |||
## Set the 3D cursor's ''Location''... | |||
### ''X'' to ''0''.5. | |||
### ''Y'' to ''0.5''. | |||
### ''Z'' to ''0.5.'' | |||
## Select the ''MedievalStallMesh'' using the ''Scene Collection'' panel. | |||
## Open the ''Object'' menu (second toolbar down). | ## Open the ''Object'' menu (second toolbar down). | ||
## Hover ''Set Origin''. | ## Hover ''Set Origin''. | ||
## Select ''Origin to 3D Cursor''. | ## Select ''Origin to 3D Cursor''. | ||
# Select the reference cube from the ''Scene Collections'' panel. | # Select the reference cube named ''Cube'' from the ''Scene Collections'' panel. | ||
# Open ''Object'' menu (second toolbar down). | # Open ''Object'' menu (second toolbar down). | ||
# Select ''Delete''. | # Select ''Delete''. | ||
# Move the ''MedievalStallMesh'' to <code>(0, 0, 0)</code>... | |||
## Be in ''Layout'' workspace (top toolbar) and in the ''Object Mode...'' | |||
### Find the drop down in the second toolbar from the top that has options like ''Object Mode, Edit Mode, Sculpt Mode,'' etc. | |||
### Select ''Object Mode'' from that drop down. | |||
## Open the ''View'' menu (second toolbar down). | |||
## Select ''Sidebar''. | |||
## A new panel will have expanded. | |||
## Along the right side of that panel there's buttons (''Item, Tool, View, Animation''). Find and click the ''Item'' button. | |||
## Make sure the ''MedievalStallMesh'' is selected. Use the ''Scene Collection'' panel if needed. | |||
## Find and expand the ''Transform'' section | |||
## Set the ''Location...'' | |||
### ''X'' to 0. | |||
### ''Y'' to 0. | |||
### ''Z'' to 0. | |||
# Make sure the ''MedievalStallMesh'' is selected. Use the ''Scene Collection'' panel if needed. | |||
# Open the ''Object'' menu. | # Open the ''Object'' menu. | ||
# Hover ''Apply''. | # Hover ''Apply''. | ||
# Select ''All Transformations''. | # Select ''All Transformations''.<br>'''Note:''' This step bakes all of the changes into the mesh. It's very important. | ||
# Open the ''File'' menu from the top toolbar. | # Open the ''File'' menu from the top toolbar. | ||
# Hover ''Export'' to open the sub-menu. | # Hover ''Export'' to open the sub-menu. | ||
| Line 425: | Line 467: | ||
# In the settings region scroll and find the ''Transform'' section and expand it. Change the following: | # In the settings region scroll and find the ''Transform'' section and expand it. Change the following: | ||
## Find ''Apply Scalings'' and set it to ''FBX All''. | ## Find ''Apply Scalings'' and set it to ''FBX All''. | ||
## Just below that find ''Forward'' and set it to '' | ## Just below that find ''Forward'' and set it to ''Z Forward''. | ||
## Ensure that the next setting down, ''Up'', changed to ''Y Up''. | ## Ensure that the next setting down, ''Up'', changed to ''Y Up''. | ||
## Find ''Apply Unit'' and make sure it's checked. | ## Find ''Apply Unit'' and make sure it's checked. | ||
| Line 431: | Line 473: | ||
## Lastly, find ''Apply Transform'' and check it too. | ## Lastly, find ''Apply Transform'' and check it too. | ||
# Save it to <code>Assets/WikiDemo/MedievalStall.fbx</code>. | # Save it to <code>Assets/WikiDemo/MedievalStall.fbx</code>. | ||
# Save the <code>.blend</code> | # Save the Blender scene... | ||
## ''File'' drop down from top toolbar. | |||
## ''Save As...'' to save the Blender scene to the computer. | |||
## Save it to <code>Assets/WikiDemo/MedievalStall - Eco Ready Scene.blend</code>. | |||
=== Add to Unity Scene === | === Add to Unity Scene === | ||
| Line 445: | Line 490: | ||
# Press the ''Setup World Objects'' button. | # Press the ''Setup World Objects'' button. | ||
# Notice in the project window that a new <code>.prefab</code> file was created -- <code>MedievalStallObject.prefab</code> | # Notice in the project window that a new <code>.prefab</code> file was created -- <code>MedievalStallObject.prefab</code> | ||
# Select the <code>.prefab</code> | # Select the <code>.prefab</code>. | ||
# In the ''Inspector'' | # In the ''Inspector'' panel find the ''Transform'' component. | ||
# | # Change this component's ''Rotation...'' | ||
# A new field | ## ''X'' to ''0.'' | ||
# Set the '' | ## ''Y'' to ''0.'' | ||
# '' | ## ''Z'' to ''0.'' | ||
# '' | # In the ''Inspector'' panel find the ''Box Collider'' component. | ||
# Select ''Objects'' from ''Hierarchy'' panel. | #Find the ''⋮'' icon (all the way to the right of the words ''Box Collider)'' and click on it. | ||
# Find the ''Modkit Prefab Container (Script)'' component. | #Select ''Reset'' from the menu. This will regenerate the box collider now that the rotation has changed. | ||
#Look in the ''Inspector'' panel and find the ''World Object (Script)'' component. | |||
# That component has a checkbox ''Override Occupancy''. Check it. | |||
# A new field should've expanded below it called ''Size''. | |||
# Set the ''Size''...<br>'''Note:''' This size similar to the size of the reference cube from earlier, but the Y and Z coordinates get flipped! So if in Blender it was <code>(1, 2, 3)</code> then in Unity its <code>(1, 3, 2)</code>. | |||
## ''X'' to ''4''. | |||
## ''Y'' to ''3''. | |||
## ''Z'' to ''3''. | |||
# Select ''Objects'' from ''Hierarchy'' panel (left-side of the window). | |||
# Find the ''Modkit Prefab Container (Script)'' component. This component was added earlier, if it's not there add it now. | |||
# Expand the ''Prefabs'' section in that component. | # Expand the ''Prefabs'' section in that component. | ||
# Click the ''+'' button to add an item to the list. | # Click the ''+'' button to add an item to the list. | ||
| Line 459: | Line 513: | ||
## Click the ''⦿'' button, switch to the ''Assets'' tab, find or search for ''MedievalStallObject'', and double click on it. Make sure it's the medieval stall <u>object</u> with the <code>.prefab</code> ending. | ## Click the ''⦿'' button, switch to the ''Assets'' tab, find or search for ''MedievalStallObject'', and double click on it. Make sure it's the medieval stall <u>object</u> with the <code>.prefab</code> ending. | ||
## Drag the <code>.prefab</code> file onto the ''⦿'' button | ## Drag the <code>.prefab</code> file onto the ''⦿'' button | ||
# Open the ''File'' menu from top toolbar and select ''Save''.<br>'''Note:''' Do not skip. The scene must be saved for the ModKit build to work properly. | |||
# Open the ''File'' menu from top toolbar and select ''Save''. | |||
# Open the ''Eco Tools'' menu from the top toolbar. | # Open the ''Eco Tools'' menu from the top toolbar. | ||
# Hover ''Mod Kit''. | # Hover ''Mod Kit''. | ||
| Line 466: | Line 519: | ||
# Save the bundle to <code>/Eco Server/Mods/UserCode/WikiDemo.unity3d</code> | # Save the bundle to <code>/Eco Server/Mods/UserCode/WikiDemo.unity3d</code> | ||
=== Coding the World Object === | |||
The following collapses the <code>#region Recipe</code>. Please see the earlier section [[#Code the Item's Recipe|Code the Item's Recipe]] to get the code that belongs there. | |||
Add the new <code>using</code> lines, replace the <code>#region Item</code> section, and replace the <code>#region Object</code> sections using the following:<syntaxhighlight lang="c#" line="1">using Eco.Core.Items; | |||
using Eco.Core.Items; | |||
using Eco.Gameplay.Components; | using Eco.Gameplay.Components; | ||
using Eco.Gameplay.Items; | using Eco.Gameplay.Items; | ||
| Line 482: | Line 534: | ||
using System.Runtime.Versioning; | using System.Runtime.Versioning; | ||
using System; | using System; | ||
using Eco.Core.Controller; | |||
using Eco.Gameplay.Systems.NewTooltip; | |||
using Eco.Shared.Items; | |||
using Eco.Gameplay.Occupancy; | |||
using Eco.Shared.Math; | |||
using Eco.Gameplay.Components.Auth; | |||
namespace WikiDemo | namespace WikiDemo | ||
| Line 487: | Line 546: | ||
#region Item | #region Item | ||
[Serialized] // Tells the save/load system this object needs to be serialized. | [Serialized] // Tells the save/load system this object needs to be serialized. | ||
[SupportedOSPlatform("windows7.0")] | |||
[LocDisplayName("Market Stall")] // Defines the localized name of the item. | [LocDisplayName("Market Stall")] // Defines the localized name of the item. | ||
[Weight( | [Weight(3000)] // Defines how heavy this is. | ||
[Ecopedia("Work Stations", "Craft Tables", createAsSubPage: true)] | [Ecopedia("Work Stations", "Craft Tables", createAsSubPage: true)] | ||
[LocDescription("A medieval market stall.")] //The tooltip description for the item. | [LocDescription("A medieval market stall.")] //The tooltip description for the item. | ||
public partial class MedievalStallItem : WorldObjectItem<MedievalStallObject> { } | public partial class MedievalStallItem : WorldObjectItem<MedievalStallObject>, IPersistentData | ||
{ | |||
[Serialized, SyncToView, NewTooltipChildren(CacheAs.Instance, flags: TTFlags.AllowNonControllerTypeForChildren)] public object? PersistentData { get; set; } | |||
protected override OccupancyContext GetOccupancyContext => new SideAttachedContext( | |||
DirectionAxisFlags.Down, // Read: every occupied block on the bottom must be supported | |||
WorldObject.GetOccupancyInfo(this.WorldObjectType) | |||
); | |||
} | |||
#endregion | #endregion | ||
| Line 498: | Line 566: | ||
#region Object | #region Object | ||
[Serialized] | [Serialized] | ||
[SupportedOSPlatform("windows7.0")] | |||
[RequireComponent(typeof(CraftingComponent))] | |||
[RequireComponent(typeof(MinimapComponent))] | |||
[RequireComponent(typeof(LinkComponent))] | |||
[RequireComponent(typeof(OccupancyRequirementComponent))] | |||
[Tag("Usable")] | |||
[Ecopedia("Work Stations", "Craft Tables", subPageName: "Market Stall")] | |||
public partial class MedievalStallObject : WorldObject, IRepresentsItem | public partial class MedievalStallObject : WorldObject, IRepresentsItem | ||
{ | { | ||
public Type RepresentedItemType => typeof(MedievalStallItem); | public Type RepresentedItemType => typeof(MedievalStallItem); | ||
static MedievalStallObject() | |||
{ | |||
WorldObject.AddOccupancy<MedievalStallObject>(CalculateBoxOccupancy(4, 3, 3)); | |||
} | |||
protected override void Initialize() | |||
{ | |||
this.ModsPreInitialize(); | |||
this.GetComponent<LinkComponent>().Initialize(15); | |||
this.GetComponent<MinimapComponent>().SetCategory(Localizer.DoStr("Crafting")); | |||
this.ModsPostInitialize(); | |||
} | |||
/// <summary>Hook for mods to customize WorldObject before initialization. You can change housing values here.</summary> | |||
partial void ModsPreInitialize(); | |||
/// <summary>Hook for mods to customize WorldObject after initialization.</summary> | |||
partial void ModsPostInitialize(); | |||
/// <summary> | |||
/// Calculates the blocks that this item will occupy when placed. All coordinates are offsets relative to this 3D model's origin | |||
/// point. This function can only be used to calculate a box shape; there can be no gaps. All blocks will be of the | |||
/// BlockOccupancyType.None type. | |||
/// </summary> | |||
/// | |||
/// Examples: | |||
/// * Imagine a 1x1x1 cube. The origin point of the 3D model is the middle of the bottom-left cube. The only block the | |||
/// cube would occupy would be the same one the origin point is in. In offset coordinates, the only block the cube occupies | |||
/// is (0,0,0) from the origin point. | |||
/// * Image a 1x5x1 flag pole. Again the origin point of the 3D model is in the middle of the bottom most cube. The only | |||
/// blocks the flage pole occupies is the one the origin point is in and the 4 above that one. In offset coordinates, that | |||
/// would be (0,0,0) + (0,1,0) + (0,2,0) + (0,3,0) + (0,4,0). | |||
/// <returns></returns> | |||
private static List<BlockOccupancy> CalculateBoxOccupancy(int sizeX, int sizeY, int sizeZ) | |||
{ | |||
var cells = new List<BlockOccupancy>(sizeX * sizeY * sizeZ); | |||
for (int x = 0; x < sizeX; x++) | |||
for (int y = 0; y < sizeY; y++) | |||
for (int z = 0; z < sizeZ; z++) | |||
cells.Add(new BlockOccupancy(new Vector3i(x, y, z))); | |||
return cells; | |||
} | |||
} | } | ||
#endregion | #endregion | ||
} | } | ||
</syntaxhighlight>'''Line | </syntaxhighlight>'''Line 30:''' This changes from implementing <code>Item</code> to <code>WorldObjectItem<MedievalStallObject></code>. This is what tell Eco that this item has the ability to place a world object into the world. | ||
'''Line 32:''' This defines the object where <code>PersistentData</code> is stored. Other components like a ''PartsComponet'' would store the information of the table parts' durability in here. in this example, this line is illustrative and doesn't have any components using it. | |||
'''Line 34:''' Sets the type of occupancy context this world object has. Occupancy is the system used to determine what space blocks and object are in. The <code>SideAttachContext</code> means that this object must have a certain side supported for it to be attached to the world and valid to be placed. | |||
'''Line 35:''' Defines the bottom side as the side this object uses to attach. | |||
'''Line 36:''' This line is getting the list of blocks occupied from a static lookup in <code>WorldObject</code> for the <code>MedievalStallObject</code>. See line 60 to see this value set. | |||
'''Line | '''Line 41:''' The "collapsed" Recipe section. See earlier sections in this guide to see what code belongs here. | ||
'''Line | '''Line 46:''' Adds a <code>CraftComponent</code> to the table. This component lets players use this table to craft something on. | ||
'''Line | '''Line 47:''' <code>MinimapComponent</code> this registers the object with the minimap. This makes it so when a player places a medieval stall, the minimap shows it. Related: line 67. | ||
'''Line 48:''' <code>LinkComponent</code> allows storage linking. Related: line 66. | |||
'''Line 49:''' <code>OccupancyRequirementComponent</code> defines this object as having and occupying physical space. Related: line 60. | |||
'''Line 50:''' Assigns a tag to this object. Like how the tag ''Wood'' in Eco refers to all the different types of logs. In this case, the ''MedievalStallObject'' is being added to the <code>Usable</code> tag. | |||
'''Line 52:''' Declares the <code>MedievalStallObject</code>. It's important that this class name is matches exactly the <code>.prefab</code> file name because the name is what links them. | |||
'''Line 54:''' Declares the item that is given when this world object is picked up. | |||
'''Line 58:''' This sets the occupancy for the world object in the simulation. This must also be set for the object in addition to the ''Override Occupancy'' and ''Size'' setting previously set on the Unity <code>.prefab</code>. That's because the settings in Unity are used client side. This sets the occupancy on the server side. They both need to be set and be matching for things to work right. | |||
'''Line 64:''' Initializes the <code>LinkComponent</code> with a base 15 block radius. Know that this value is just the base value and that server settings will determine the actual game play radius. | |||
'''Line 65:''' Initializes the <code>MinimapComponent</code> and add this object to the <code>Crafting</code> category. | |||
=== Checkpoint === | === Checkpoint === | ||
==== | [[File:WikiDemo - Medieval Stall - Checkpoint -3.png|thumb|The Medieval Stall modded into Eco.]] | ||
'''Warning:''' In ''Eco'' v13.0.2, free-placed objects may display misaligned ghost cubes, even when configured correctly in your mod. This is a visual-only base-game bug — placement still works as expected, even if the object appears red near edges. <!-- See: https://github.com/StrangeLoopGames/EcoIssues/issues/25834 --> | |||
# Have the <code>.unity3d</code> and the <code>.cs</code> file in the <code>/Eco Server/Mods/UserCode</code> folder. | |||
# Start the server and log in. | |||
# Type <code>/give MedievalStall</code>. | |||
# Place the stall down. '''Pro-tip:''' Put down a floor of <u>flat roof</u> tiles made of ''Reinforced Concrete''. This will show you where the occupancy of your object is when you place it because the roof tiles will change shape under the object. Neat! | |||
# It should look and function like a normal workbench. | |||
The <code>WikiDemo.unity3d</code> and the <code>WikiDemo.cs</code> files are all that is needed to share this mod now. | |||
= Adding a Recipe to Craft = | |||
To add a recipe to the medieval stall add this to the <code>WikiDemo.cs</code> file:<syntaxhighlight lang="c#" line="1"> | |||
using Eco.Core.Items; | |||
using Eco.Gameplay.Components; | |||
using Eco.Gameplay.Items; | |||
using Eco.Gameplay.Items.Recipes; | |||
using Eco.Gameplay.Objects; | |||
using Eco.Gameplay.Skills; | |||
using Eco.Mods.TechTree; | |||
using Eco.Shared.Localization; | |||
using Eco.Shared.Serialization; | |||
using System.Collections.Generic; | |||
using System.Runtime.Versioning; | |||
using System; | |||
using Eco.Core.Controller; | |||
using Eco.Gameplay.Systems.NewTooltip; | |||
using Eco.Shared.Items; | |||
using Eco.Gameplay.Occupancy; | |||
using Eco.Shared.Math; | |||
using Eco.Gameplay.Components.Auth; | |||
namespace WikiDemo | |||
{ | |||
#region Item | |||
#region Recipe | |||
#region Object | |||
#region CraftingRecipes | |||
public partial class MyArrowRecipe : RecipeFamily | |||
{ | |||
[SupportedOSPlatform("windows7.0")] | |||
public MyArrowRecipe() | |||
{ | |||
var recipe = new Recipe(); | |||
recipe.Init( | |||
name: "Alternate Arrow", | |||
displayName: Localizer.DoStr("Alternate Arrow"), | |||
ingredients: new List<IngredientElement> | |||
{ | |||
new IngredientElement("Wood", 1, typeof(Skill)), | |||
new IngredientElement("Rock", 1) | |||
}, | |||
items: new List<CraftingElement> | |||
{ | |||
new CraftingElement<ArrowItem>(1) | |||
} | |||
); | |||
this.Recipes = new List<Recipe> { recipe }; | |||
this.LaborInCalories = CreateLaborInCaloriesValue(10); | |||
this.CraftMinutes = CreateCraftTimeValue(0.1f); | |||
// Perform pre/post initialization for user mods and initialize our recipe instance with the display name "Market Stall" | |||
this.ModsPreInitialize(); | |||
this.Initialize(displayText: Localizer.DoStr("Alternate Arrow Recipe"), recipeType: typeof(MyArrowRecipe)); | |||
this.ModsPostInitialize(); | |||
// Register our RecipeFamily instance to a work table (in this case the Carpentry Table) so it can be crafted. | |||
CraftingComponent.AddRecipe(tableType: typeof(MedievalStallObject), recipeFamily: this); // NOTE: The table must be the object instance! | |||
} | |||
/// <summary>Hook for other mods to customize RecipeFamily before initialization.</summary> | |||
partial void ModsPreInitialize(); | |||
/// <summary>Hook for other mods to customize RecipeFamily after initialization, but before registration. You can change skill requirements here.</summary> | |||
partial void ModsPostInitialize(); | |||
} | |||
#endregion | |||
} | |||
</syntaxhighlight> | |||
[[File:WikiDemo MedievalStall AltArrowRecipe.png|thumb|Shows a new recipe added to the crafting tab of the Medieval Stall.]] | |||
'''Line 58:''' This line here adds this recipe to the <code>MedievalStallObject</code> just created. | |||
Latest revision as of 20:49, 30 April 2026
Introduction
[edit | edit source]Below is a guide on how to take an 3D asset from the Unity Store and make a working workbench in Eco. This includes:
- Creating a recipe to craft the modded table
- Creating recipes so the player can use the modded table to craft something
- Using Blender to generate a modded icon (seen when holding it in inventory)
- Using Blender to adjust the origin point of the model
- How to setup all this in a Unity scene and package for Eco
Setup
[edit | edit source]- Already have setup ModKit + Unity
- Have a 3D model
- Just following along? Find the one used here at
https://assetstore.unity.com/packages/3d/props/low-poly-medieval-market-stalls-314286
- Just following along? Find the one used here at
- A C# IDE (notepad++, Visual Studio, etc.)
- Highly encouraged to have an Intellisense setup and linked to the Reference Assemblies. Optional, but its really worth the time to figure out because it will help quickly correct small typos and trivial mistakes.
- See: Getting Started with Eco Modding in Visual Studio 2022 (generally the same steps apply if using a new version of Visual Studio)
- Blender installed
- Homepage:
https://www.blender.org/
- Homepage:
Importing the Assets
[edit | edit source]- Open the Unity editor to the project.
- From the top toolbar open the Window drop down.
- Hover Package Management to open sub-menu.
- Select Package Manager.
- The Package Manager window will pop-up.
- Install the package containing the assets you want to use...
- If not using Unity Registry...
- Find the +▾ button in the top left and open the drop down.
- Install the package from one of those options.
- If using Unity Registry...
- Visit
https://assetstore.unity.comand sign in. - Search for the asset desired.
- Go to it's page (e.g.
https://assetstore.unity.com/packages/3d/props/low-poly-medieval-market-stalls-314286) and click the big blue button, Add to My Assets. - Now, in the Unity editor and back at the Package Manager window.
- Find My Assets on the left menu and navigate to it.
- Click the ⟳ button in the lower-right.
- The asset should be in the list now. Use the search to filter if needed.
- Click on the asset in the list. For those following along, Low Poly Medieval Market Stalls.
- In the right panel, find the Download ⤓ button. Click it.
- Once downloaded, a new button should show up, it'll say something like ⊕ Import 1.0 to project . Click it.
- The Import Unity Package window will pop-up.
- Select Import on it.
- Visit
- If not using Unity Registry...
- Verify you can find your assets from the explorer. If following along, the assets are at
Assets/PolyRonin/Medieval Market Stalls. - Load in a demo scene, if provided, and make sure everything looks okay.
- For those following along, double click on the Demo scene at
Assets/PolyRonin/Medieval Market Stalls/Demo.unity.
- For those following along, double click on the Demo scene at

If something seems off, check the different draw modes and see if changing those allow the scene to render as expected (see picture).
Creating The Worktable
[edit | edit source]This guide will create the worktable in this order:
- Create the item that represents the worktable
- Make a recipe to craft the worktable item
- Make the worktable item something that places a world object
- Give the worktable functionality by adding recipes to it
Creating the Item
[edit | edit source]Item Icon
[edit | edit source]
- Open Blender.
- Delete everything in the Scene Collection. Find this section in the top-right of the application.
- From the top toolbar, open the File drop down.
- Hover Import to open the sub-menu.
- Select the type of 3D asset. For those using medieval assets, select FBX (.fbx).
- Find the asset on the computer...
Tip: Use Unity to find the.fbxasset.- For the medieval assets, that's in
Assets/PolyRonin/Medieval Market Stalls/Meshes/medieval-market-stalls-1.fbx. - Right click on it and select Show in explorer.
- Now copy the address of that folder from Explorer. It might look like
C:\Users\Wug\EcoMod--WikiDemo\WikiDemo\Assets\PolyRonin\Medieval Market Stalls\Meshes. - Paste that in the address bar of the Blender import pop-up.
- For the medieval assets, that's in
- Select the blue Import FBX button.
- Be in the Layout workspace (top toolbar) and in the Object Mode...
- Find the drop down in the second toolbar from the top that has options like Object Mode, Edit Mode, Sculpt Mode, etc.
- Select Object Mode from that drop down.
- Change the Viewport Shading to Material Preview or Rendered. This is on the second toolbar down, far right of center, but before Scene Collection section.
- If you see purple models, Blender will need help finding textures for these meshes...
- From the top toolbar, open the File drop down.
- Hover External Data to open the sub-menu.
- Select Find Missing Files...
- Point this to the whole directory that the 3D assets came in. For the medieval pack,
C:\Users\Wug\EcoMod--WikiDemo\WikiDemo\Assets\PolyRonin. - The proper textures/materials should have now loaded in. If it hasn't, consult Google because without the textures the following steps won't produce a usable icon.
- Add a source of light...
- Still be in the Layout workspace (top toolbar) and in the Object Mode...
- Find the drop down in the second toolbar from the top that has options like Object Mode, Edit Mode, Sculpt Mode, etc.
- Select Object Mode from that drop down.
- From the toolbar just under that one, find and open the Add drop down.
- Hover Light to open that sub-menu.
- Click Sun.
- Still be in the Layout workspace (top toolbar) and in the Object Mode...
- Add a camera...
- In the Layout workspace (top toolbar) and in the Object Mode...
- Find the drop down in the second toolbar from the top that has options like Object Mode, Edit Mode, Sculpt Mode, etc.
- Select Object Mode from that drop down.
- From the second toolbar down, find and open the Add drop down.
- Select Camera.
- In the Layout workspace (top toolbar) and in the Object Mode...
- Setup the scene with the object placement and lighting direction desired.
Tip: To reset the editor to something selected press the period key on the numpad. Without a numpad, use View (second toolbar from the top) and select Frame Selected from it. Alternatively, just set the zoom to zoom to the mouse position: Edit (top toolbar), Preferences (from drop down), Navigation (on left menu), Zoom to Mouse Position (In the zoom section). This makes moving around a lot more natural feeling. - Setup the rendering camera...
- Go to Rendering tab on the top toolbar
- On the right there will be a side-panel open, it should be the Render tab. Confirm that.
- Change Render Engine to Cycles.
- Look down below in the same tab for the Film section.
- Expand it and find the Transparent checkbox and section. Click it so that it has a check mark. This will make the icon's background transparent.
- Now, go to the Output tab on the side panel. The tab is just below the current one.
- In the Format section set Resolution X to 64. And Y to 64 as well. This will make the icon generated a 64 by 64 pixel image.
- Go back to the Layout tab from the top toolbar.
- Center your view on the object (numpad period or View > Frame Selected). Adjust it so that the object is how it should be for the icon.
- Align the camera to the view...
- Make sure the editor is in Layout workspace (top toolbar) and in the Object Mode...
- Find the drop down in the second toolbar from the top that has options like Object Mode, Edit Mode, Sculpt Mode, etc.
- Select Object Mode from that drop down.
- Find View from the second from the top toolbar and open the drop down.
- Hover Align View to open the sub-menu.
- Select Align Active Camera To View.
- If the view is slightly off, there is a lock icon on the right side of this panel. Use it to "lock" controls to the camera and tweak it's view.
- Make sure the editor is in Layout workspace (top toolbar) and in the Object Mode...
- Now return to the Rendering tab from the top toolbar.
- Press the F12 key to start the render. This should complete quickly since 64x64 pixels is a very small render.
- A window should popup, Blender Render. This is the icon!
- From the top tool bar of this Blender Render window, open the Image drop down.
- Select Save As... to save somewhere on the computer.
- Return to step 13 and repeat to do larger images if desired. Create a 128 by 128 pixel image too. It will make things smoother later.
- Save the Blender scene. Not only will it be used later, this will make making a new icon with a small tweak that much easier.
- File drop down from top toolbar.
- Save As... to save the Blender scene to the computer.
- Save it to
Assets/WikiDemo/MedievalStall - Icon Scene.blend.
Adding to Unity Scene
[edit | edit source]The developers explain how to create an item in one of ModKit's read me files (See: Assets/EcoModKit/Docs/README.md), but this guide will explain it below.
Additionally, TheKye on YouTube covers this in their Creating Your First Item and Creating Your First Item Pt 2 videos.
Use those additional resource to help troubleshoot issues with item's icons.
- Open Unity.
- In the left panel, the Hierarchy tab should be selected.
- Select the top-most object there. It should be a scene. If the editor last loaded the Demo scene from the medieval assets, it'll be named Demo.
- Right click on this scene and select Add New Scene from the menu.
- Right click again on the old scene (Demo) and select Remove Scene.
- Let it save if the changes to the old scene are important. Discard if it was open just for exploration's sake.
- Right click the new, Untitled scene. Click Save Scene As...
- Save it to
Assets/WikiDemo.unity. - Delete anything in the scene.
- Right click the scene, hover GameObject, and select Create Empty from the sub-menu.
- Name this new object Objects.
- Select the newly created Objects object from the Hierarchy menu.
- On the far right side of the screen, in the Inspector menu, click the Add Component button.
- Type in ModkitPrefabContainer. Click on the component from the search to add it. The component now should be listed in the Inspector.
- In the Hierarchy panel right click the scene, hover GameObject, and select Create Empty.
- Name this new object Items.
- Right click the scene, hover GameObject, and select Create Empty.
- Name this new object Emoji.
- Select the newly created Emoji object, find the Inspector menu (far-right), and click the Add Component button.
- Type in ChatEmoteSetOld. Click on the component from the search to add it. That component should now be listed in the Inspector.
- Right click the scene, hover GameObject, and select Create Empty.
- Name this new object BlockSets.
- Select the newly created BlockSets object, find the Inspector menu (far-right), and click Add Component.
- Search for BlockSetContainer. Click on the component from the search to add it. The Inspector should now show that component as added.
- Go to
Assets/EcoModKit/Prefabsin the Unity project window. - Find the prefab ItemTemplate.
- Drag it onto the Items object in the Hierarchy panel. It should add it as a child of the Items object.
- Right click on the new ItemTemplate object, hover Prefab, and select Unpack Completely.
- Right click on the ItemTemplate object and select Rename. Name this what you want the item to be called. Example: MedievalStallItem.
- Set this item's background...
- Here's the default backgrounds (blue = item, brown = block, green = food):

- Download or prepare the background and add it to the
Assetsfolder in Unity.- To follow along lockstep, put the background in a new
Assets/WikiDemofolder. - Right click on
Assetsfolder, hover Create, select Folder. - Name the folder WikiDemo.
- To follow along lockstep, put the background in a new
- Configure Unity to use these as sprites...
- Select the background(s) added (Ctrl+Click each one).
- In the Inspector, find TextureType and change that to Sprite (2D and UI).
- Again in the Inspector, find SpriteMode and change that to Single.
- Then scroll and go to the bottom of the Inspector and find the Apply button.
- This will apply those changes to that file and all other ones highlighted.
- Select the item being created (MedievalStallItem).
- In the Inspector panel (far-right), scroll and find the Item Template (Script) section.
- In here find the Background input. It'll say Background (Image) in it. If clicked that text to reveal and highlight the related object in the Hierarchy panel.
- Select the revealed, and highlighted object Background.
- In the Inspector panel, scroll and find the Image component section.
- Inside that component's section, find Source Image. It'll say Missing (Sprite). Click the ⦿ button to the right.
- The Select Sprite popup will show. Make sure the Assets tab is selected, and find the backgrounds desired.
- Here's the default backgrounds (blue = item, brown = block, green = food):
- Create the foreground image...
- This is easily accomplished in MS Paint.
- Get to the background image file in a file explorer.
- Right click on it, hover Open with..., and select Paint.
- The solid background should be displayed.
- Open the File menu from the top toolbar.
- Hover Import to Canvas and select From a File.
- Find the icon in the file browser and import it. Match the size of the background image to have it nicely center itself.
- Now File from the top toolbar.
- Hover Save As... and select PNG.
- Save this to the
Assets/WikiDemofolder in Unity. - Configure Unity to use these as sprites...
- Select the foreground image.
- In the Inspector, find TextureType and change that to Sprite (2D and UI).
- Again in the Inspector, find SpriteMode and change that to Single.
- Then scroll and go to the bottom of the Inspector and find the Apply button.
- This will apply those changes to that file and all other ones highlighted.
- Set this item's foreground...
- Copy the item's icon into the
Assetsfolder. - Configure Unity to use it as a sprite (see the previous step's Set this item's background... instructions)
- Select the item being created (MedievalStallItem).
- In the Inspector panel (far-right), scroll and find the Item Template (Script) section.
- In here find the Foreground input. It'll say Foreground (Image) in it. If clicked that text to reveal and highlight the related object in the Hierarchy panel.
- Select the revealed, and highlighted object Foreground.
- Use the Inspector, find the Image component, within that component find the Source Image input. It will say Missing (Sprite).
- Click the ⦿ button to the right of that input.
- From the Select Sprite popup, ensure the Assets tab is being searched, and find the icon just created.
- Copy the item's icon into the
Export From Unity
[edit | edit source]- Open the File menu from the top toolbar.
- Select Save. Save it to the
Assets/WikiDemofolder.
Note: Do not skip. The scene must be saved for the ModKit build to work properly. - Open the Eco Tools menu from the top toolbar.
- Hover Mod Kit to open the sub-menu.
- Select Build Current Bundle.
- Have it output the bundle to
/Eco Server/Mods/UserCode/WikiDemo.unity3d - Wait for this to build. This may take a few minutes.
Coding the Item
[edit | edit source]For this guide, all code will be placed in a single .cs file and will not be compiled into a .dll.
- Create a
.csfile:/Eco Server/Mods/UserCode/WikiDemo.cs - Put the following into the newly created file:
using Eco.Core.Items;
using Eco.Gameplay.Items;
using Eco.Shared.Localization;
using Eco.Shared.Serialization;
namespace WikiDemo
{
#region Item
[Serialized] // Tells the save/load system this object needs to be serialized.
[LocDisplayName("Market Stall")] // Defines the localized name of the item.
[Weight(100)] // Defines how heavy this is.
[Ecopedia("Work Stations", "Craft Tables", createAsSubPage: true)]
[LocDescription("A medieval market stall.")] //The tooltip description for the item.
public partial class MedievalStallItem: Item { }
#endregion
}
Line 8: A region tag. Lets the editor know it can collapse all of that code as a section. The following examples in this guide will just show #region Item in their code examples.
Line 13: The implementation of Item means that Eco will find this and look for Unity assets that matching this class' name, MedivalStallItem. While this doesn't do anything fancy, it completes the first step towards a new workbench.
Checkpoint #1
[edit | edit source]
Make sure everything is running smoothly by doing the following:
- Double-check that the
WikiDemo.unity3dand theWikiDemo.csfiles are in/Eco Server/Mods/UserCodefolder. - Start the server and connect to it.
- Test it out by typing
/give MedievalStallin chat.- It's also possible to do
/give Market Stallto get the item. How? Line 10: of the the above code declares that name as this item's "common name". Neat.
- It's also possible to do
- The item should appear in the players inventory with a working icon.
Code the Item's Recipe
[edit | edit source]
The following goes over how to add a new class and implement the RecipeFamily interface.
using Eco.Core.Items;
using Eco.Gameplay.Components;
using Eco.Gameplay.Items;
using Eco.Gameplay.Items.Recipes;
using Eco.Gameplay.Skills;
using Eco.Mods.TechTree;
using Eco.Shared.Localization;
using Eco.Shared.Serialization;
using System.Runtime.Versioning;
using System.Collections.Generic;
namespace WikiDemo
{
#region Item
#region Recipe
[RequiresSkill(typeof(CarpentrySkill), 3)]
[Ecopedia("Work Stations", "Craft Tables", subPageName: "Market Stall")]
public partial class MedievalStallRecipe : RecipeFamily
{
[SupportedOSPlatform("windows7.0")]
public MedievalStallRecipe()
{
var recipe = new Recipe();
recipe.Init(
name: "MedievalStallItem",
displayName: Localizer.DoStr("Market Stall"),
ingredients: new List<IngredientElement>
{
new IngredientElement("Wood", 40, typeof(CarpentrySkill)),
new IngredientElement(typeof(CottonFabricItem), 30, typeof(CarpentrySkill)),
new IngredientElement(typeof(HempMooringRopeItem), 5, true)
},
items: new List<CraftingElement>
{
new CraftingElement<MedievalStallItem>(1)
}
);
this.Recipes = new List<Recipe> { recipe };
this.LaborInCalories = CreateLaborInCaloriesValue(800, typeof(CarpentrySkill));
this.CraftMinutes = CreateCraftTimeValue(typeof(MedievalStallRecipe), 10f, typeof(CarpentrySkill));
// Perform pre/post initialization for user mods and initialize our recipe instance with the display name "Market Stall"
this.ModsPreInitialize();
this.Initialize(displayText: Localizer.DoStr("Market Stall"), recipeType: typeof(MedievalStallRecipe));
this.ModsPostInitialize();
// Register our RecipeFamily instance to a work table (in this case the Carpentry Table) so it can be crafted.
CraftingComponent.AddRecipe(tableType: typeof(CarpentryTableObject), recipeFamily: this); // NOTE: The table must be the object instance!
}
/// <summary>Hook for other mods to customize RecipeFamily before initialization.</summary>
partial void ModsPreInitialize();
/// <summary>Hook for other mods to customize RecipeFamily after initialization, but before registration. You can change skill requirements here.</summary>
partial void ModsPostInitialize();
}
#endregion
}
Line 10: Eco will need this explicitly added to the file. Visual Studio will not add this line automatically. It's used for the List<T> objects found in this code.
Line 14: "Collapsed" Item section. See the earlier sections in this guide for the code that belongs there.
Line 17: Sets the required skill and skill level to craft this recipe.
Line 21: [SupportedOSPlatform("windows7.0")] is here to silence some annoying warnings in Visual Studio. It's optional.
Line 30-32: Declares the input ingredients used for crafting. CarpentrySkill as defined by line 31. In this example the HempMooringRope is a static input. A static input will not be modified by skills, upgrade modules, or game settings.
Note: It seems that at the time of writing (4/21/2026, Eco v13.0.2) the only way to get an ingredient to be a dynamic value that is reduced by the table's upgrade is to pass typeof(Skill) to it; Passing either true or false makes the this input static.
Line 34: The items list declares what items are output by this recipe.
Line 36: This line declares that one medieval stall is output from this recipe. Functionally this links this recipe to the MedievalStallItem (aka "Market Stall") item created in the last step.
Line 40: Amount of calories needed to craft this item. For a static value (not modified by upgrades or skill levels) change this line to: this.LaborInCalories = CreateLaborInCaloriesValue(800);. As it's written in the example, this item's calorie cost will be dynamic (modified by upgrades and skill levels). The skill level that will modify it is declared on line 16.
Line 41: Minutes needed to craft. Both static and dynamic values for crafting time can be modified by the world difficulty settings. For a static value change this line to: this.CraftMinutes = CreateCraftTimeValue(10f);. As it's written in the example, this item's craft time will be dynamic.
Line 49: This line assigns the recipe to a workbench. Do not assign to itself because then the first table could never be made. It's recommend to use a preexisting vanilla table.
Checkpoint #2
[edit | edit source]Check the functionality at this point -- it should be possible to see the recipe in the crafting table.
- Have the
.unity3dand the.csfile in the/Eco Server/Mods/UserCodefolder. - Start the server and log in.
- Type
/give Carpentry Table. - Place the Carpentry Table down and interact to see the what can be crafted.
- Find the newly added recipe under the name Market Stall.
- Type
/give Basic Upgrade 4. - Put the basic upgrade into the table.
- Go back to the recipe for the Market Stall and make sure the Wood and the Cotton fabric inputs now require less, but the Hemp Mooring Rope still is the same.
Note: In case the recipe hasn't changed close that table's window and interact with it again. It should for the recipes to refresh now that the upgrade is in it.
Create the World Object
[edit | edit source]Preparing the 3D Asset
[edit | edit source]- Open Blender.
- Load the 3D object created earlier for icon rendering --
Assets/WikiDemo/MedievalStall - Icon Scene.blend. - Cleanup the scene...
- Delete any light source. Use the Scene Collection panel on the top-right side of the screen. These will have a 💡 icon and by default are named something like "sun", "point", "spot" or "area".
Note: If your model is a light source or has one in it, you can leave that light source. The point here is to remove the ambient lights used for icon rendering. - Delete any camera(s). Again, use the Scene Collection panel. These have a 🎥 icon and by default are named something like "camera".
- Delete any light source. Use the Scene Collection panel on the top-right side of the screen. These will have a 💡 icon and by default are named something like "sun", "point", "spot" or "area".
- If there are multiple different 3D assets in the scene (like bags, crates, jars, ect.), join them all together...
- Select all of the meshes by holding Shift and clicking on each one in the Scene Collection panel (right side of window).
Tip: Quickly select a group of them by selecting one near the top. Then hold Shift, Ctrl, and click on one near the bottom. This will both the one at the top and the one at the bottom, but also every item in between. Neat! - Be in Layout workspace (top toolbar) and in the Object Mode...
- Find the drop down in the second toolbar from the top that has options like Object Mode, Edit Mode, Sculpt Mode, etc.
- Select Object Mode from that drop down.
- Find and open the Object menu (second toolbar down from the top).
- Select Join.
- In the Scene Collection panel, double click on the name of the newly joined mesh.
- Select all of the meshes by holding Shift and clicking on each one in the Scene Collection panel (right side of window).
- Rename the joined mesh to
MedievalStallMesh. - Add and position a reference cube...
- Make sure the editor is in Layout view (top toolbar) and in the Object Mode...
- Find the drop down in the second toolbar from the top that has options like Object Mode, Edit Mode, Sculpt Mode, etc.
- Select Object Mode from that drop down.
- Then, add a reference cube. Open the Add menu (second top toolbar down).
- Hover Mesh.
- Select Cube.
- Open the View menu (second toolbar down).
- Select Sidebar.
- A new panel will have expanded.
- Along the right side of that panel there's buttons (Item, Tool, View, Animation). Find and click the Item button.
- Find and expand the Transform section
- Set the Location...
- X to 1.
- Y to 1.
- Z to 1.
- The bottom corner of the cube should be touching the where green and red axis lines meet.
- Make sure the editor is in Layout view (top toolbar) and in the Object Mode...
- Move the reference cube's origin to
(0, 0, 0)...- Be in Layout workspace (top toolbar) and in the Object Mode...
- Find the drop down in the second toolbar from the top that has options like Object Mode, Edit Mode, Sculpt Mode, etc.
- Select Object Mode from that drop down.
- Open the View menu (second toolbar down).
- Select Sidebar.
- A new panel will have expanded.
- Along the right side of that panel there's buttons (Item, Tool, View, Animation). Find and click the View button.
- Find and expand the 3D Cursor section.
- Set the 3D cursor's Location...
- X to 0.
- Y to 0.
- Z to 0.
- Now in the Scene Collection panel, click on the Cube mesh to highlight and select it.
- Open the Object menu from the second toolbar down from the top.
- Hover Set Origin.
- Select Origin to 3D Cursor.
- Be in Layout workspace (top toolbar) and in the Object Mode...
- Set the reference cube's dimensions...
- Be in Layout workspace (top toolbar) and in the Object Mode...
- Find the drop down in the second toolbar from the top that has options like Object Mode, Edit Mode, Sculpt Mode, etc.
- Select Object Mode from that drop down.
- Open the View menu (second toolbar down).
- Select and check the Sidebar option.
- The Sidebar menu just expanded over on the right side of the screen.
- To the right of the Sidebar, find and click the Item button.
- Expand the Transform section.
- Set the Dimensions...
Note: These dimensions only make sense for the asset being used for this guide. If using a different one, set the dimensions to the size of the box that model should fit in.- X to 4.
- Y to 3.
- Z to 3.
- Be in Layout workspace (top toolbar) and in the Object Mode...
- Adjust the position and scale of the MedievalStallMesh to fit inside a box.
- Be in Layout workspace (top toolbar) and in the Object Mode...
- Find the drop down in the second toolbar from the top that has options like Object Mode, Edit Mode, Sculpt Mode, etc.
- Select Object Mode from that drop down.
- On the left side of the screen there's a column of icons. Hover over them to see their names.
- Select the Move tool.
- Click on the Medieval Stall to select it. Zoom out and reposition the camera so that the blue, green, and red arrows are visible.
Tip: By holding the middle-mouse button and dragging the scene will rotate. By holding the middle-mouse button and the Shift key, the scene will pan.
Tip: If panning or rotating the scene becomes slow or frustrating (especially after zooming), try selecting 3D asset from the Scene Collection panel, opening the View menu (second toolbar from top), and selecting Frame Selected. This will reset the view onto that object and controls should feel normal again. - Click and hold one of the arrows. Move the mouse to drag the 3D asset towards the box.
- Move the 3D asset around till it's completely inside the box. If it cannot fit and is too big, continue to the next step.
Tip: To select the 3D asset once it disappears, use the Scene Collection panel. Click on it there and the blue, green, and red arrows will show up again for it.
Tip: There are preset views. To use them go to the View menu (second toolbar from top), hover Viewpoint, and select the view that would be most helpful. - Find the Scale tool from the left side of the screen.
- Now the blue, green, and red "arrows" don't really look like arrows anymore. They are lines with boxes at the end.
- Click and hold on those lines to adjust the scale of the 3D asset to make it fit inside the box.
Tip: There are little colored boxes in between the lines that can be dragged to scale the 3D asset more proportionally. - Continue using the Move and Scale tools till the model fits. This will take patience and time.
Tip: Hide the reference cube to see what is happening with the 3D asset. Go to the Scene Collections panel and click the 👁 button to hide it. Click that button again to show it.
- Be in Layout workspace (top toolbar) and in the Object Mode...
- Move the reference cube's origin to
(0.5, 0.5, 0.5)...- Be in Layout workspace (top toolbar) and in the Object Mode...
- Find the drop down in the second toolbar from the top that has options like Object Mode, Edit Mode, Sculpt Mode, etc.
- Select Object Mode from that drop down.
- Open the View menu (second toolbar down).
- Select Sidebar.
- A new panel will have expanded.
- Along the right side of that panel there's buttons (Item, Tool, View, Animation). Find and click the View button.
- Find and expand the 3D Cursor section.
- Set the 3D cursor's Location...
- X to 0.5.
- Y to 0.5.
- Z to 0.5.
- Select the MedievalStallMesh using the Scene Collection panel.
- Open the Object menu (second toolbar down).
- Hover Set Origin.
- Select Origin to 3D Cursor.
- Be in Layout workspace (top toolbar) and in the Object Mode...
- Select the reference cube named Cube from the Scene Collections panel.
- Open Object menu (second toolbar down).
- Select Delete.
- Move the MedievalStallMesh to
(0, 0, 0)...- Be in Layout workspace (top toolbar) and in the Object Mode...
- Find the drop down in the second toolbar from the top that has options like Object Mode, Edit Mode, Sculpt Mode, etc.
- Select Object Mode from that drop down.
- Open the View menu (second toolbar down).
- Select Sidebar.
- A new panel will have expanded.
- Along the right side of that panel there's buttons (Item, Tool, View, Animation). Find and click the Item button.
- Make sure the MedievalStallMesh is selected. Use the Scene Collection panel if needed.
- Find and expand the Transform section
- Set the Location...
- X to 0.
- Y to 0.
- Z to 0.
- Be in Layout workspace (top toolbar) and in the Object Mode...
- Make sure the MedievalStallMesh is selected. Use the Scene Collection panel if needed.
- Open the Object menu.
- Hover Apply.
- Select All Transformations.
Note: This step bakes all of the changes into the mesh. It's very important. - Open the File menu from the top toolbar.
- Hover Export to open the sub-menu.
- Select FBX (.fbx)
- A Blender File View window will pop-up.
- On the right side of this window there's a ⚙️ icon. Click it to expand the settings region.
- In the expanded region find the Include section and expand it. Change the following:
- Find Object Types and only select Mesh. No other option should be highlighted for this setting.
- In the settings region scroll and find the Transform section and expand it. Change the following:
- Find Apply Scalings and set it to FBX All.
- Just below that find Forward and set it to Z Forward.
- Ensure that the next setting down, Up, changed to Y Up.
- Find Apply Unit and make sure it's checked.
- Next, find Use Space Transform check it.
- Lastly, find Apply Transform and check it too.
- Save it to
Assets/WikiDemo/MedievalStall.fbx. - Save the Blender scene...
- File drop down from top toolbar.
- Save As... to save the Blender scene to the computer.
- Save it to
Assets/WikiDemo/MedievalStall - Eco Ready Scene.blend.
Add to Unity Scene
[edit | edit source]- Open Unity.
- Select the
.fbxfile in the project window. - Open the Eco Tools menu from the top toolbar.
- Hover Mod Kit.
- Select World Object Setup.
- A World Object Setup window will pop-up.
- Make sure that Selected Objects reads MedievalStall.
- Also make sure that World Object Type is set to World Object.
- Press the Setup World Objects button.
- Notice in the project window that a new
.prefabfile was created --MedievalStallObject.prefab - Select the
.prefab. - In the Inspector panel find the Transform component.
- Change this component's Rotation...
- X to 0.
- Y to 0.
- Z to 0.
- In the Inspector panel find the Box Collider component.
- Find the ⋮ icon (all the way to the right of the words Box Collider) and click on it.
- Select Reset from the menu. This will regenerate the box collider now that the rotation has changed.
- Look in the Inspector panel and find the World Object (Script) component.
- That component has a checkbox Override Occupancy. Check it.
- A new field should've expanded below it called Size.
- Set the Size...
Note: This size similar to the size of the reference cube from earlier, but the Y and Z coordinates get flipped! So if in Blender it was(1, 2, 3)then in Unity its(1, 3, 2).- X to 4.
- Y to 3.
- Z to 3.
- Select Objects from Hierarchy panel (left-side of the window).
- Find the Modkit Prefab Container (Script) component. This component was added earlier, if it's not there add it now.
- Expand the Prefabs section in that component.
- Click the + button to add an item to the list.
- Either...
- Click the ⦿ button, switch to the Assets tab, find or search for MedievalStallObject, and double click on it. Make sure it's the medieval stall object with the
.prefabending. - Drag the
.prefabfile onto the ⦿ button
- Click the ⦿ button, switch to the Assets tab, find or search for MedievalStallObject, and double click on it. Make sure it's the medieval stall object with the
- Open the File menu from top toolbar and select Save.
Note: Do not skip. The scene must be saved for the ModKit build to work properly. - Open the Eco Tools menu from the top toolbar.
- Hover Mod Kit.
- Select Build Current Bundle.
- Save the bundle to
/Eco Server/Mods/UserCode/WikiDemo.unity3d
Coding the World Object
[edit | edit source]The following collapses the #region Recipe. Please see the earlier section Code the Item's Recipe to get the code that belongs there.
Add the new using lines, replace the #region Item section, and replace the #region Object sections using the following:
using Eco.Core.Items;
using Eco.Gameplay.Components;
using Eco.Gameplay.Items;
using Eco.Gameplay.Items.Recipes;
using Eco.Gameplay.Objects;
using Eco.Gameplay.Skills;
using Eco.Mods.TechTree;
using Eco.Shared.Localization;
using Eco.Shared.Serialization;
using System.Collections.Generic;
using System.Runtime.Versioning;
using System;
using Eco.Core.Controller;
using Eco.Gameplay.Systems.NewTooltip;
using Eco.Shared.Items;
using Eco.Gameplay.Occupancy;
using Eco.Shared.Math;
using Eco.Gameplay.Components.Auth;
namespace WikiDemo
{
#region Item
[Serialized] // Tells the save/load system this object needs to be serialized.
[SupportedOSPlatform("windows7.0")]
[LocDisplayName("Market Stall")] // Defines the localized name of the item.
[Weight(3000)] // Defines how heavy this is.
[Ecopedia("Work Stations", "Craft Tables", createAsSubPage: true)]
[LocDescription("A medieval market stall.")] //The tooltip description for the item.
public partial class MedievalStallItem : WorldObjectItem<MedievalStallObject>, IPersistentData
{
[Serialized, SyncToView, NewTooltipChildren(CacheAs.Instance, flags: TTFlags.AllowNonControllerTypeForChildren)] public object? PersistentData { get; set; }
protected override OccupancyContext GetOccupancyContext => new SideAttachedContext(
DirectionAxisFlags.Down, // Read: every occupied block on the bottom must be supported
WorldObject.GetOccupancyInfo(this.WorldObjectType)
);
}
#endregion
#region Recipe
#region Object
[Serialized]
[SupportedOSPlatform("windows7.0")]
[RequireComponent(typeof(CraftingComponent))]
[RequireComponent(typeof(MinimapComponent))]
[RequireComponent(typeof(LinkComponent))]
[RequireComponent(typeof(OccupancyRequirementComponent))]
[Tag("Usable")]
[Ecopedia("Work Stations", "Craft Tables", subPageName: "Market Stall")]
public partial class MedievalStallObject : WorldObject, IRepresentsItem
{
public Type RepresentedItemType => typeof(MedievalStallItem);
static MedievalStallObject()
{
WorldObject.AddOccupancy<MedievalStallObject>(CalculateBoxOccupancy(4, 3, 3));
}
protected override void Initialize()
{
this.ModsPreInitialize();
this.GetComponent<LinkComponent>().Initialize(15);
this.GetComponent<MinimapComponent>().SetCategory(Localizer.DoStr("Crafting"));
this.ModsPostInitialize();
}
/// <summary>Hook for mods to customize WorldObject before initialization. You can change housing values here.</summary>
partial void ModsPreInitialize();
/// <summary>Hook for mods to customize WorldObject after initialization.</summary>
partial void ModsPostInitialize();
/// <summary>
/// Calculates the blocks that this item will occupy when placed. All coordinates are offsets relative to this 3D model's origin
/// point. This function can only be used to calculate a box shape; there can be no gaps. All blocks will be of the
/// BlockOccupancyType.None type.
/// </summary>
///
/// Examples:
/// * Imagine a 1x1x1 cube. The origin point of the 3D model is the middle of the bottom-left cube. The only block the
/// cube would occupy would be the same one the origin point is in. In offset coordinates, the only block the cube occupies
/// is (0,0,0) from the origin point.
/// * Image a 1x5x1 flag pole. Again the origin point of the 3D model is in the middle of the bottom most cube. The only
/// blocks the flage pole occupies is the one the origin point is in and the 4 above that one. In offset coordinates, that
/// would be (0,0,0) + (0,1,0) + (0,2,0) + (0,3,0) + (0,4,0).
/// <returns></returns>
private static List<BlockOccupancy> CalculateBoxOccupancy(int sizeX, int sizeY, int sizeZ)
{
var cells = new List<BlockOccupancy>(sizeX * sizeY * sizeZ);
for (int x = 0; x < sizeX; x++)
for (int y = 0; y < sizeY; y++)
for (int z = 0; z < sizeZ; z++)
cells.Add(new BlockOccupancy(new Vector3i(x, y, z)));
return cells;
}
}
#endregion
}
Line 30: This changes from implementing Item to WorldObjectItem<MedievalStallObject>. This is what tell Eco that this item has the ability to place a world object into the world.
Line 32: This defines the object where PersistentData is stored. Other components like a PartsComponet would store the information of the table parts' durability in here. in this example, this line is illustrative and doesn't have any components using it.
Line 34: Sets the type of occupancy context this world object has. Occupancy is the system used to determine what space blocks and object are in. The SideAttachContext means that this object must have a certain side supported for it to be attached to the world and valid to be placed.
Line 35: Defines the bottom side as the side this object uses to attach.
Line 36: This line is getting the list of blocks occupied from a static lookup in WorldObject for the MedievalStallObject. See line 60 to see this value set.
Line 41: The "collapsed" Recipe section. See earlier sections in this guide to see what code belongs here.
Line 46: Adds a CraftComponent to the table. This component lets players use this table to craft something on.
Line 47: MinimapComponent this registers the object with the minimap. This makes it so when a player places a medieval stall, the minimap shows it. Related: line 67.
Line 48: LinkComponent allows storage linking. Related: line 66.
Line 49: OccupancyRequirementComponent defines this object as having and occupying physical space. Related: line 60.
Line 50: Assigns a tag to this object. Like how the tag Wood in Eco refers to all the different types of logs. In this case, the MedievalStallObject is being added to the Usable tag.
Line 52: Declares the MedievalStallObject. It's important that this class name is matches exactly the .prefab file name because the name is what links them.
Line 54: Declares the item that is given when this world object is picked up.
Line 58: This sets the occupancy for the world object in the simulation. This must also be set for the object in addition to the Override Occupancy and Size setting previously set on the Unity .prefab. That's because the settings in Unity are used client side. This sets the occupancy on the server side. They both need to be set and be matching for things to work right.
Line 64: Initializes the LinkComponent with a base 15 block radius. Know that this value is just the base value and that server settings will determine the actual game play radius.
Line 65: Initializes the MinimapComponent and add this object to the Crafting category.
Checkpoint
[edit | edit source]
Warning: In Eco v13.0.2, free-placed objects may display misaligned ghost cubes, even when configured correctly in your mod. This is a visual-only base-game bug — placement still works as expected, even if the object appears red near edges.
- Have the
.unity3dand the.csfile in the/Eco Server/Mods/UserCodefolder. - Start the server and log in.
- Type
/give MedievalStall. - Place the stall down. Pro-tip: Put down a floor of flat roof tiles made of Reinforced Concrete. This will show you where the occupancy of your object is when you place it because the roof tiles will change shape under the object. Neat!
- It should look and function like a normal workbench.
The WikiDemo.unity3d and the WikiDemo.cs files are all that is needed to share this mod now.
Adding a Recipe to Craft
[edit | edit source]
To add a recipe to the medieval stall add this to the WikiDemo.cs file:
using Eco.Core.Items;
using Eco.Gameplay.Components;
using Eco.Gameplay.Items;
using Eco.Gameplay.Items.Recipes;
using Eco.Gameplay.Objects;
using Eco.Gameplay.Skills;
using Eco.Mods.TechTree;
using Eco.Shared.Localization;
using Eco.Shared.Serialization;
using System.Collections.Generic;
using System.Runtime.Versioning;
using System;
using Eco.Core.Controller;
using Eco.Gameplay.Systems.NewTooltip;
using Eco.Shared.Items;
using Eco.Gameplay.Occupancy;
using Eco.Shared.Math;
using Eco.Gameplay.Components.Auth;
namespace WikiDemo
{
#region Item
#region Recipe
#region Object
#region CraftingRecipes
public partial class MyArrowRecipe : RecipeFamily
{
[SupportedOSPlatform("windows7.0")]
public MyArrowRecipe()
{
var recipe = new Recipe();
recipe.Init(
name: "Alternate Arrow",
displayName: Localizer.DoStr("Alternate Arrow"),
ingredients: new List<IngredientElement>
{
new IngredientElement("Wood", 1, typeof(Skill)),
new IngredientElement("Rock", 1)
},
items: new List<CraftingElement>
{
new CraftingElement<ArrowItem>(1)
}
);
this.Recipes = new List<Recipe> { recipe };
this.LaborInCalories = CreateLaborInCaloriesValue(10);
this.CraftMinutes = CreateCraftTimeValue(0.1f);
// Perform pre/post initialization for user mods and initialize our recipe instance with the display name "Market Stall"
this.ModsPreInitialize();
this.Initialize(displayText: Localizer.DoStr("Alternate Arrow Recipe"), recipeType: typeof(MyArrowRecipe));
this.ModsPostInitialize();
// Register our RecipeFamily instance to a work table (in this case the Carpentry Table) so it can be crafted.
CraftingComponent.AddRecipe(tableType: typeof(MedievalStallObject), recipeFamily: this); // NOTE: The table must be the object instance!
}
/// <summary>Hook for other mods to customize RecipeFamily before initialization.</summary>
partial void ModsPreInitialize();
/// <summary>Hook for other mods to customize RecipeFamily after initialization, but before registration. You can change skill requirements here.</summary>
partial void ModsPostInitialize();
}
#endregion
}

Line 58: This line here adds this recipe to the MedievalStallObject just created.