Added Furnance and smelting
This commit is contained in:
@@ -0,0 +1,303 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Unity.Netcode;
|
||||
using Unity.Netcode.Components;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public static class FurnacePipelinePrototypeSetup
|
||||
{
|
||||
private const string ItemDataFolder = "Assets/CONTENT/Game/Data/Items";
|
||||
private const string RecipeDataFolder = "Assets/CONTENT/Game/Data/Recipes";
|
||||
private const string ItemPrefabFolder = "Assets/CONTENT/Game/Prefabs/Items/FurnacePrototype";
|
||||
private const string WorkstationPrefabFolder = "Assets/CONTENT/Game/Prefabs/Workstations";
|
||||
private const string NetworkPrefabsPath = "Assets/DefaultNetworkPrefabs.asset";
|
||||
|
||||
[MenuItem("FORT-BO/Prototypes/Create Furnace Pipeline")]
|
||||
public static void CreatePrototype()
|
||||
{
|
||||
EnsureFolder(ItemDataFolder);
|
||||
EnsureFolder(RecipeDataFolder);
|
||||
EnsureFolder(ItemPrefabFolder);
|
||||
EnsureFolder(WorkstationPrefabFolder);
|
||||
|
||||
ItemDefinition scrapDefinition = GetOrCreateAsset<ItemDefinition>(
|
||||
$"{ItemDataFolder}/Scrap.asset");
|
||||
ItemDefinition plateDefinition = GetOrCreateAsset<ItemDefinition>(
|
||||
$"{ItemDataFolder}/MetalPlate.asset");
|
||||
ItemDefinition rodDefinition = GetOrCreateAsset<ItemDefinition>(
|
||||
$"{ItemDataFolder}/MetalRod.asset");
|
||||
|
||||
ConfigureItemDefinition(scrapDefinition, "scrap", "Scrap", ItemCategory.Scrap);
|
||||
ConfigureItemDefinition(plateDefinition, "metal_plate", "Metal Plate", ItemCategory.SmeltedMaterial);
|
||||
ConfigureItemDefinition(rodDefinition, "metal_rod", "Metal Rod", ItemCategory.SmeltedMaterial);
|
||||
|
||||
GameObject scrapPrefab = CreateNetworkItemPrefab(
|
||||
$"{ItemPrefabFolder}/Scrap.prefab",
|
||||
"Scrap",
|
||||
scrapDefinition,
|
||||
new Vector3(0.55f, 0.4f, 0.5f),
|
||||
4f,
|
||||
25f);
|
||||
GameObject platePrefab = CreateNetworkItemPrefab(
|
||||
$"{ItemPrefabFolder}/MetalPlate.prefab",
|
||||
"MetalPlate",
|
||||
plateDefinition,
|
||||
new Vector3(0.7f, 0.12f, 0.45f),
|
||||
2f,
|
||||
0f);
|
||||
GameObject rodPrefab = CreateNetworkItemPrefab(
|
||||
$"{ItemPrefabFolder}/MetalRod.prefab",
|
||||
"MetalRod",
|
||||
rodDefinition,
|
||||
new Vector3(0.18f, 0.18f, 0.9f),
|
||||
1.5f,
|
||||
0f);
|
||||
|
||||
SetObjectReference(scrapDefinition, "worldPrefab", scrapPrefab.GetComponent<NetworkObject>());
|
||||
SetObjectReference(plateDefinition, "worldPrefab", platePrefab.GetComponent<NetworkObject>());
|
||||
SetObjectReference(rodDefinition, "worldPrefab", rodPrefab.GetComponent<NetworkObject>());
|
||||
|
||||
ItemCatalog catalog = GetOrCreateAsset<ItemCatalog>($"{ItemDataFolder}/ItemCatalog.asset");
|
||||
SetObjectReferenceList(catalog, "items", new Object[]
|
||||
{
|
||||
scrapDefinition,
|
||||
plateDefinition,
|
||||
rodDefinition
|
||||
});
|
||||
|
||||
SmeltingRecipe plateRecipe = GetOrCreateAsset<SmeltingRecipe>(
|
||||
$"{RecipeDataFolder}/SmeltMetalPlate.asset");
|
||||
ConfigureRecipe(plateRecipe, "metal_plate", "Metal Plate", plateDefinition, 25f, 3f);
|
||||
|
||||
SmeltingRecipe rodRecipe = GetOrCreateAsset<SmeltingRecipe>(
|
||||
$"{RecipeDataFolder}/SmeltMetalRod.asset");
|
||||
ConfigureRecipe(rodRecipe, "metal_rod", "Metal Rod", rodDefinition, 20f, 2.5f);
|
||||
|
||||
GameObject furnacePrefab = CreateFurnacePrefab(
|
||||
$"{WorkstationPrefabFolder}/PrototypeFurnace.prefab",
|
||||
plateRecipe,
|
||||
rodRecipe);
|
||||
|
||||
RegisterNetworkPrefabs(scrapPrefab, platePrefab, rodPrefab, furnacePrefab);
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
Selection.activeObject = furnacePrefab;
|
||||
|
||||
Debug.Log("Furnace pipeline prototype created. Place PrototypeFurnace.prefab in Factory.");
|
||||
}
|
||||
|
||||
private static GameObject CreateNetworkItemPrefab(
|
||||
string path,
|
||||
string objectName,
|
||||
ItemDefinition definition,
|
||||
Vector3 scale,
|
||||
float mass,
|
||||
float metalAmount)
|
||||
{
|
||||
GameObject root = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
root.name = objectName;
|
||||
root.transform.localScale = scale;
|
||||
|
||||
root.AddComponent<NetworkObject>();
|
||||
NetworkTransform networkTransform = root.AddComponent<NetworkTransform>();
|
||||
networkTransform.AuthorityMode = NetworkTransform.AuthorityModes.Server;
|
||||
networkTransform.UseUnreliableDeltas = true;
|
||||
|
||||
Rigidbody body = root.AddComponent<Rigidbody>();
|
||||
body.mass = mass;
|
||||
body.interpolation = RigidbodyInterpolation.Interpolate;
|
||||
body.collisionDetectionMode = CollisionDetectionMode.Continuous;
|
||||
|
||||
NetworkRigidbody networkRigidbody = root.AddComponent<NetworkRigidbody>();
|
||||
networkRigidbody.UseRigidBodyForMotion = true;
|
||||
|
||||
NetworkCarryableInteractable carryable = root.AddComponent<NetworkCarryableInteractable>();
|
||||
SetVector3(carryable, "carryOffset", new Vector3(0f, -0.3f, 1.25f));
|
||||
|
||||
NetworkItem item = root.AddComponent<NetworkItem>();
|
||||
SetObjectReference(item, "definition", definition);
|
||||
|
||||
if (metalAmount > 0f)
|
||||
{
|
||||
FurnaceMetalSource source = root.AddComponent<FurnaceMetalSource>();
|
||||
SetFloat(source, "metalAmount", metalAmount);
|
||||
}
|
||||
|
||||
GameObject prefab = PrefabUtility.SaveAsPrefabAsset(root, path);
|
||||
Object.DestroyImmediate(root);
|
||||
return prefab;
|
||||
}
|
||||
|
||||
private static GameObject CreateFurnacePrefab(
|
||||
string path,
|
||||
SmeltingRecipe plateRecipe,
|
||||
SmeltingRecipe rodRecipe)
|
||||
{
|
||||
GameObject root = new("PrototypeFurnace");
|
||||
root.AddComponent<NetworkObject>();
|
||||
FurnaceController controller = root.AddComponent<FurnaceController>();
|
||||
|
||||
GameObject body = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
body.name = "Body";
|
||||
body.transform.SetParent(root.transform, false);
|
||||
body.transform.localPosition = new Vector3(0f, 0.8f, 0f);
|
||||
body.transform.localScale = new Vector3(2.2f, 1.6f, 2f);
|
||||
|
||||
GameObject inputTrigger = new("ScrapReceiver");
|
||||
inputTrigger.transform.SetParent(root.transform, false);
|
||||
inputTrigger.transform.localPosition = new Vector3(0f, 1.7f, 0f);
|
||||
BoxCollider trigger = inputTrigger.AddComponent<BoxCollider>();
|
||||
trigger.isTrigger = true;
|
||||
trigger.size = new Vector3(1.4f, 0.8f, 1.4f);
|
||||
FurnaceScrapReceiver receiver = inputTrigger.AddComponent<FurnaceScrapReceiver>();
|
||||
SetObjectReference(receiver, "furnace", controller);
|
||||
|
||||
GameObject outputPoint = new("OutputPoint");
|
||||
outputPoint.transform.SetParent(root.transform, false);
|
||||
outputPoint.transform.localPosition = new Vector3(0f, 0.45f, 1.5f);
|
||||
|
||||
GameObject emptyPoint = new("MetalEmptyPoint");
|
||||
emptyPoint.transform.SetParent(root.transform, false);
|
||||
emptyPoint.transform.localPosition = new Vector3(0f, 0.25f, 0f);
|
||||
|
||||
GameObject fullPoint = new("MetalFullPoint");
|
||||
fullPoint.transform.SetParent(root.transform, false);
|
||||
fullPoint.transform.localPosition = new Vector3(0f, 1.25f, 0f);
|
||||
|
||||
GameObject metalVisual = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
metalVisual.name = "MoltenMetalVisual";
|
||||
metalVisual.transform.SetParent(root.transform, false);
|
||||
metalVisual.transform.localPosition = emptyPoint.transform.localPosition;
|
||||
metalVisual.transform.localScale = new Vector3(1.3f, 0.12f, 1.1f);
|
||||
Object.DestroyImmediate(metalVisual.GetComponent<Collider>());
|
||||
|
||||
FurnaceMetalLevelView levelView = metalVisual.AddComponent<FurnaceMetalLevelView>();
|
||||
SetObjectReference(levelView, "furnace", controller);
|
||||
SetObjectReference(levelView, "metalVisual", metalVisual.transform);
|
||||
SetObjectReference(levelView, "emptyLocalPosition", emptyPoint.transform);
|
||||
SetObjectReference(levelView, "fullLocalPosition", fullPoint.transform);
|
||||
|
||||
GameObject panelAnchor = new("WorldPanelAnchor");
|
||||
panelAnchor.transform.SetParent(root.transform, false);
|
||||
panelAnchor.transform.localPosition = new Vector3(1.2f, 1.2f, 1.05f);
|
||||
|
||||
SetString(controller, "workstationName", "Prototype Furnace");
|
||||
SetFloat(controller, "metalCapacity", 100f);
|
||||
SetObjectReference(controller, "outputPoint", outputPoint.transform);
|
||||
SetObjectReferenceList(controller, "recipes", new Object[] { plateRecipe, rodRecipe });
|
||||
|
||||
GameObject prefab = PrefabUtility.SaveAsPrefabAsset(root, path);
|
||||
Object.DestroyImmediate(root);
|
||||
return prefab;
|
||||
}
|
||||
|
||||
private static void ConfigureItemDefinition(
|
||||
ItemDefinition definition,
|
||||
string itemId,
|
||||
string displayName,
|
||||
ItemCategory category)
|
||||
{
|
||||
SetString(definition, "itemId", itemId);
|
||||
SetString(definition, "displayName", displayName);
|
||||
SetInt(definition, "category", (int)category);
|
||||
}
|
||||
|
||||
private static void ConfigureRecipe(
|
||||
SmeltingRecipe recipe,
|
||||
string recipeId,
|
||||
string displayName,
|
||||
ItemDefinition output,
|
||||
float metalCost,
|
||||
float duration)
|
||||
{
|
||||
SetString(recipe, "recipeId", recipeId);
|
||||
SetString(recipe, "displayName", displayName);
|
||||
SetObjectReference(recipe, "outputItem", output);
|
||||
SetInt(recipe, "outputAmount", 1);
|
||||
SetFloat(recipe, "metalCost", metalCost);
|
||||
SetFloat(recipe, "processingDuration", duration);
|
||||
}
|
||||
|
||||
private static void RegisterNetworkPrefabs(params GameObject[] prefabs)
|
||||
{
|
||||
NetworkPrefabsList list = AssetDatabase.LoadAssetAtPath<NetworkPrefabsList>(NetworkPrefabsPath);
|
||||
if (list == null)
|
||||
throw new FileNotFoundException("Default network prefab list was not found.", NetworkPrefabsPath);
|
||||
|
||||
foreach (GameObject prefab in prefabs)
|
||||
{
|
||||
if (prefab != null && !list.Contains(prefab))
|
||||
list.Add(new NetworkPrefab { Prefab = prefab });
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(list);
|
||||
}
|
||||
|
||||
private static T GetOrCreateAsset<T>(string path) where T : ScriptableObject
|
||||
{
|
||||
T asset = AssetDatabase.LoadAssetAtPath<T>(path);
|
||||
if (asset != null)
|
||||
return asset;
|
||||
|
||||
asset = ScriptableObject.CreateInstance<T>();
|
||||
AssetDatabase.CreateAsset(asset, path);
|
||||
return asset;
|
||||
}
|
||||
|
||||
private static void EnsureFolder(string folderPath)
|
||||
{
|
||||
string current = "Assets";
|
||||
string[] segments = folderPath.Split('/');
|
||||
for (int index = 1; index < segments.Length; index++)
|
||||
{
|
||||
string next = $"{current}/{segments[index]}";
|
||||
if (!AssetDatabase.IsValidFolder(next))
|
||||
AssetDatabase.CreateFolder(current, segments[index]);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetString(Object target, string propertyName, string value) =>
|
||||
Edit(target, propertyName, property => property.stringValue = value);
|
||||
|
||||
private static void SetFloat(Object target, string propertyName, float value) =>
|
||||
Edit(target, propertyName, property => property.floatValue = value);
|
||||
|
||||
private static void SetInt(Object target, string propertyName, int value) =>
|
||||
Edit(target, propertyName, property => property.intValue = value);
|
||||
|
||||
private static void SetVector3(Object target, string propertyName, Vector3 value) =>
|
||||
Edit(target, propertyName, property => property.vector3Value = value);
|
||||
|
||||
private static void SetObjectReference(Object target, string propertyName, Object value) =>
|
||||
Edit(target, propertyName, property => property.objectReferenceValue = value);
|
||||
|
||||
private static void SetObjectReferenceList(
|
||||
Object target,
|
||||
string propertyName,
|
||||
IReadOnlyList<Object> values)
|
||||
{
|
||||
SerializedObject serializedObject = new(target);
|
||||
SerializedProperty property = serializedObject.FindProperty(propertyName);
|
||||
property.arraySize = values.Count;
|
||||
for (int index = 0; index < values.Count; index++)
|
||||
property.GetArrayElementAtIndex(index).objectReferenceValue = values[index];
|
||||
serializedObject.ApplyModifiedPropertiesWithoutUndo();
|
||||
EditorUtility.SetDirty(target);
|
||||
}
|
||||
|
||||
private static void Edit(
|
||||
Object target,
|
||||
string propertyName,
|
||||
System.Action<SerializedProperty> edit)
|
||||
{
|
||||
SerializedObject serializedObject = new(target);
|
||||
SerializedProperty property = serializedObject.FindProperty(propertyName);
|
||||
if (property == null)
|
||||
throw new System.MissingFieldException(target.GetType().Name, propertyName);
|
||||
edit(property);
|
||||
serializedObject.ApplyModifiedPropertiesWithoutUndo();
|
||||
EditorUtility.SetDirty(target);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 29fefdfbc459d664e91002f5a2faa978
|
||||
Reference in New Issue
Block a user