Fixed
This commit is contained in:
@@ -0,0 +1,458 @@
|
||||
using TMPro;
|
||||
using Unity.Netcode;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
|
||||
public static class CannonPrototypeSetup
|
||||
{
|
||||
private const string DataFolder = "Assets/CONTENT/Game/Data/Cannon";
|
||||
private const string CannonConfigPath = DataFolder + "/CannonConfig.asset";
|
||||
private const string CannonShockwavePath = DataFolder + "/CannonShockwave.asset";
|
||||
private const string RocketShockwavePath = DataFolder + "/RocketImpactShockwave.asset";
|
||||
private const string PlayerPrefabPath =
|
||||
"Assets/CONTENT/Friendslop/Prefabs/NetworkPlayer.prefab";
|
||||
private const string RocketPrefabPath =
|
||||
"Assets/CONTENT/Game/Prefabs/Items/Ready-Rocket-Standart.prefab";
|
||||
private const string StandardRocketDefinitionPath =
|
||||
"Assets/CONTENT/Game/Data/Items/Rocket-Ready/Ready-Rocket-Standart.asset";
|
||||
private const string LeverPrefabPath =
|
||||
"Assets/CONTENT/Game/Prefabs/Interaction/PhysicalLever.prefab";
|
||||
|
||||
[MenuItem("FORT-BO/Cannon/Configure Network Prototype")]
|
||||
public static void ConfigureNetworkPrototype()
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Debug.LogWarning("Stop Play Mode before configuring the cannon prototype.");
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureDataFolder();
|
||||
CannonConfig config = GetOrCreateCannonConfig();
|
||||
ShockwaveProfile cannonShockwave = GetOrCreateProfile(
|
||||
CannonShockwavePath,
|
||||
new ShockwaveZone
|
||||
{
|
||||
Radius = 8f,
|
||||
PlayerImpulse = 12f,
|
||||
RigidbodyImpulse = 18f,
|
||||
UpwardBias = 0.35f,
|
||||
CameraShakeAmplitude = 0.22f,
|
||||
CameraShakeDuration = 0.9f,
|
||||
CameraShakeFrequency = 28f
|
||||
},
|
||||
new ShockwaveZone
|
||||
{
|
||||
Radius = 18f,
|
||||
PlayerImpulse = 5f,
|
||||
RigidbodyImpulse = 8f,
|
||||
UpwardBias = 0.25f,
|
||||
CameraShakeAmplitude = 0.12f,
|
||||
CameraShakeDuration = 0.75f,
|
||||
CameraShakeFrequency = 24f
|
||||
},
|
||||
new ShockwaveZone
|
||||
{
|
||||
Radius = 35f,
|
||||
PlayerImpulse = 0f,
|
||||
RigidbodyImpulse = 1.5f,
|
||||
UpwardBias = 0.1f,
|
||||
CameraShakeAmplitude = 0.055f,
|
||||
CameraShakeDuration = 0.55f,
|
||||
CameraShakeFrequency = 20f
|
||||
});
|
||||
ShockwaveProfile rocketShockwave = GetOrCreateProfile(
|
||||
RocketShockwavePath,
|
||||
new ShockwaveZone
|
||||
{
|
||||
Radius = 4f,
|
||||
PlayerImpulse = 8f,
|
||||
RigidbodyImpulse = 12f,
|
||||
UpwardBias = 0.4f,
|
||||
CameraShakeAmplitude = 0.18f,
|
||||
CameraShakeDuration = 0.7f,
|
||||
CameraShakeFrequency = 27f
|
||||
},
|
||||
new ShockwaveZone
|
||||
{
|
||||
Radius = 8f,
|
||||
PlayerImpulse = 3f,
|
||||
RigidbodyImpulse = 5f,
|
||||
UpwardBias = 0.3f,
|
||||
CameraShakeAmplitude = 0.09f,
|
||||
CameraShakeDuration = 0.55f,
|
||||
CameraShakeFrequency = 23f
|
||||
},
|
||||
new ShockwaveZone
|
||||
{
|
||||
Radius = 14f,
|
||||
PlayerImpulse = 0f,
|
||||
RigidbodyImpulse = 0.5f,
|
||||
UpwardBias = 0.1f,
|
||||
CameraShakeAmplitude = 0.04f,
|
||||
CameraShakeDuration = 0.4f,
|
||||
CameraShakeFrequency = 18f
|
||||
});
|
||||
|
||||
ConfigurePlayerPrefab();
|
||||
ConfigureRocketPrefab(rocketShockwave);
|
||||
ConfigureStandardRocketDefinition();
|
||||
NetworkCannonController cannon = ConfigureCannonScene(config, cannonShockwave);
|
||||
ConfigureMapMarker();
|
||||
|
||||
AssetDatabase.SaveAssets();
|
||||
EditorSceneManager.MarkSceneDirty(cannon.gameObject.scene);
|
||||
EditorSceneManager.SaveOpenScenes();
|
||||
Selection.activeObject = cannon.gameObject;
|
||||
Debug.Log(
|
||||
"[Cannon] Network prototype configured. Insert a ready rocket, " +
|
||||
"set delay with -/+ buttons and pull the fire lever.", cannon);
|
||||
}
|
||||
|
||||
private static CannonConfig GetOrCreateCannonConfig()
|
||||
{
|
||||
CannonConfig config = AssetDatabase.LoadAssetAtPath<CannonConfig>(CannonConfigPath);
|
||||
if (config == null)
|
||||
{
|
||||
config = ScriptableObject.CreateInstance<CannonConfig>();
|
||||
AssetDatabase.CreateAsset(config, CannonConfigPath);
|
||||
}
|
||||
|
||||
SerializedObject serialized = new(config);
|
||||
SetFloat(serialized, "minimumDelay", 0f);
|
||||
SetFloat(serialized, "maximumDelay", 30f);
|
||||
SetFloat(serialized, "defaultDelay", 5f);
|
||||
SetFloat(serialized, "adjustmentStep", 1f);
|
||||
serialized.ApplyModifiedPropertiesWithoutUndo();
|
||||
EditorUtility.SetDirty(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
private static ShockwaveProfile GetOrCreateProfile(
|
||||
string path,
|
||||
params ShockwaveZone[] zones)
|
||||
{
|
||||
ShockwaveProfile profile = AssetDatabase.LoadAssetAtPath<ShockwaveProfile>(path);
|
||||
if (profile == null)
|
||||
{
|
||||
profile = ScriptableObject.CreateInstance<ShockwaveProfile>();
|
||||
AssetDatabase.CreateAsset(profile, path);
|
||||
}
|
||||
|
||||
SerializedObject serialized = new(profile);
|
||||
SerializedProperty array = serialized.FindProperty("zones");
|
||||
array.arraySize = zones.Length;
|
||||
for (int index = 0; index < zones.Length; index++)
|
||||
{
|
||||
SerializedProperty element = array.GetArrayElementAtIndex(index);
|
||||
ShockwaveZone zone = zones[index];
|
||||
element.FindPropertyRelative("Radius").floatValue = zone.Radius;
|
||||
element.FindPropertyRelative("PlayerImpulse").floatValue = zone.PlayerImpulse;
|
||||
element.FindPropertyRelative("RigidbodyImpulse").floatValue = zone.RigidbodyImpulse;
|
||||
element.FindPropertyRelative("UpwardBias").floatValue = zone.UpwardBias;
|
||||
element.FindPropertyRelative("CameraShakeAmplitude").floatValue =
|
||||
zone.CameraShakeAmplitude;
|
||||
element.FindPropertyRelative("CameraShakeDuration").floatValue =
|
||||
zone.CameraShakeDuration;
|
||||
element.FindPropertyRelative("CameraShakeFrequency").floatValue =
|
||||
zone.CameraShakeFrequency;
|
||||
}
|
||||
serialized.ApplyModifiedPropertiesWithoutUndo();
|
||||
EditorUtility.SetDirty(profile);
|
||||
return profile;
|
||||
}
|
||||
|
||||
private static void ConfigurePlayerPrefab()
|
||||
{
|
||||
GameObject root = PrefabUtility.LoadPrefabContents(PlayerPrefabPath);
|
||||
try
|
||||
{
|
||||
GetOrAdd<PlayerCameraShakeController>(root);
|
||||
GetOrAdd<PlayerImpactController>(root);
|
||||
PrefabUtility.SaveAsPrefabAsset(root, PlayerPrefabPath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PrefabUtility.UnloadPrefabContents(root);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConfigureRocketPrefab(ShockwaveProfile rocketShockwave)
|
||||
{
|
||||
GameObject root = PrefabUtility.LoadPrefabContents(RocketPrefabPath);
|
||||
try
|
||||
{
|
||||
NetworkRocketItem rocket = root.GetComponent<NetworkRocketItem>();
|
||||
NetworkShockwaveEmitter emitter = GetOrAdd<NetworkShockwaveEmitter>(root);
|
||||
RocketImpactExplosion explosion = GetOrAdd<RocketImpactExplosion>(root);
|
||||
|
||||
SerializedObject serializedEmitter = new(emitter);
|
||||
SetObject(serializedEmitter, "profile", rocketShockwave);
|
||||
SetObject(serializedEmitter, "origin", root.transform);
|
||||
serializedEmitter.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
SerializedObject serializedExplosion = new(explosion);
|
||||
SetObject(serializedExplosion, "rocket", rocket);
|
||||
SetObject(serializedExplosion, "shockwave", emitter);
|
||||
serializedExplosion.ApplyModifiedPropertiesWithoutUndo();
|
||||
PrefabUtility.SaveAsPrefabAsset(root, RocketPrefabPath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
PrefabUtility.UnloadPrefabContents(root);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConfigureStandardRocketDefinition()
|
||||
{
|
||||
RocketItemDefinition definition =
|
||||
AssetDatabase.LoadAssetAtPath<RocketItemDefinition>(StandardRocketDefinitionPath);
|
||||
if (definition == null)
|
||||
return;
|
||||
|
||||
SerializedObject serialized = new(definition);
|
||||
serialized.FindProperty("missileType").enumValueIndex = (int)MissileType.Standard;
|
||||
serialized.ApplyModifiedPropertiesWithoutUndo();
|
||||
EditorUtility.SetDirty(definition);
|
||||
}
|
||||
|
||||
private static NetworkCannonController ConfigureCannonScene(
|
||||
CannonConfig config,
|
||||
ShockwaveProfile cannonShockwave)
|
||||
{
|
||||
GameObject root = GameObject.Find("Cannon Prototype");
|
||||
bool created = root == null;
|
||||
if (created)
|
||||
{
|
||||
root = new GameObject("Cannon Prototype");
|
||||
root.transform.SetPositionAndRotation(
|
||||
new Vector3(132f, 2.55f, 24.3f),
|
||||
Quaternion.Euler(0f, 90f, 0f));
|
||||
Undo.RegisterCreatedObjectUndo(root, "Create cannon prototype");
|
||||
}
|
||||
|
||||
GetOrAdd<NetworkObject>(root);
|
||||
NetworkCannonController controller = GetOrAdd<NetworkCannonController>(root);
|
||||
NetworkShockwaveEmitter emitter = GetOrAdd<NetworkShockwaveEmitter>(root);
|
||||
CannonControlBinder binder = GetOrAdd<CannonControlBinder>(root);
|
||||
CannonView view = GetOrAdd<CannonView>(root);
|
||||
|
||||
Transform baseVisual = GetOrCreatePrimitive(
|
||||
root.transform, "Cannon Base", PrimitiveType.Cube);
|
||||
baseVisual.localPosition = new Vector3(0f, 0.75f, 0f);
|
||||
baseVisual.localRotation = Quaternion.identity;
|
||||
baseVisual.localScale = new Vector3(2.2f, 1.5f, 2.2f);
|
||||
|
||||
Transform recoil = GetOrCreateChild(root.transform, "Barrel Recoil");
|
||||
recoil.localPosition = new Vector3(0f, 2.1f, 0f);
|
||||
recoil.localRotation = Quaternion.identity;
|
||||
recoil.localScale = Vector3.one;
|
||||
Transform barrel = GetOrCreatePrimitive(recoil, "Barrel", PrimitiveType.Cube);
|
||||
barrel.localPosition = new Vector3(0f, 0f, 2.1f);
|
||||
barrel.localRotation = Quaternion.identity;
|
||||
barrel.localScale = new Vector3(0.8f, 0.8f, 4.2f);
|
||||
Transform muzzle = GetOrCreateChild(recoil, "Muzzle");
|
||||
muzzle.localPosition = new Vector3(0f, 0f, 4.25f);
|
||||
|
||||
Transform slotObject = GetOrCreateChild(root.transform, "Rocket Slot");
|
||||
slotObject.localPosition = new Vector3(-2.2f, 1.25f, 0f);
|
||||
slotObject.localRotation = Quaternion.Euler(0f, 90f, 0f);
|
||||
slotObject.localScale = Vector3.one;
|
||||
BoxCollider slotCollider = GetOrAdd<BoxCollider>(slotObject.gameObject);
|
||||
slotCollider.isTrigger = true;
|
||||
slotCollider.size = new Vector3(1.4f, 1.4f, 3.2f);
|
||||
CannonRocketSlot slot = GetOrAdd<CannonRocketSlot>(slotObject.gameObject);
|
||||
Transform snapPoint = GetOrCreateChild(slotObject, "Rocket Snap Point");
|
||||
snapPoint.localPosition = Vector3.zero;
|
||||
snapPoint.localRotation = Quaternion.identity;
|
||||
|
||||
Transform controls = GetOrCreateChild(root.transform, "Controls");
|
||||
controls.localPosition = Vector3.zero;
|
||||
controls.localRotation = Quaternion.identity;
|
||||
controls.localScale = Vector3.one;
|
||||
NetworkPhysicalLeverInteractable lever = CreateLever(controls);
|
||||
NetworkButtonInteractable minus = CreateButton(
|
||||
controls, "Timer Minus", new Vector3(1.8f, 1.4f, -1.4f), "Timer -");
|
||||
NetworkButtonInteractable plus = CreateButton(
|
||||
controls, "Timer Plus", new Vector3(3.1f, 1.4f, -1.4f), "Timer +");
|
||||
TMP_Text timerText = CreateTimerText(controls);
|
||||
|
||||
SerializedObject serializedEmitter = new(emitter);
|
||||
SetObject(serializedEmitter, "profile", cannonShockwave);
|
||||
SetObject(serializedEmitter, "origin", muzzle);
|
||||
serializedEmitter.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
SerializedObject serializedController = new(controller);
|
||||
SetObject(serializedController, "config", config);
|
||||
SetObject(serializedController, "rocketSlot", slot);
|
||||
SetObject(serializedController, "rocketSnapPoint", snapPoint);
|
||||
SetObject(serializedController, "mapController",
|
||||
Object.FindFirstObjectByType<MapController>(FindObjectsInactive.Include));
|
||||
SetObject(serializedController, "shotShockwave", emitter);
|
||||
serializedController.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
SerializedObject serializedSlot = new(slot);
|
||||
SetObject(serializedSlot, "snapPoint", snapPoint);
|
||||
serializedSlot.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
SerializedObject serializedBinder = new(binder);
|
||||
SetObject(serializedBinder, "cannon", controller);
|
||||
SetObject(serializedBinder, "fireLever", lever);
|
||||
SetObject(serializedBinder, "decreaseTimerButton", minus);
|
||||
SetObject(serializedBinder, "increaseTimerButton", plus);
|
||||
serializedBinder.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
SerializedObject serializedView = new(view);
|
||||
SetObject(serializedView, "controller", controller);
|
||||
SetObject(serializedView, "recoilVisual", recoil);
|
||||
serializedView.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
CannonTimerView timerView = GetOrAdd<CannonTimerView>(timerText.gameObject);
|
||||
SerializedObject serializedTimer = new(timerView);
|
||||
SetObject(serializedTimer, "controller", controller);
|
||||
SetObject(serializedTimer, "timerText", timerText);
|
||||
serializedTimer.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
slot.Configure(controller);
|
||||
EditorUtility.SetDirty(root);
|
||||
return controller;
|
||||
}
|
||||
|
||||
private static NetworkPhysicalLeverInteractable CreateLever(Transform parent)
|
||||
{
|
||||
Transform existing = parent.Find("Fire Lever");
|
||||
GameObject root;
|
||||
if (existing != null)
|
||||
{
|
||||
root = existing.gameObject;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(LeverPrefabPath);
|
||||
root = (GameObject)PrefabUtility.InstantiatePrefab(prefab, parent);
|
||||
root.name = "Fire Lever";
|
||||
}
|
||||
|
||||
root.transform.localPosition = new Vector3(4.5f, 1.25f, -1.2f);
|
||||
root.transform.localRotation = Quaternion.Euler(0f, -90f, 0f);
|
||||
root.transform.localScale = Vector3.one * 0.65f;
|
||||
NetworkPhysicalLeverInteractable lever =
|
||||
root.GetComponent<NetworkPhysicalLeverInteractable>();
|
||||
SerializedObject serialized = new(lever);
|
||||
SetString(serialized, "interactionLabel", "Fire cannon");
|
||||
SetBool(serialized, "initialPositionIsMaximum", false);
|
||||
SetBool(serialized, "returnToInitialPositionAfterSwitch", true);
|
||||
SetFloat(serialized, "automaticReturnDelay", 0.2f);
|
||||
serialized.ApplyModifiedPropertiesWithoutUndo();
|
||||
return lever;
|
||||
}
|
||||
|
||||
private static NetworkButtonInteractable CreateButton(
|
||||
Transform parent,
|
||||
string name,
|
||||
Vector3 localPosition,
|
||||
string label)
|
||||
{
|
||||
Transform root = GetOrCreateChild(parent, name);
|
||||
root.localPosition = localPosition;
|
||||
root.localRotation = Quaternion.identity;
|
||||
root.localScale = Vector3.one;
|
||||
GetOrAdd<NetworkObject>(root.gameObject);
|
||||
|
||||
Transform visual = GetOrCreatePrimitive(root, "Button Visual", PrimitiveType.Cube);
|
||||
visual.localPosition = Vector3.zero;
|
||||
visual.localRotation = Quaternion.identity;
|
||||
visual.localScale = new Vector3(0.8f, 0.8f, 0.3f);
|
||||
NetworkButtonInteractable button = GetOrAdd<NetworkButtonInteractable>(root.gameObject);
|
||||
SerializedObject serialized = new(button);
|
||||
SetString(serialized, "interactionLabel", label);
|
||||
SetFloat(serialized, "maximumInteractionDistance", 3.5f);
|
||||
serialized.ApplyModifiedPropertiesWithoutUndo();
|
||||
return button;
|
||||
}
|
||||
|
||||
private static TMP_Text CreateTimerText(Transform parent)
|
||||
{
|
||||
Transform root = GetOrCreateChild(parent, "Timer Display");
|
||||
root.localPosition = new Vector3(2.45f, 2.25f, -1.35f);
|
||||
root.localRotation = Quaternion.Euler(0f, 180f, 0f);
|
||||
root.localScale = Vector3.one * 0.12f;
|
||||
TextMeshPro text = GetOrAdd<TextMeshPro>(root.gameObject);
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
text.fontSize = 4f;
|
||||
text.text = "INSERT ROCKET";
|
||||
text.rectTransform.sizeDelta = new Vector2(12f, 3f);
|
||||
return text;
|
||||
}
|
||||
|
||||
private static void ConfigureMapMarker()
|
||||
{
|
||||
MapController map = Object.FindFirstObjectByType<MapController>(FindObjectsInactive.Include);
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
Transform root = map.transform.Find("Impact Markers");
|
||||
if (root == null)
|
||||
{
|
||||
root = new GameObject("Impact Markers").transform;
|
||||
root.SetParent(map.transform, false);
|
||||
}
|
||||
MapImpactMarkerView view = GetOrAdd<MapImpactMarkerView>(root.gameObject);
|
||||
view.Configure(map.CoordinateSystem);
|
||||
|
||||
SerializedObject serializedMap = new(map);
|
||||
SetObject(serializedMap, "impactMarkerView", view);
|
||||
serializedMap.ApplyModifiedPropertiesWithoutUndo();
|
||||
EditorUtility.SetDirty(map);
|
||||
}
|
||||
|
||||
private static void EnsureDataFolder()
|
||||
{
|
||||
if (!AssetDatabase.IsValidFolder("Assets/CONTENT/Game/Data"))
|
||||
AssetDatabase.CreateFolder("Assets/CONTENT/Game", "Data");
|
||||
if (!AssetDatabase.IsValidFolder(DataFolder))
|
||||
AssetDatabase.CreateFolder("Assets/CONTENT/Game/Data", "Cannon");
|
||||
}
|
||||
|
||||
private static Transform GetOrCreateChild(Transform parent, string name)
|
||||
{
|
||||
Transform existing = parent.Find(name);
|
||||
if (existing != null)
|
||||
return existing;
|
||||
GameObject child = new(name);
|
||||
child.transform.SetParent(parent, false);
|
||||
Undo.RegisterCreatedObjectUndo(child, $"Create {name}");
|
||||
return child.transform;
|
||||
}
|
||||
|
||||
private static Transform GetOrCreatePrimitive(
|
||||
Transform parent,
|
||||
string name,
|
||||
PrimitiveType primitiveType)
|
||||
{
|
||||
Transform existing = parent.Find(name);
|
||||
if (existing != null)
|
||||
return existing;
|
||||
GameObject primitive = GameObject.CreatePrimitive(primitiveType);
|
||||
primitive.name = name;
|
||||
primitive.transform.SetParent(parent, false);
|
||||
Undo.RegisterCreatedObjectUndo(primitive, $"Create {name}");
|
||||
return primitive.transform;
|
||||
}
|
||||
|
||||
private static T GetOrAdd<T>(GameObject target) where T : Component
|
||||
{
|
||||
T component = target.GetComponent<T>();
|
||||
return component != null ? component : Undo.AddComponent<T>(target);
|
||||
}
|
||||
|
||||
private static void SetObject(SerializedObject target, string property, Object value) =>
|
||||
target.FindProperty(property).objectReferenceValue = value;
|
||||
private static void SetFloat(SerializedObject target, string property, float value) =>
|
||||
target.FindProperty(property).floatValue = value;
|
||||
private static void SetBool(SerializedObject target, string property, bool value) =>
|
||||
target.FindProperty(property).boolValue = value;
|
||||
private static void SetString(SerializedObject target, string property, string value) =>
|
||||
target.FindProperty(property).stringValue = value;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe3002dfbec1fe1458dcd6058b1486c3
|
||||
Reference in New Issue
Block a user