Merge remote-tracking branch 'origin/feat/inport-props' into feat/craft-discovery
# Conflicts: # Assets/External/Animated PBR Chest Demo/Materials/WoodChest.mat # Packages/com.distantlands.cozy.core/Content/Integration/Import for BiRP.unitypackage.meta # Packages/com.distantlands.cozy.core/Content/Integration/Import for HDRP.unitypackage.meta # Packages/com.distantlands.cozy.core/Content/Integration/Import for URP.unitypackage.meta
This commit is contained in:
@@ -10,11 +10,13 @@ namespace Ashwild.EditorTools
|
||||
/// <summary>
|
||||
/// Editor-only factory that creates ItemData assets and, on demand, builds the world pickup
|
||||
/// prefab (Pickable + collider on the Pickable layer) and the in-hand prefab (ToolBehaviour +
|
||||
/// HeldItemOffset on the Tools layer) by wrapping a chosen source object — a model (FBX) or an
|
||||
/// existing prefab. The source is nested as a child so the designer's authored model stays intact
|
||||
/// and editable, while the generated root carries the gameplay components and a collider auto-fit
|
||||
/// to the source's renderers. Every reference is wired back onto the ItemData. Follows §3 of the
|
||||
/// project rules: world pickups are plain WorldObjects (registry-synced), never NetworkObjects.
|
||||
/// HeldItemOffset on the Tools layer) as a Prefab Variant of a chosen source prefab. The designer
|
||||
/// authors one base prefab with its meshes and materials set up (the raw FBX comes in untextured),
|
||||
/// hands it to the generator, and each generated prefab becomes a variant that carries the gameplay
|
||||
/// components as overrides on its own root — so re-texturing the base propagates to both variants.
|
||||
/// A non-prefab source falls back to a plain duplicate. Every reference is wired back onto the
|
||||
/// ItemData. Follows §3 of the project rules: world pickups are plain WorldObjects (registry-synced),
|
||||
/// never NetworkObjects.
|
||||
/// </summary>
|
||||
public static class ItemAssetFactory
|
||||
{
|
||||
@@ -24,6 +26,9 @@ namespace Ashwild.EditorTools
|
||||
private const string WorldPrefabFolder = "Assets/GAME/Prefabs/Pickable";
|
||||
private const string HandPrefabFolder = "Assets/GAME/Prefabs/Tools";
|
||||
|
||||
private const string WorldPrefabSuffix = "_Pickable";
|
||||
private const string HandPrefabSuffix = "_Tools";
|
||||
|
||||
private const string PickableLayerName = "Pickable";
|
||||
private const string ToolsLayerName = "Tools";
|
||||
private const string HarvestableLayerName = "Harvestable";
|
||||
@@ -65,19 +70,20 @@ namespace Ashwild.EditorTools
|
||||
#region World Prefab
|
||||
|
||||
/// <summary>
|
||||
/// Builds the world pickup prefab for an item by wrapping the source object: a root on the
|
||||
/// Pickable layer carries the source as a child, an auto-fitted non-trigger BoxCollider (so the
|
||||
/// interactor ray — which reads the Pickable off the hit collider's own GameObject — has a
|
||||
/// target on the root), and the Pickable component wired to this item. The id stays -1; scene
|
||||
/// instances get a baked id later via Tools ▸ Ashwild ▸ Assign World Object IDs. The finished
|
||||
/// prefab is assigned back onto ItemData.worldPrefab. Returns the saved prefab, or null on error.
|
||||
/// Builds the world pickup prefab for an item as a variant of the source prefab: the variant root
|
||||
/// sits on the Pickable layer, gains an auto-fitted non-trigger BoxCollider (so the interactor ray
|
||||
/// — which reads the Pickable off the hit collider's own GameObject — has a target on the root),
|
||||
/// and a Pickable wired to this item. The id stays -1; scene instances get a baked id later via
|
||||
/// Tools ▸ Ashwild ▸ Setup World Object IDs. The finished prefab is assigned back onto
|
||||
/// ItemData.worldPrefab. Returns the saved prefab, or null on error.
|
||||
/// </summary>
|
||||
public static GameObject GenerateWorldPrefab(ItemData item, GameObject source)
|
||||
{
|
||||
if (!ValidateInputs(item, source, "world")) return null;
|
||||
if (!EnsureFolder(WorldPrefabFolder)) return null;
|
||||
|
||||
GameObject root = BuildRoot(item, source, ResolveLayer(PickableLayerName));
|
||||
string prefabName = item.name + WorldPrefabSuffix;
|
||||
GameObject root = InstantiateSourceRoot(source, ResolveLayer(PickableLayerName), prefabName);
|
||||
FitBoxCollider(root);
|
||||
|
||||
Pickable pickable = root.AddComponent<Pickable>();
|
||||
@@ -85,7 +91,7 @@ namespace Ashwild.EditorTools
|
||||
so.FindProperty("itemData").objectReferenceValue = item;
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
return SaveAndAssign(root, WorldPrefabFolder, item, "worldPrefab");
|
||||
return SaveAndAssign(root, WorldPrefabFolder, item, "worldPrefab", prefabName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -93,18 +99,19 @@ namespace Ashwild.EditorTools
|
||||
#region Hand Prefab
|
||||
|
||||
/// <summary>
|
||||
/// Builds the in-hand prefab for a tool/weapon by wrapping the source object: a root on the
|
||||
/// Tools layer carries the source as a child, a ToolBehaviour (harvest ray masked to the
|
||||
/// Harvestable layer) and a HeldItemOffset so it can be posed in the holder. No collider —
|
||||
/// held items carry no physics. The prefab is assigned back onto ItemData.handPrefab.
|
||||
/// Returns the prefab, or null on error.
|
||||
/// Builds the in-hand prefab for a tool/weapon as a variant of the source prefab: the variant
|
||||
/// root sits on the Tools layer and gains a ToolBehaviour (harvest ray masked to the Harvestable
|
||||
/// layer) and a HeldItemOffset so it can be posed in the holder. No collider — held items carry
|
||||
/// no physics. The prefab is assigned back onto ItemData.handPrefab. Returns the prefab, or null
|
||||
/// on error.
|
||||
/// </summary>
|
||||
public static GameObject GenerateHandPrefab(ItemData item, GameObject source)
|
||||
{
|
||||
if (!ValidateInputs(item, source, "hand")) return null;
|
||||
if (!EnsureFolder(HandPrefabFolder)) return null;
|
||||
|
||||
GameObject root = BuildRoot(item, source, ResolveLayer(ToolsLayerName));
|
||||
string prefabName = item.name + HandPrefabSuffix;
|
||||
GameObject root = InstantiateSourceRoot(source, ResolveLayer(ToolsLayerName), prefabName);
|
||||
|
||||
ToolBehaviour tool = root.AddComponent<ToolBehaviour>();
|
||||
SerializedObject so = new SerializedObject(tool);
|
||||
@@ -113,7 +120,7 @@ namespace Ashwild.EditorTools
|
||||
|
||||
root.AddComponent<HeldItemOffset>();
|
||||
|
||||
return SaveAndAssign(root, HandPrefabFolder, item, "handPrefab");
|
||||
return SaveAndAssign(root, HandPrefabFolder, item, "handPrefab", prefabName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -139,18 +146,20 @@ namespace Ashwild.EditorTools
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the generated root named after the item, on the given layer, with the source object
|
||||
/// (model or prefab) nested as a child at the origin so its authored transform is preserved as
|
||||
/// a prefab link rather than flattened.
|
||||
/// Instantiates the source prefab itself as the generated root — keeping the prefab connection so
|
||||
/// SaveAndAssign turns it into a variant — then applies the target name and layer as variant
|
||||
/// overrides. A non-prefab source falls back to a plain (unlinked) copy, which SaveAndAssign then
|
||||
/// saves as a regular prefab rather than a variant.
|
||||
/// </summary>
|
||||
private static GameObject BuildRoot(ItemData item, GameObject source, int layer)
|
||||
private static GameObject InstantiateSourceRoot(GameObject source, int layer, string rootName)
|
||||
{
|
||||
GameObject root = new GameObject(item.name) { layer = layer };
|
||||
GameObject root = PrefabUtility.InstantiatePrefab(source) as GameObject;
|
||||
if (root == null) root = Object.Instantiate(source);
|
||||
|
||||
GameObject visual = (GameObject)PrefabUtility.InstantiatePrefab(source);
|
||||
if (visual == null) visual = Object.Instantiate(source);
|
||||
visual.transform.SetParent(root.transform, false);
|
||||
visual.transform.localPosition = Vector3.zero;
|
||||
root.name = rootName;
|
||||
root.layer = layer;
|
||||
root.transform.position = Vector3.zero;
|
||||
root.transform.rotation = Quaternion.identity;
|
||||
|
||||
return root;
|
||||
}
|
||||
@@ -179,12 +188,13 @@ namespace Ashwild.EditorTools
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a built GameObject as a prefab under a unique path, destroys the scene instance,
|
||||
/// wires the saved prefab onto the given ItemData field, and refreshes the asset database.
|
||||
/// Saves a built GameObject as a prefab under a unique path (named with the type-specific suffix
|
||||
/// so pickables and hand tools stay distinguishable), destroys the scene instance, wires the
|
||||
/// saved prefab onto the given ItemData field, and refreshes the asset database.
|
||||
/// </summary>
|
||||
private static GameObject SaveAndAssign(GameObject root, string folder, ItemData item, string itemField)
|
||||
private static GameObject SaveAndAssign(GameObject root, string folder, ItemData item, string itemField, string prefabName)
|
||||
{
|
||||
string prefabPath = AssetDatabase.GenerateUniqueAssetPath($"{folder}/{item.name}.prefab");
|
||||
string prefabPath = AssetDatabase.GenerateUniqueAssetPath($"{folder}/{prefabName}.prefab");
|
||||
GameObject prefab = PrefabUtility.SaveAsPrefabAsset(root, prefabPath);
|
||||
Object.DestroyImmediate(root);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user