init
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d8cd96d9d6f4569b1e10d3b6292778d
|
||||
timeCreated: 1708460783
|
||||
@@ -0,0 +1,96 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Sirenix.OdinInspector;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.Utilities;
|
||||
using UnityEditor;
|
||||
using VOID.ScriptableObjects.Affiliation;
|
||||
|
||||
namespace VOID.Editor.EditorWindow.Affiliation
|
||||
{
|
||||
public class AffiliationEditor : OdinEditorWindow
|
||||
{
|
||||
[MenuItem("VOID RPG/Affiliation/Affiliation Editor")]
|
||||
private static void OpenWindow() => GetWindow<AffiliationEditor>().Show();
|
||||
|
||||
[ShowInInspector]
|
||||
[ReadOnly]
|
||||
private List<Faction> _factions = new();
|
||||
|
||||
[ShowInInspector]
|
||||
[HideReferenceObjectPicker]
|
||||
[ListDrawerSettings(HideAddButton = true, HideRemoveButton = true, DraggableItems = false)]
|
||||
private List<AffiliationEditorConflict> _conflicts = new();
|
||||
|
||||
[Button]
|
||||
private void FindFactions()
|
||||
{
|
||||
_factions = AssetDatabase
|
||||
.FindAssets($"t:{nameof(Faction)}", new[] { "Assets/85 - GameData" })
|
||||
.Select(AssetDatabase.GUIDToAssetPath)
|
||||
.Select(AssetDatabase.LoadAssetAtPath<Faction>)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
[Button]
|
||||
private void FindConflicts()
|
||||
{
|
||||
if (_factions.IsNullOrEmpty()) FindFactions();
|
||||
|
||||
_factions.ForEach(thisFaction =>
|
||||
{
|
||||
_factions.ForEach(otherFaction =>
|
||||
{
|
||||
CompareAttitudeConflict(thisFaction, otherFaction);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void CompareAttitudeConflict(Faction faction1, Faction faction2)
|
||||
{
|
||||
var attitude1 = faction1.GetAttitudeFor(faction2);
|
||||
var attitude2 = faction2.GetAttitudeFor(faction1);
|
||||
if (attitude1 != attitude2) AddConflict(faction1, faction2);
|
||||
}
|
||||
|
||||
private void AddConflict(Faction faction1, Faction faction2)
|
||||
{
|
||||
var conflictExists = _conflicts
|
||||
.Where(conflict => conflict.faction1 == faction1 || conflict.faction1 == faction2)
|
||||
.Any(conflict => conflict.faction2 == faction1 || conflict.faction2 == faction2);
|
||||
if (conflictExists) return;
|
||||
_conflicts.Add(new AffiliationEditorConflict { faction1 = faction1, faction2 = faction2 });
|
||||
}
|
||||
|
||||
[Button]
|
||||
private void ResolveEasyConflicts()
|
||||
{
|
||||
if (_conflicts.IsNullOrEmpty()) FindConflicts();
|
||||
|
||||
_conflicts.ToList().ForEach(conflict =>
|
||||
{
|
||||
var attitude1 = conflict.faction1.GetAttitudeFor(conflict.faction2);
|
||||
var attitude2 = conflict.faction2.GetAttitudeFor(conflict.faction1);
|
||||
if (attitude1.HasValue && attitude2.HasValue) return;
|
||||
|
||||
if (attitude1.HasValue)
|
||||
{
|
||||
conflict.faction1.factionAttitudes[conflict.faction2] = attitude1.Value;
|
||||
conflict.faction2.factionAttitudes[conflict.faction1] = attitude1.Value;
|
||||
}
|
||||
|
||||
if (attitude2.HasValue)
|
||||
{
|
||||
conflict.faction1.factionAttitudes[conflict.faction2] = attitude2.Value;
|
||||
conflict.faction2.factionAttitudes[conflict.faction1] = attitude2.Value;
|
||||
}
|
||||
|
||||
EditorUtility.SetDirty(conflict.faction1);
|
||||
EditorUtility.SetDirty(conflict.faction2);
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
_conflicts.Remove(conflict);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26794cdf00a546adb8097ebd134eefe7
|
||||
timeCreated: 1708460788
|
||||
@@ -0,0 +1,51 @@
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using VOID.Generic.Dict;
|
||||
using VOID.ScriptableObjects.Affiliation;
|
||||
|
||||
namespace VOID.Editor.EditorWindow.Affiliation
|
||||
{
|
||||
public record AffiliationEditorConflict
|
||||
{
|
||||
[ReadOnly]
|
||||
[HorizontalGroup("faction1")]
|
||||
public Faction faction1;
|
||||
|
||||
[ReadOnly]
|
||||
[ShowInInspector]
|
||||
[HideLabel]
|
||||
[HorizontalGroup("faction1")]
|
||||
public string faction1Attitude => faction1.GetAttitudeFor(faction2).ToString();
|
||||
|
||||
[ReadOnly]
|
||||
[HorizontalGroup("faction2")]
|
||||
public Faction faction2;
|
||||
|
||||
[ReadOnly]
|
||||
[ShowInInspector]
|
||||
[HideLabel]
|
||||
[HorizontalGroup("faction2")]
|
||||
public string faction2Attitude => faction2.GetAttitudeFor(faction1).ToString();
|
||||
|
||||
[GUIColor(nameof(GetResolveColor))]
|
||||
[InlineButton(nameof(Resolve))]
|
||||
public AttitudeType newAttitude;
|
||||
|
||||
private bool _resolved;
|
||||
|
||||
private void Resolve()
|
||||
{
|
||||
faction1.factionAttitudes[faction2] = newAttitude;
|
||||
faction2.factionAttitudes[faction1] = newAttitude;
|
||||
_resolved = true;
|
||||
|
||||
EditorUtility.SetDirty(faction1);
|
||||
EditorUtility.SetDirty(faction2);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
|
||||
private Color GetResolveColor() => _resolved ? Color.green : Color.red;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7971e0e526a945848f51bd9e9eb99fad
|
||||
timeCreated: 1708462802
|
||||
@@ -0,0 +1,58 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Sirenix.OdinInspector;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VOID.Editor.EditorWindow
|
||||
{
|
||||
public class ForceReserializeAssets : OdinEditorWindow
|
||||
{
|
||||
[MenuItem("VOID RPG/Assets/Force Reserialize Assets", priority = 1)]
|
||||
private static void OpenWindow() => GetWindow<ForceReserializeAssets>().Show();
|
||||
|
||||
[InfoBox(
|
||||
"<b>WHY use this:</b>\n" +
|
||||
"- Update all names of properties when changed by <b>FormerlySerializedAs</b>\n" +
|
||||
"\n" +
|
||||
"<b>HOW use this:</b>\n" +
|
||||
"- Add all files to update serialized data and press <b>Reserialize</b>\n" +
|
||||
"- OR! Just press <b>Serialize Everything</b>, but it will go through all files in project"
|
||||
)]
|
||||
[ShowInInspector, AssetsOnly] private List<Object> _files = new();
|
||||
|
||||
[Button(ButtonSizes.Gigantic)]
|
||||
public void Reserialize()
|
||||
{
|
||||
var paths = _files
|
||||
.Select(AssetDatabase.GetAssetPath)
|
||||
.SelectMany(file => AssetDatabase.IsValidFolder(file) ? GetAssetsPathsFromFolder(file) : new[] { file })
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
AssetDatabase.ForceReserializeAssets(paths);
|
||||
|
||||
_files.Clear();
|
||||
}
|
||||
|
||||
[Button(Name = "Reserialize Everything")]
|
||||
[GUIColor(1, 0, 0)]
|
||||
public void ReserializeEverything()
|
||||
{
|
||||
if (EditorUtility.DisplayDialog(
|
||||
"Reserialize Everything",
|
||||
"Are you sure? It'll be very long process, around ~30 minutes!",
|
||||
"Yes, do it",
|
||||
"No"))
|
||||
{
|
||||
AssetDatabase.ForceReserializeAssets();
|
||||
}
|
||||
}
|
||||
|
||||
private string[] GetAssetsPathsFromFolder(string folderPath)
|
||||
{
|
||||
return AssetDatabase.FindAssets("", new[] { folderPath }).Select(AssetDatabase.GUIDToAssetPath).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5964811217cf4e80b131270d1c11cad2
|
||||
timeCreated: 1727892808
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e84a6e0b5acc40088df9f749e3994c87
|
||||
timeCreated: 1691598777
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Sirenix.OdinInspector;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.Utilities;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using VOID.Generic.Objects.Item;
|
||||
|
||||
namespace VOID.Editor.EditorWindow.Objects
|
||||
{
|
||||
public class ItemUniquenessGenerator : OdinEditorWindow
|
||||
{
|
||||
[ShowInInspector, ReadOnly] private List<GameObject> _wereDuplicated = new();
|
||||
[ShowInInspector, ReadOnly] private List<GameObject> _wereMissing = new();
|
||||
[ShowInInspector, ReadOnly] private List<GameObject> _untouched = new();
|
||||
|
||||
[MenuItem("VOID RPG/Items/UniqueID generator")]
|
||||
private static void OpenWindow() => GetWindow<ItemUniquenessGenerator>().Show();
|
||||
|
||||
[Button("GENERATE")]
|
||||
public void Generate()
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Generating unique ids...", "PREPARING", 0);
|
||||
|
||||
_wereDuplicated.Clear();
|
||||
_wereMissing.Clear();
|
||||
_untouched.Clear();
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var usedUniqueIds = new List<string>();
|
||||
var guids = AssetDatabase.FindAssets("t:prefab", new[] { "Assets/2 - Prefabs" });
|
||||
|
||||
for (var i = 0; i < guids.Length; i++)
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Generating unique ids...", $"{i} / {guids.Length}", (float)i / guids.Length);
|
||||
var path = AssetDatabase.GUIDToAssetPath(guids[i]);
|
||||
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);
|
||||
if (PrefabUtility.GetPrefabAssetType(prefab) is not PrefabAssetType.Regular) continue;
|
||||
var item = prefab.GetComponent<ItemObject>();
|
||||
if (!item) continue;
|
||||
|
||||
if (item.itemData.uniqueId.IsNullOrWhitespace())
|
||||
{
|
||||
// Missing UniqueId
|
||||
_wereMissing.Add(prefab);
|
||||
item.itemData.uniqueId = Guid.NewGuid().ToString();
|
||||
}
|
||||
else if (usedUniqueIds.Contains(item.itemData.uniqueId))
|
||||
{
|
||||
// Duplicated UniqueId
|
||||
_wereDuplicated.Add(prefab);
|
||||
item.itemData.uniqueId = Guid.NewGuid().ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Looks good
|
||||
_untouched.Add(prefab);
|
||||
}
|
||||
|
||||
usedUniqueIds.Add(item.itemData.uniqueId);
|
||||
PrefabUtility.SaveAsPrefabAsset(prefab, AssetDatabase.GetAssetPath(prefab));
|
||||
}
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
EditorUtility.DisplayDialog(
|
||||
"Generating UniqueIDs finished",
|
||||
$"Generating finished in {stopwatch.ElapsedMilliseconds} ms.\n" +
|
||||
$"{_wereMissing.Count} - ItemObjects had missing UniqueID.\n" +
|
||||
$"{_wereDuplicated.Count} - ItemObjects had duplicated UniqueID.\n" +
|
||||
$"{_untouched.Count} - ItemObjects had good UniqueID.",
|
||||
"OK"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40849949eefb43a699aeb43c1ed0e681
|
||||
timeCreated: 1691598803
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b88ecf75a0a68d4097bf76407b5bf22
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,350 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Sirenix.OdinInspector;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.Utilities;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using VOID.Editor.Utils;
|
||||
using VOID.Generic.World;
|
||||
|
||||
namespace VOID.Editor.EditorWindow.World
|
||||
{
|
||||
public class ComplexAreaRotateVariantGenerator : OdinEditorWindow
|
||||
{
|
||||
[MenuItem("VOID RPG/World/Complex Area Rotate Variant Generator")]
|
||||
private static void OpenWindow() => GetWindow<ComplexAreaRotateVariantGenerator>().Show();
|
||||
|
||||
// Input and Output for user
|
||||
[ShowInInspector, AssetsOnly] private List<ComplexArea> sourceComplexAreas = new();
|
||||
[ShowInInspector, ReadOnly] private List<ComplexArea> generatedComplexAreas = new();
|
||||
|
||||
// Rotation variants to create
|
||||
private static readonly float[] Rotations = { 90, 180, 270 };
|
||||
|
||||
// Temporary variables
|
||||
private ComplexArea _targetComplexArea;
|
||||
private string _sourcePrefabPath;
|
||||
private string _sourceFolder;
|
||||
private float _variantRotation;
|
||||
private string _targetPrefabPath;
|
||||
private string _targetFolder;
|
||||
|
||||
public static void GenerateRotatedVariants(ComplexArea complexArea)
|
||||
{
|
||||
// Only ASSETS for this generation!
|
||||
var prefab = complexArea.gameObject.GetPrefabAsset();
|
||||
if (prefab == null)
|
||||
{
|
||||
Debug.LogError("Only prefab asset is valid to variant generation!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Just to be sure - save given prefab for user before generation
|
||||
PrefabUtility.SavePrefabAsset(complexArea.gameObject);
|
||||
|
||||
var isOpen = HasOpenInstances<ComplexAreaRotateVariantGenerator>();
|
||||
var variantGenerator = GetWindow<ComplexAreaRotateVariantGenerator>(false, null, false);
|
||||
variantGenerator.sourceComplexAreas = new List<ComplexArea> { prefab.GetComponent<ComplexArea>() };
|
||||
variantGenerator.GenerateRotatedVariants();
|
||||
if (!isOpen) variantGenerator.Close();
|
||||
}
|
||||
|
||||
[Button]
|
||||
private void GenerateRotatedVariants()
|
||||
{
|
||||
if (sourceComplexAreas.IsNullOrEmpty())
|
||||
{
|
||||
Debug.LogWarning("ComplexArea not selected");
|
||||
return;
|
||||
}
|
||||
|
||||
generatedComplexAreas.Clear();
|
||||
sourceComplexAreas.ForEach(sourceComplexArea =>
|
||||
{
|
||||
var variants = Rotations.Select(rotation => GenerateRotatedVariant(sourceComplexArea, rotation)).ToList();
|
||||
sourceComplexArea.isVariant = false;
|
||||
sourceComplexArea.variants = variants;
|
||||
sourceComplexArea.original = null;
|
||||
PrefabUtility.SavePrefabAsset(sourceComplexArea.gameObject);
|
||||
generatedComplexAreas.AddRange(variants);
|
||||
});
|
||||
sourceComplexAreas.Clear();
|
||||
}
|
||||
|
||||
private ComplexArea GenerateRotatedVariant(ComplexArea sourceComplexArea, float rotation)
|
||||
{
|
||||
_sourcePrefabPath = AssetDatabase.GetAssetPath(sourceComplexArea.gameObject);
|
||||
_sourceFolder = Path.GetDirectoryName(_sourcePrefabPath)?.Replace("\\", "/") ?? "";
|
||||
_variantRotation = rotation;
|
||||
_targetFolder = $"{_sourceFolder}/{sourceComplexArea.gameObject.name}_v{_variantRotation}";
|
||||
|
||||
if (Directory.Exists(_targetFolder)) Directory.Delete(_targetFolder, true);
|
||||
Directory.CreateDirectory(_targetFolder);
|
||||
|
||||
DuplicatePrefab();
|
||||
DuplicateTerrains();
|
||||
RotatePrefab();
|
||||
UpdateTerrainsHeight();
|
||||
UpdateTerrainsAlphas();
|
||||
UpdateTerrainsDetails();
|
||||
UpdateTerrainsTrees();
|
||||
UpdateComplexArea();
|
||||
UpdateComplexAreaOriginalVariant(sourceComplexArea);
|
||||
|
||||
PrefabUtility.SaveAsPrefabAsset(_targetComplexArea.gameObject, _targetPrefabPath);
|
||||
PrefabUtility.UnloadPrefabContents(_targetComplexArea.gameObject);
|
||||
|
||||
return AssetDatabase.LoadAssetAtPath<GameObject>(_targetPrefabPath).GetComponent<ComplexArea>();
|
||||
}
|
||||
|
||||
private void DuplicatePrefab()
|
||||
{
|
||||
// Duplicate prefab asset in sub directory
|
||||
_targetPrefabPath = $"{_targetFolder}/{Path.GetFileNameWithoutExtension(_sourcePrefabPath)}_v{_variantRotation}.prefab";
|
||||
AssetDatabase.CopyAsset(_sourcePrefabPath, _targetPrefabPath);
|
||||
|
||||
// "Open" duplicated prefab for editing
|
||||
_targetComplexArea = PrefabUtility.LoadPrefabContents(_targetPrefabPath).GetComponent<ComplexArea>();
|
||||
}
|
||||
|
||||
private void DuplicateTerrains()
|
||||
{
|
||||
// Duplicate TerrainData and place them in relative directiory (if not possible put them next to prefab)
|
||||
_targetComplexArea.GetComponentsInChildren<Terrain>().ForEach(terrain =>
|
||||
{
|
||||
var dataPath = AssetDatabase.GetAssetPath(terrain.terrainData);
|
||||
var dataPathNew = GetNewAssetPath(dataPath);
|
||||
Directory.CreateDirectory(_targetFolder);
|
||||
AssetDatabase.CopyAsset(dataPath, dataPathNew);
|
||||
var terrainData = AssetDatabase.LoadAssetAtPath<TerrainData>(dataPathNew);
|
||||
terrain.GetComponent<Terrain>().terrainData = terrainData;
|
||||
terrain.GetComponent<TerrainCollider>().terrainData = terrainData;
|
||||
});
|
||||
|
||||
// Update asset database
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
private void RotatePrefab()
|
||||
{
|
||||
// Terrain rotating FIX - instead we will rotate dummies
|
||||
var terrainPositionDummyList = new Dictionary<GameObject, Terrain>();
|
||||
_targetComplexArea.gameObject.GetComponentsInChildren<Terrain>().ForEach(terrain =>
|
||||
{
|
||||
var dummy = new GameObject();
|
||||
var sizeOffset = Vector3.Scale(new Vector3(.5f, 0, .5f), terrain.terrainData.size);
|
||||
dummy.transform.parent = terrain.transform.parent;
|
||||
dummy.transform.position = terrain.transform.position + sizeOffset;
|
||||
terrainPositionDummyList.Add(dummy, terrain);
|
||||
});
|
||||
|
||||
// All children of prefab
|
||||
var prefabChildren = new List<Transform>();
|
||||
for (var i = 0; i < _targetComplexArea.gameObject.transform.childCount; i++)
|
||||
prefabChildren.Add(_targetComplexArea.gameObject.transform.GetChild(i));
|
||||
|
||||
// Put empty dummy
|
||||
var dummyRotate = new GameObject();
|
||||
dummyRotate.transform.parent = _targetComplexArea.gameObject.transform;
|
||||
dummyRotate.transform.position = Vector3.zero;
|
||||
|
||||
// Put all children into dummy
|
||||
prefabChildren.ForEach(child => child.parent = dummyRotate.transform);
|
||||
|
||||
// Rotate dummy with all children
|
||||
dummyRotate.transform.Rotate(Vector3.up, _variantRotation);
|
||||
|
||||
// Take out all children from dummy
|
||||
prefabChildren.ForEach(child => child.parent = _targetComplexArea.gameObject.transform);
|
||||
|
||||
// Remove dummy
|
||||
DestroyImmediate(dummyRotate);
|
||||
|
||||
// Terrain rotating FIX - Put terrains in good positions
|
||||
terrainPositionDummyList.ForEach(pair =>
|
||||
{
|
||||
var dummy = pair.Key;
|
||||
var terrain = pair.Value;
|
||||
var sizeOffset = Vector3.Scale(new Vector3(.5f, 0, .5f), terrain.terrainData.size);
|
||||
terrain.transform.position = pair.Key.transform.position - sizeOffset;
|
||||
terrain.transform.rotation = Quaternion.identity;
|
||||
DestroyImmediate(pair.Key);
|
||||
});
|
||||
|
||||
// Update asset database
|
||||
AssetDatabase.SaveAssets();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
private void UpdateTerrainsHeight()
|
||||
{
|
||||
_targetComplexArea.gameObject.GetComponentsInChildren<Terrain>().ForEach(terrain =>
|
||||
{
|
||||
var rotationTimes = Mathf.RoundToInt(_variantRotation / 90);
|
||||
var terrainData = terrain.terrainData;
|
||||
var heightMapSize = terrainData.heightmapResolution;
|
||||
var heights = terrainData.GetHeights(0, 0, heightMapSize, heightMapSize);
|
||||
var rotatedHeights = new float[heightMapSize, heightMapSize];
|
||||
|
||||
// Perform rotating N times
|
||||
for (var i = 0; i < rotationTimes; i++)
|
||||
{
|
||||
// Rotating whole two-dimensional height array by 90 degree
|
||||
for (var y = 0; y < heightMapSize; y++)
|
||||
for (var x = 0; x < heightMapSize; x++)
|
||||
rotatedHeights[y, x] = heights[x, heightMapSize - y - 1];
|
||||
|
||||
// Rotated by 90 degree, prepare starting point for next rotating
|
||||
heights = (float[,])rotatedHeights.Clone();
|
||||
}
|
||||
|
||||
// Update terrain
|
||||
terrainData.SetHeights(0, 0, rotatedHeights);
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateTerrainsAlphas()
|
||||
{
|
||||
_targetComplexArea.gameObject.GetComponentsInChildren<Terrain>().ForEach(terrain =>
|
||||
{
|
||||
var rotationTimes = Mathf.RoundToInt(_variantRotation / 90);
|
||||
var terrainData = terrain.terrainData;
|
||||
var alphaSize = terrainData.alphamapResolution;
|
||||
var alphaCount = terrainData.alphamapLayers;
|
||||
var alphas = terrainData.GetAlphamaps(0, 0, alphaSize, alphaSize);
|
||||
var rotatedAlphas = new float[alphaSize, alphaSize, alphaCount];
|
||||
|
||||
// Perform rotating N times
|
||||
for (var i = 0; i < rotationTimes; i++)
|
||||
{
|
||||
// Rotating whole two-dimensional array for each alpha map by 90 degree
|
||||
for (var y = 0; y < alphaSize; y++)
|
||||
for (var x = 0; x < alphaSize; x++)
|
||||
for (var a = 0; a < alphaCount; a++)
|
||||
rotatedAlphas[y, x, a] = alphas[x, alphaSize - y - 1, a];
|
||||
|
||||
// Rotated by 90 degree, prepare starting point for next rotating
|
||||
alphas = (float[,,])rotatedAlphas.Clone();
|
||||
}
|
||||
|
||||
// Update terrain
|
||||
terrainData.SetAlphamaps(0, 0, rotatedAlphas);
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateTerrainsDetails()
|
||||
{
|
||||
_targetComplexArea.gameObject.GetComponentsInChildren<Terrain>().ForEach(terrain =>
|
||||
{
|
||||
var rotationTimes = Mathf.RoundToInt(_variantRotation / 90);
|
||||
var terrainData = terrain.terrainData;
|
||||
var detailSize = terrainData.detailResolution;
|
||||
var detailLayerCount = terrainData.detailPrototypes.Length;
|
||||
var rotatedDetails = new int[detailSize, detailSize];
|
||||
|
||||
// Rotate ALL detail layers
|
||||
for (var a = 0; a < detailLayerCount; a++)
|
||||
{
|
||||
// Get current detail layer at index
|
||||
var details = terrainData.GetDetailLayer(0, 0, detailSize, detailSize, a);
|
||||
|
||||
// Perform rotating N times
|
||||
for (var i = 0; i < rotationTimes; i++)
|
||||
{
|
||||
// Rotating whole dimensional array by 90 degree
|
||||
for (var y = 0; y < detailSize; y++)
|
||||
for (var x = 0; x < detailSize; x++)
|
||||
rotatedDetails[y, x] = details[x, detailSize - y - 1];
|
||||
|
||||
// Rotated by 90 degree, prepare starting point for next rotating
|
||||
details = (int[,])rotatedDetails.Clone();
|
||||
}
|
||||
|
||||
// Update terrain
|
||||
terrainData.SetDetailLayer(0, 0, a, rotatedDetails);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateTerrainsTrees()
|
||||
{
|
||||
_targetComplexArea.gameObject.GetComponentsInChildren<Terrain>().ForEach(terrain =>
|
||||
{
|
||||
var terrainData = terrain.terrainData;
|
||||
|
||||
// New empty GameObject for further rotating trees
|
||||
var terrainDummy = new GameObject();
|
||||
terrainDummy.transform.position = terrain.transform.position + terrainData.size/2;
|
||||
|
||||
// Map dummy GameObjects to each tree for rotating purposes, by making it child to terrain dummy
|
||||
var treeList = terrainData.treeInstances;
|
||||
var dummyList = new GameObject[treeList.Length];
|
||||
for (var i = 0; i < treeList.Length; i++)
|
||||
{
|
||||
dummyList[i] = new GameObject();
|
||||
dummyList[i].transform.parent = terrainDummy.transform;
|
||||
dummyList[i].transform.position = terrain.transform.position + Vector3.Scale(treeList[i].position, terrainData.size);
|
||||
}
|
||||
|
||||
// Rotate dummy terrain (and all tree dummies)
|
||||
terrainDummy.transform.Rotate(Vector3.up, _variantRotation);
|
||||
|
||||
// Corrent positions and rotations of all trees, by using created dummies
|
||||
for (var i = 0; i < treeList.Length; i++)
|
||||
{
|
||||
var relativePosition = dummyList[i].transform.position - terrain.transform.position;
|
||||
treeList[i].position = new Vector3(relativePosition.x / terrainData.size.x, 0, relativePosition.z / terrainData.size.z);
|
||||
treeList[i].rotation = dummyList[i].transform.rotation.eulerAngles.y;
|
||||
}
|
||||
|
||||
// Update Terrain
|
||||
terrainData.SetTreeInstances(treeList, true);
|
||||
|
||||
// Remove dummies
|
||||
dummyList.ForEach(DestroyImmediate);
|
||||
DestroyImmediate(terrainDummy);
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateComplexArea()
|
||||
{
|
||||
_targetComplexArea.areas.ForEach(area =>
|
||||
{
|
||||
// Areas should not be rotated
|
||||
area.transform.rotation = Quaternion.identity;
|
||||
|
||||
// Swap connection clockwise - N times of needed rotation
|
||||
var rotationTimes = Mathf.RoundToInt(_variantRotation / 90);
|
||||
for (var i = 0; i < rotationTimes; i++)
|
||||
{
|
||||
var tempConnection = area.forwardConnection;
|
||||
area.forwardConnection = area.leftConnection;
|
||||
area.leftConnection = area.backConnection;
|
||||
area.backConnection = area.rightConnection;
|
||||
area.rightConnection = tempConnection;
|
||||
}
|
||||
});
|
||||
|
||||
// Run all inside updates and fixes
|
||||
_targetComplexArea.UpdateAll();
|
||||
_targetComplexArea.AutoFixAll();
|
||||
}
|
||||
|
||||
private void UpdateComplexAreaOriginalVariant(ComplexArea sourceComplexArea)
|
||||
{
|
||||
_targetComplexArea.isVariant = true;
|
||||
_targetComplexArea.variants.Clear();
|
||||
_targetComplexArea.original = sourceComplexArea;
|
||||
}
|
||||
|
||||
private string GetNewAssetPath(string path)
|
||||
{
|
||||
if (path.StartsWith(_sourceFolder) == false) return $"{_targetFolder}/{Path.GetFileName(path)}";
|
||||
var relativePath = path.Substring(_sourceFolder.Length).TrimStart('/');
|
||||
return $"{_targetFolder}/{relativePath}";
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f3e35552b4d52364b8ddd710111b0378
|
||||
Reference in New Issue
Block a user