134 lines
5.6 KiB
C#
134 lines
5.6 KiB
C#
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
using UnityEditor.SceneManagement;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
// Project namespaces
|
|
using MegaKoop.Steam; // SteamManager, SteamLobbyService
|
|
using MegaKoop.Game.Networking; // SteamCoopNetworkManager, SteamP2PTransport, LobbyGameSceneCoordinator
|
|
|
|
public static class CharacterSceneSetupGenerator
|
|
{
|
|
private const string WizardPrefabPath = "Assets/Game/Hero/Wizard.prefab";
|
|
|
|
[MenuItem("Tools/MegaKoop/Setup Character Scene Objects", priority = 1000)]
|
|
public static void SetupCharacterScene()
|
|
{
|
|
var scene = SceneManager.GetActiveScene();
|
|
if (!scene.IsValid())
|
|
{
|
|
EditorUtility.DisplayDialog("Character Scene Setup", "No valid scene is open. Please open your CharacterScene and run again.", "OK");
|
|
return;
|
|
}
|
|
|
|
Undo.IncrementCurrentGroup();
|
|
int group = Undo.GetCurrentGroup();
|
|
|
|
// 1) Ensure SteamServices root and required components
|
|
var servicesRoot = GameObject.Find("SteamServices");
|
|
if (servicesRoot == null)
|
|
{
|
|
servicesRoot = new GameObject("SteamServices");
|
|
Undo.RegisterCreatedObjectUndo(servicesRoot, "Create SteamServices");
|
|
}
|
|
|
|
EnsureComponent<SteamManager>(servicesRoot, "Add SteamManager");
|
|
var lobby = EnsureComponent<SteamLobbyService>(servicesRoot, "Add SteamLobbyService");
|
|
var coop = EnsureComponent<SteamCoopNetworkManager>(servicesRoot, "Add SteamCoopNetworkManager");
|
|
EnsureComponent<SteamP2PTransport>(servicesRoot, "Add SteamP2PTransport");
|
|
var coordinator = EnsureComponent<LobbyGameSceneCoordinator>(servicesRoot, "Add LobbyGameSceneCoordinator");
|
|
|
|
// Keep servicesRoot persistent across scenes to match runtime behavior
|
|
if (!Application.isPlaying)
|
|
{
|
|
// Editor-time: mark as DontSaveInBuild is not needed; users expect this object in scene.
|
|
// At runtime, code calls DontDestroyOnLoad itself.
|
|
}
|
|
|
|
// 2) Ensure Wizard template exists in scene root
|
|
var wizardInScene = GameObject.Find("Wizard");
|
|
if (wizardInScene == null)
|
|
{
|
|
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(WizardPrefabPath);
|
|
if (prefab != null)
|
|
{
|
|
var instantiated = PrefabUtility.InstantiatePrefab(prefab, scene) as GameObject;
|
|
if (instantiated != null)
|
|
{
|
|
Undo.RegisterCreatedObjectUndo(instantiated, "Instantiate Wizard Template");
|
|
instantiated.name = "Wizard"; // Ensure exact name for coordinator lookup
|
|
instantiated.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Fallback: create a simple placeholder
|
|
var placeholder = GameObject.CreatePrimitive(PrimitiveType.Capsule);
|
|
Undo.RegisterCreatedObjectUndo(placeholder, "Create Wizard Placeholder");
|
|
placeholder.name = "Wizard";
|
|
placeholder.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);
|
|
// Controller components are optional for template; coordinator will add bridges on clones.
|
|
placeholder.AddComponent<CharacterController>();
|
|
placeholder.AddComponent<MegaKoop.Game.ThirdPersonCharacterController>();
|
|
}
|
|
}
|
|
|
|
// 3) Optional: ensure a basic ground so CharacterController can stand
|
|
if (GameObject.Find("Ground") == null)
|
|
{
|
|
var ground = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
|
Undo.RegisterCreatedObjectUndo(ground, "Create Ground");
|
|
ground.name = "Ground";
|
|
ground.transform.position = Vector3.zero;
|
|
ground.transform.localScale = Vector3.one * 2f;
|
|
}
|
|
|
|
// 4) Optional: ensure there is at least one light
|
|
if (Object.FindObjectOfType<Light>() == null)
|
|
{
|
|
var lightGO = new GameObject("Directional Light");
|
|
Undo.RegisterCreatedObjectUndo(lightGO, "Create Directional Light");
|
|
var light = lightGO.AddComponent<Light>();
|
|
light.type = LightType.Directional;
|
|
light.intensity = 1.1f;
|
|
lightGO.transform.rotation = Quaternion.Euler(50f, -30f, 0f);
|
|
}
|
|
|
|
// 5) Hint coordinator to use current scene name if it differs
|
|
if (coordinator != null)
|
|
{
|
|
// If you want the coordinator to target this scene specifically, uncomment the next line:
|
|
// SetPrivateField(coordinator, "characterSceneName", scene.name);
|
|
}
|
|
|
|
EditorSceneManager.MarkSceneDirty(scene);
|
|
Undo.CollapseUndoOperations(group);
|
|
|
|
EditorUtility.DisplayDialog("Character Scene Setup", "Character scene objects have been set up successfully.", "OK");
|
|
}
|
|
|
|
private static T EnsureComponent<T>(GameObject go, string undoName) where T : Component
|
|
{
|
|
var c = go.GetComponent<T>();
|
|
if (c == null)
|
|
{
|
|
c = Undo.AddComponent<T>(go);
|
|
}
|
|
return c;
|
|
}
|
|
|
|
// Example helper if you later want to set private serialized fields via reflection
|
|
private static void SetPrivateField(object target, string fieldName, object value)
|
|
{
|
|
var t = target.GetType();
|
|
var f = t.GetField(fieldName, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
|
|
if (f != null)
|
|
{
|
|
f.SetValue(target, value);
|
|
EditorUtility.SetDirty((Object)target);
|
|
}
|
|
}
|
|
}
|
|
#endif
|