Add prototype gameplay loop with character/battlefield assets and server game APIs.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Imports the authored battlefield component FBX/XPbr files and creates one
|
||||
/// reusable prefab per component. Ground is built separately so its collider
|
||||
/// and read/write mesh settings cannot be confused with decoration assets.
|
||||
/// </summary>
|
||||
public static class BuildBattlefieldAssets
|
||||
{
|
||||
const string Root = "Assets/Bundles/Scenes/Prototype/Battlefield/A/Components";
|
||||
const string GroundRoot = "Assets/Bundles/Scenes/Prototype/Battlefield/A/Ground";
|
||||
const string GroundPrefab = "Assets/Bundles/Scenes/Prototype/Battlefield/GreenfieldGround.prefab";
|
||||
const string XpbrShader = "Test/XPbr";
|
||||
|
||||
static readonly string[] Parts = { "tree", "rock", "bridge", "sign", "shrub" };
|
||||
|
||||
public static string BuildComponents()
|
||||
{
|
||||
AssetDatabase.Refresh();
|
||||
var reports = new List<string>();
|
||||
foreach (var type in Parts) reports.Add(BuildPart(type));
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
return string.Join(" | ", reports);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the independently authored ground asset once Hunyuan has produced
|
||||
/// Ground/ground.fbx and its XPbr textures. The ground keeps a readable mesh
|
||||
/// so the authored prefab can carry a non-convex MeshCollider.
|
||||
/// </summary>
|
||||
public static string BuildGround()
|
||||
{
|
||||
AssetDatabase.Refresh();
|
||||
string fbxPath = GroundRoot + "/ground.fbx";
|
||||
if (!File.Exists(fbxPath)) return "ground: missing fbx";
|
||||
string basePath = GroundRoot + "/ground_base.png";
|
||||
string mixPath = GroundRoot + "/ground_mix.png";
|
||||
ConfigureTexture(basePath, true, true);
|
||||
ConfigureTexture(mixPath, false, false);
|
||||
var importer = AssetImporter.GetAtPath(fbxPath) as ModelImporter;
|
||||
if (importer != null)
|
||||
{
|
||||
importer.globalScale = 1f;
|
||||
importer.useFileScale = false;
|
||||
importer.bakeAxisConversion = true;
|
||||
importer.materialImportMode = ModelImporterMaterialImportMode.ImportViaMaterialDescription;
|
||||
importer.meshCompression = ModelImporterMeshCompression.Medium;
|
||||
importer.isReadable = true;
|
||||
importer.addCollider = false;
|
||||
importer.SaveAndReimport();
|
||||
}
|
||||
var mat = GetOrCreateMaterial(GroundRoot + "/ground.mat", "ground", basePath, mixPath);
|
||||
var model = AssetDatabase.LoadAssetAtPath<GameObject>(fbxPath);
|
||||
if (model == null) return "ground: fbx not loaded";
|
||||
var root = new GameObject("GreenfieldGround");
|
||||
try
|
||||
{
|
||||
var instance = (GameObject)PrefabUtility.InstantiatePrefab(model);
|
||||
instance.name = "GroundMesh";
|
||||
instance.transform.SetParent(root.transform, false);
|
||||
PrefabUtility.UnpackPrefabInstance(instance, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
|
||||
foreach (var renderer in instance.GetComponentsInChildren<Renderer>(true)) renderer.sharedMaterial = mat;
|
||||
foreach (var filter in instance.GetComponentsInChildren<MeshFilter>(true))
|
||||
{
|
||||
if (filter.sharedMesh == null) continue;
|
||||
var collider = filter.gameObject.GetComponent<MeshCollider>();
|
||||
if (collider == null) collider = filter.gameObject.AddComponent<MeshCollider>();
|
||||
collider.convex = false;
|
||||
collider.sharedMesh = filter.sharedMesh;
|
||||
}
|
||||
PrefabUtility.SaveAsPrefabAsset(root, GroundPrefab);
|
||||
}
|
||||
finally { UnityEngine.Object.DestroyImmediate(root); }
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
return "ground: " + GroundPrefab;
|
||||
}
|
||||
|
||||
public static string BuildAll()
|
||||
{
|
||||
var components = BuildComponents();
|
||||
var ground = BuildGround();
|
||||
return components + " | " + ground;
|
||||
}
|
||||
|
||||
static string BuildPart(string type)
|
||||
{
|
||||
string dir = Root + "/" + type;
|
||||
string fbxPath = dir + "/" + type + ".fbx";
|
||||
string matPath = dir + "/" + type + ".mat";
|
||||
string basePath = dir + "/" + type + "_base.png";
|
||||
string mixPath = dir + "/" + type + "_mix.png";
|
||||
string prefabPath = dir + "/" + type + ".prefab";
|
||||
if (!File.Exists(fbxPath)) return type + ": missing fbx";
|
||||
|
||||
ConfigureTexture(basePath, true, true);
|
||||
ConfigureTexture(mixPath, false, false);
|
||||
var importer = AssetImporter.GetAtPath(fbxPath) as ModelImporter;
|
||||
if (importer != null)
|
||||
{
|
||||
importer.globalScale = 1f;
|
||||
importer.useFileScale = false;
|
||||
importer.bakeAxisConversion = true;
|
||||
importer.materialImportMode = ModelImporterMaterialImportMode.ImportViaMaterialDescription;
|
||||
importer.meshCompression = ModelImporterMeshCompression.Medium;
|
||||
importer.isReadable = false;
|
||||
importer.addCollider = false;
|
||||
importer.SaveAndReimport();
|
||||
}
|
||||
|
||||
var mat = GetOrCreateMaterial(matPath, type, basePath, mixPath);
|
||||
|
||||
var model = AssetDatabase.LoadAssetAtPath<GameObject>(fbxPath);
|
||||
if (model == null) return type + ": fbx not loaded";
|
||||
var instance = (GameObject)PrefabUtility.InstantiatePrefab(model);
|
||||
instance.name = type;
|
||||
foreach (var renderer in instance.GetComponentsInChildren<Renderer>()) renderer.sharedMaterial = mat;
|
||||
instance.transform.localPosition = Vector3.zero;
|
||||
instance.transform.localRotation = Quaternion.identity;
|
||||
instance.transform.localScale = Vector3.one;
|
||||
PrefabUtility.SaveAsPrefabAsset(instance, prefabPath);
|
||||
UnityEngine.Object.DestroyImmediate(instance);
|
||||
return type + ": " + prefabPath;
|
||||
}
|
||||
|
||||
static Material GetOrCreateMaterial(string matPath, string name, string basePath, string mixPath)
|
||||
{
|
||||
var baseMap = AssetDatabase.LoadAssetAtPath<Texture2D>(basePath);
|
||||
var mixMap = AssetDatabase.LoadAssetAtPath<Texture2D>(mixPath);
|
||||
var shader = Shader.Find(XpbrShader) ?? Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard");
|
||||
var mat = AssetDatabase.LoadAssetAtPath<Material>(matPath);
|
||||
if (mat == null)
|
||||
{
|
||||
mat = new Material(shader) { name = name };
|
||||
AssetDatabase.CreateAsset(mat, matPath);
|
||||
}
|
||||
else mat.shader = shader;
|
||||
if (mat.HasProperty("_MainTex")) mat.SetTexture("_MainTex", baseMap);
|
||||
if (mat.HasProperty("_MixTex")) mat.SetTexture("_MixTex", mixMap);
|
||||
if (mat.HasProperty("_BaseColor")) mat.SetColor("_BaseColor", Color.white);
|
||||
if (mat.HasProperty("_Metallic")) mat.SetFloat("_Metallic", 1f);
|
||||
if (mat.HasProperty("_Roughness")) mat.SetFloat("_Roughness", 1f);
|
||||
if (mat.HasProperty("_AO")) mat.SetFloat("_AO", 1f);
|
||||
EditorUtility.SetDirty(mat);
|
||||
return mat;
|
||||
}
|
||||
|
||||
static void ConfigureTexture(string path, bool srgb, bool alpha)
|
||||
{
|
||||
if (!File.Exists(path)) return;
|
||||
var importer = AssetImporter.GetAtPath(path) as TextureImporter;
|
||||
if (importer == null) return;
|
||||
importer.textureType = TextureImporterType.Default;
|
||||
importer.sRGBTexture = srgb;
|
||||
importer.mipmapEnabled = true;
|
||||
importer.alphaIsTransparency = alpha;
|
||||
importer.SaveAndReimport();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user