This commit is contained in:
SzymonMis
2026-02-19 21:34:07 +01:00
parent 8de064552e
commit 06f9c7349d
25 changed files with 45269 additions and 346 deletions

8
Assets/AI/Common.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c2cfd6f241d01aa4db9370f43cc0950e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
using System;
using UnityEngine;
namespace DemonBoss.AI
{
/// <summary>
/// Tiny helper MonoBehaviour to delay a callback without coroutines.
/// </summary>
public sealed class DelayedInvoker : MonoBehaviour
{
private float _timeLeft;
private Action _callback;
public void Init(float delay, Action callback)
{
_timeLeft = delay;
_callback = callback;
}
private void Update()
{
_timeLeft -= Time.deltaTime;
if (_timeLeft <= 0f)
{
try { _callback?.Invoke(); }
finally { Destroy(this); }
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6c81673d9e75da44fb3d5c5f6911c775

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c82aa8a4a75da9b49b73d6b4d5d86158
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,3 +1,4 @@
using DemonBoss.AI;
using Invector.vCharacterController.AI.FSMBehaviour;
using Lean.Pool;
using UnityEngine;
@@ -331,29 +332,5 @@ namespace DemonBoss.Magic
public float GetSequenceProgress() => meteorCount > 0 ? (float)_meteorsSpawned / meteorCount : 1f;
/// <summary>
/// Tiny helper MonoBehaviour to delay a callback without coroutines here.
/// </summary>
private sealed class DelayedInvoker : MonoBehaviour
{
private float _timeLeft;
private System.Action _callback;
public void Init(float delay, System.Action callback)
{
_timeLeft = delay;
_callback = callback;
}
private void Update()
{
_timeLeft -= Time.deltaTime;
if (_timeLeft <= 0f)
{
try { _callback?.Invoke(); }
finally { Destroy(this); }
}
}
}
}
}
}

View File

@@ -30,6 +30,9 @@ namespace DemonBoss.Summoner
[Tooltip("Only spawn if player is within this distance (0 = disabled)")]
public float maxDistanceToPlayer = 0f;
[Tooltip("Require summoner to be at or beyond safe distance before summoning")]
public bool requireSafeDistance = false;
[Header("Debug")]
[Tooltip("Enable debug logging")]
public bool enableDebug = false;
@@ -77,6 +80,12 @@ namespace DemonBoss.Summoner
}
}
if (requireSafeDistance && !summoner.IsAtSafeDistance())
{
if (enableDebug) Debug.Log("[DEC_CanSpawnMinions] Not at safe distance - FALSE");
return false;
}
// Check cooldown
if (checkCooldown)
{
@@ -102,4 +111,4 @@ namespace DemonBoss.Summoner
return true;
}
}
}
}

View File

@@ -0,0 +1,32 @@
using Invector.vCharacterController.AI.FSMBehaviour;
using UnityEngine;
namespace DemonBoss.Summoner
{
/// <summary>
/// FSM Decision: true when summoner is NOT spawning (spawn sequence finished)
/// </summary>
[CreateAssetMenu(menuName = "Invector/FSM/Decisions/Summoner/Is Spawning Complete")]
public class DEC_IsSpawningComplete : vStateDecision
{
public override string categoryName => "Summoner";
public override string defaultName => "Is Spawning Complete";
[Header("Debug")]
public bool enableDebug = false;
public override bool Decide(vIFSMBehaviourController fsmBehaviour)
{
var summoner = fsmBehaviour.gameObject.GetComponent<SummonerAI>();
if (summoner == null)
{
if (enableDebug) Debug.LogWarning("[DEC_IsSpawningComplete] No SummonerAI component found!");
return false;
}
bool done = !summoner.IsSpawning;
if (enableDebug) Debug.Log($"[DEC_IsSpawningComplete] done={done}");
return done;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 57576c59e67c93f47bf31ee6a7cb00a6

View File

@@ -0,0 +1,33 @@
using Invector.vCharacterController.AI.FSMBehaviour;
using UnityEngine;
namespace DemonBoss.Summoner
{
/// <summary>
/// FSM Decision: should Summoner cast a ranged spell
/// </summary>
[CreateAssetMenu(menuName = "Invector/FSM/Decisions/Summoner/Should Cast Spell")]
public class DEC_ShouldCastSpell : vStateDecision
{
public override string categoryName => "Summoner";
public override string defaultName => "Should Cast Spell";
[Header("Debug")]
[Tooltip("Enable debug logging")]
public bool enableDebug = false;
public override bool Decide(vIFSMBehaviourController fsmBehaviour)
{
var summoner = fsmBehaviour.gameObject.GetComponent<SummonerAI>();
if (summoner == null)
{
if (enableDebug) Debug.LogWarning("[DEC_ShouldCastSpell] No SummonerAI component found!");
return false;
}
bool canCast = summoner.CanCastSpell();
if (enableDebug) Debug.Log($"[DEC_ShouldCastSpell] canCast={canCast}");
return canCast;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8d84d40bbfa01d24a8b3d0e9ac5ab2c3

View File

@@ -0,0 +1,33 @@
using Invector.vCharacterController.AI.FSMBehaviour;
using UnityEngine;
namespace DemonBoss.Summoner
{
/// <summary>
/// FSM Decision: should Summoner flee to reach safe distance
/// </summary>
[CreateAssetMenu(menuName = "Invector/FSM/Decisions/Summoner/Should Flee To Safe Distance")]
public class DEC_ShouldFleeToSafeDistance : vStateDecision
{
public override string categoryName => "Summoner";
public override string defaultName => "Should Flee To Safe Distance";
[Header("Debug")]
[Tooltip("Enable debug logging")]
public bool enableDebug = false;
public override bool Decide(vIFSMBehaviourController fsmBehaviour)
{
var summoner = fsmBehaviour.gameObject.GetComponent<SummonerAI>();
if (summoner == null)
{
if (enableDebug) Debug.LogWarning("[DEC_ShouldFleeToSafeDistance] No SummonerAI component found!");
return false;
}
bool shouldFlee = summoner.ShouldFleeToSafeDistance();
if (enableDebug) Debug.Log($"[DEC_ShouldFleeToSafeDistance] shouldFlee={shouldFlee}");
return shouldFlee;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9f2c33cfc53333944b5c60a3ff6a3de2

View File

@@ -24,6 +24,9 @@ namespace DemonBoss.Summoner
[Tooltip("Attack even when minions are alive")]
public bool attackWithMinions = false;
[Tooltip("Force melee when player is too close, even if minions are alive")]
public bool forceMeleeWhenTooClose = true;
[Header("Debug")]
[Tooltip("Enable debug logging")]
public bool enableDebug = false;
@@ -44,6 +47,25 @@ namespace DemonBoss.Summoner
return false;
}
// Check distance to player
float distance = summoner.GetDistanceToPlayer();
bool inRange = distance >= minMeleeDistance && distance <= maxMeleeDistance;
// Last resort: only melee when in range AND cannot spawn or cast
bool canSpawn = summoner.CanSpawnMinions;
bool canCast = summoner.CanCastSpell();
if (forceMeleeWhenTooClose && inRange)
{
bool lastResort = !canSpawn && !canCast;
if (enableDebug)
{
Debug.Log($"[DEC_ShouldMeleeAttack] Last resort check (distance {distance:F1}m, canSpawn={canSpawn}, canCast={canCast}) - {(lastResort ? "TRUE" : "FALSE")}");
}
return lastResort;
}
// Check if has minions and shouldn't attack with them
if (!attackWithMinions && summoner.HasActiveMinions)
{
@@ -51,11 +73,6 @@ namespace DemonBoss.Summoner
return false;
}
// Check distance to player
float distance = summoner.GetDistanceToPlayer();
bool inRange = distance >= minMeleeDistance && distance <= maxMeleeDistance;
if (enableDebug)
{
if (inRange)
@@ -68,7 +85,7 @@ namespace DemonBoss.Summoner
}
}
return inRange;
return inRange && !canSpawn && !canCast;
}
}
}
}

View File

@@ -0,0 +1,145 @@
using DemonBoss.AI;
using Invector.vCharacterController.AI.FSMBehaviour;
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
namespace DemonBoss.Summoner
{
/// <summary>
/// FSM Action: cast a single fireball with optional overlay clip
/// </summary>
[CreateAssetMenu(menuName = "Invector/FSM/Actions/Summoner/Cast Fireball")]
public class SA_CastFireball : vStateAction
{
public override string categoryName => "Summoner";
public override string defaultName => "Cast Fireball";
[Header("Timing")]
[Tooltip("Optional delay before the fireball is spawned")]
public float castDelay = 0f;
[Header("One-off Overlay Clip (No Animator Params)")]
public AnimationClip overlayClip;
[Tooltip("Playback speed (1 = normal)")]
public float overlaySpeed = 1f;
[Tooltip("Blend-in seconds (instant in this minimal impl)")]
public float overlayFadeIn = 0.10f;
[Tooltip("Blend-out seconds (instant in this minimal impl)")]
public float overlayFadeOut = 0.10f;
[Header("Debug")]
public bool enableDebug = false;
private SummonerAI _summoner;
private bool _castScheduled;
// --- Playables runtime ---
private PlayableGraph _overlayGraph;
private AnimationPlayableOutput _overlayOutput;
private AnimationClipPlayable _overlayPlayable;
private bool _overlayPlaying;
private float _overlayStopAtTime;
public override void DoAction(vIFSMBehaviourController fsm, vFSMComponentExecutionType execType = vFSMComponentExecutionType.OnStateUpdate)
{
if (execType == vFSMComponentExecutionType.OnStateEnter)
{
OnEnter(fsm);
}
else if (execType == vFSMComponentExecutionType.OnStateUpdate)
{
if (_overlayPlaying && Time.time >= _overlayStopAtTime)
{
StopOverlayWithFade();
}
}
else if (execType == vFSMComponentExecutionType.OnStateExit)
{
OnExit();
}
}
private void OnEnter(vIFSMBehaviourController fsm)
{
_summoner = fsm.gameObject.GetComponent<SummonerAI>();
if (_summoner == null)
{
if (enableDebug) Debug.LogWarning("[SA_CastFireball] No SummonerAI component found!");
return;
}
_castScheduled = false;
// Play overlay clip (no Animator params)
PlayOverlayOnce(fsm.transform);
if (castDelay > 0f)
{
fsm.gameObject.AddComponent<DelayedInvoker>().Init(castDelay, SpawnFireballNow);
_castScheduled = true;
}
else
{
SpawnFireballNow();
}
}
private void OnExit()
{
StopOverlayImmediate();
_castScheduled = false;
}
private void SpawnFireballNow()
{
if (_summoner == null) return;
_summoner.CastFireball();
if (enableDebug) Debug.Log("[SA_CastFireball] Fireball cast");
}
// ------------------ Overlay helpers ------------------
private void PlayOverlayOnce(Transform owner)
{
if (overlayClip == null || owner == null) return;
Animator anim = owner.GetComponent<Animator>();
if (anim == null) return;
_overlayGraph = PlayableGraph.Create("ActionOverlay(CastFireball)");
_overlayGraph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
_overlayPlayable = AnimationClipPlayable.Create(_overlayGraph, overlayClip);
_overlayPlayable.SetSpeed(Mathf.Max(0.0001f, overlaySpeed));
_overlayPlayable.SetApplyFootIK(false);
_overlayPlayable.SetApplyPlayableIK(false);
_overlayOutput = AnimationPlayableOutput.Create(_overlayGraph, "AnimOut", anim);
_overlayOutput.SetSourcePlayable(_overlayPlayable);
_overlayOutput.SetWeight(1f);
_overlayGraph.Play();
float duration = (float)overlayClip.length / Mathf.Max(0.0001f, overlaySpeed);
_overlayStopAtTime = Time.time + duration;
_overlayPlaying = true;
}
private void StopOverlayWithFade()
{
StopOverlayImmediate();
}
private void StopOverlayImmediate()
{
if (!_overlayGraph.IsValid()) return;
_overlayGraph.Stop();
_overlayGraph.Destroy();
_overlayPlaying = false;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0ed945c0d54773940ab5191abeac4cd0

View File

@@ -23,6 +23,12 @@ namespace DemonBoss.Summoner
[Header("Behavior")]
[Tooltip("Wait for spawning to complete before allowing state exit")]
public bool waitForCompletion = true;
[Tooltip("If true, spawn starts only after an animation event calls SummonerAI.OnSummonAnimationEvent")]
public bool spawnOnAnimationEvent = true;
[Tooltip("Fallback: start spawn if animation event doesn't fire within this time (seconds). 0 = no fallback.")]
public float animationEventTimeout = 1.2f;
[Header("Debug")]
[Tooltip("Enable debug logging")]
@@ -31,6 +37,8 @@ namespace DemonBoss.Summoner
private SummonerAI summoner;
private Animator animator;
private bool hasStartedSpawning = false;
private float spawnRequestTime = -1f;
private bool spawnTriggered = false;
public override void DoAction(vIFSMBehaviourController fsmBehaviour, vFSMComponentExecutionType executionType = vFSMComponentExecutionType.OnStateUpdate)
{
@@ -73,15 +81,40 @@ namespace DemonBoss.Summoner
}
}
// Start spawning minions
summoner.StartSpawning();
hasStartedSpawning = true;
if (enableDebug) Debug.Log("[SA_SpawnMinions] Started spawning minions");
if (spawnOnAnimationEvent)
{
summoner.RequestSpawn();
hasStartedSpawning = true;
spawnTriggered = false;
spawnRequestTime = Time.time;
if (enableDebug) Debug.Log("[SA_SpawnMinions] Waiting for animation event to spawn");
}
else
{
// Start spawning minions immediately
summoner.StartSpawning();
hasStartedSpawning = true;
spawnTriggered = true;
if (enableDebug) Debug.Log("[SA_SpawnMinions] Started spawning minions");
}
}
private void OnUpdate(vIFSMBehaviourController fsmBehaviour)
{
if (summoner != null && spawnOnAnimationEvent && !spawnTriggered)
{
if (summoner.IsSpawning)
{
spawnTriggered = true;
}
else if (animationEventTimeout > 0f && spawnRequestTime > 0f && (Time.time - spawnRequestTime) >= animationEventTimeout)
{
summoner.StartSpawning();
spawnTriggered = true;
if (enableDebug) Debug.Log("[SA_SpawnMinions] Animation event timeout - spawning fallback");
}
}
// If waiting for completion, keep state active until spawning is done
if (waitForCompletion && summoner != null && summoner.IsSpawning)
{
@@ -107,8 +140,14 @@ namespace DemonBoss.Summoner
summoner.StopSpawning();
if (enableDebug) Debug.Log("[SA_SpawnMinions] Spawning interrupted on state exit");
}
else if (summoner != null)
{
summoner.CancelSpawnRequest();
}
hasStartedSpawning = false;
spawnTriggered = false;
spawnRequestTime = -1f;
if (enableDebug) Debug.Log("[SA_SpawnMinions] State exited");
}
@@ -122,4 +161,4 @@ namespace DemonBoss.Summoner
return hasStartedSpawning && !summoner.IsSpawning;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 8faaed5f0f8beac4193201e791fa0406
guid: 1ff92c6825e7585419de5a79794bc3f2
PrefabImporter:
externalObjects: {}
userData:

View File

@@ -2,6 +2,7 @@ using Invector;
using Invector.vCharacterController.AI;
using System.Collections;
using System.Collections.Generic;
using Lean.Pool;
using UnityEngine;
namespace DemonBoss.Summoner
@@ -43,6 +44,16 @@ namespace DemonBoss.Summoner
[Tooltip("Minimum distance to player before engaging in melee")]
public float meleeEngageDistance = 3f;
[Header("Melee Cooldown")]
[Tooltip("Minimum seconds between melee attacks")]
public float meleeCooldownMin = 5f;
[Tooltip("Maximum seconds between melee attacks")]
public float meleeCooldownMax = 8f;
[Tooltip("Preferred safe distance from player (used for flee/spacing)")]
public float safeDistance = 8f;
[Tooltip("Should summoner fight when minions are alive?")]
public bool fightWithMinions = false;
@@ -61,6 +72,29 @@ namespace DemonBoss.Summoner
[Tooltip("Sound played when spawning minions")]
public AudioClip summonSound;
[Header("Summon Restrictions")]
[Tooltip("If true, summoner will only summon when no minions are alive")]
public bool requireZeroMinionsToSummon = true;
[Header("Spell Casting")]
[Tooltip("Fireball prefab (projectile handles its own targeting)")]
public GameObject fireballPrefab;
[Tooltip("Optional spawn pivot for spells (e.g. staff tip). If null, uses summoner transform.")]
public Transform spellSpawnPivot;
[Tooltip("Cooldown between spell casts (seconds)")]
public float spellCooldown = 6f;
[Tooltip("Minimum distance required to cast spell")]
public float spellMinDistance = 5f;
[Tooltip("Maximum distance allowed to cast spell (0 = no limit)")]
public float spellMaxDistance = 20f;
[Tooltip("Only cast spell when minions are alive")]
public bool spellRequiresMinionsAlive = true;
[Header("Debug")]
[Tooltip("Enable debug logging")]
public bool enableDebug = false;
@@ -76,12 +110,23 @@ namespace DemonBoss.Summoner
private vHealthController healthController;
private bool isSpawning = false;
private Coroutine spawnCoroutine;
private float lastSpellTime = -999f;
private bool spawnRequested = false;
private float nextMeleeTime = 0f;
// Public properties for FSM decisions
public bool IsSpawning => isSpawning;
public int ActiveMinionCount => activeMinions.Count;
public bool CanSpawnMinions => activeMinions.Count < maxActiveMinions && !isSpawning;
public bool CanSpawnMinions
{
get
{
if (isSpawning) return false;
if (requireZeroMinionsToSummon && activeMinions.Count > 0) return false;
return activeMinions.Count < maxActiveMinions;
}
}
public bool HasActiveMinions => activeMinions.Count > 0;
private void Awake()
@@ -125,6 +170,7 @@ namespace DemonBoss.Summoner
/// </summary>
public void StartSpawning()
{
spawnRequested = false;
if (isSpawning)
{
if (enableDebug) Debug.Log("[SummonerAI] Already spawning minions");
@@ -137,9 +183,44 @@ namespace DemonBoss.Summoner
return;
}
if (requireZeroMinionsToSummon && HasActiveMinions)
{
if (enableDebug) Debug.Log("[SummonerAI] Minions alive - summon blocked");
return;
}
spawnCoroutine = StartCoroutine(SpawnMinionsCoroutine());
}
/// <summary>
/// Request spawning to begin on an animation event.
/// </summary>
public void RequestSpawn()
{
spawnRequested = true;
}
/// <summary>
/// Cancel a pending spawn request (e.g., on state exit).
/// </summary>
public void CancelSpawnRequest()
{
spawnRequested = false;
}
/// <summary>
/// Animation event hook. Call from the summon animation.
/// </summary>
public void OnSummonAnimationEvent()
{
if (!spawnRequested)
{
return;
}
StartSpawning();
}
/// <summary>
/// Stop spawning minions immediately
/// </summary>
@@ -282,14 +363,102 @@ namespace DemonBoss.Summoner
return GetDistanceToPlayer() <= meleeEngageDistance;
}
/// <summary>
/// Check if player is within the desired safe distance
/// </summary>
public bool IsPlayerTooCloseForSafeDistance()
{
return GetDistanceToPlayer() < safeDistance;
}
/// <summary>
/// Check if summoner has reached/maintains safe distance
/// </summary>
public bool IsAtSafeDistance()
{
return GetDistanceToPlayer() >= safeDistance;
}
/// <summary>
/// Should summoner try to flee to reach safe distance
/// </summary>
public bool ShouldFleeToSafeDistance()
{
float distance = GetDistanceToPlayer();
if (distance <= meleeEngageDistance) return false;
if (CanSpawnMinions || CanCastSpell()) return false;
return distance < safeDistance;
}
/// <summary>
/// Check if summoner should engage in melee combat
/// </summary>
public bool ShouldEngageMelee()
{
if (!IsPlayerInMeleeRange()) return false;
if (fightWithMinions) return true;
return !HasActiveMinions;
if (!CanMeleeNow()) return false;
return !CanSpawnMinions && !CanCastSpell();
}
public bool CanMeleeNow()
{
return Time.time >= nextMeleeTime;
}
public void NotifyMeleeAttack()
{
float min = Mathf.Min(meleeCooldownMin, meleeCooldownMax);
float max = Mathf.Max(meleeCooldownMin, meleeCooldownMax);
if (max <= 0f)
{
nextMeleeTime = 0f;
return;
}
nextMeleeTime = Time.time + Random.Range(min, max);
}
/// <summary>
/// Check if summoner can cast a ranged spell now
/// </summary>
public bool CanCastSpell()
{
if (isSpawning) return false;
if (fireballPrefab == null) return false;
if (spellRequiresMinionsAlive && !HasActiveMinions) return false;
float distance = GetDistanceToPlayer();
if (distance < spellMinDistance) return false;
if (spellMaxDistance > 0f && distance > spellMaxDistance) return false;
return (Time.time - lastSpellTime) >= spellCooldown;
}
/// <summary>
/// Notify that a spell was cast (updates cooldown timer)
/// </summary>
public void NotifySpellCast()
{
lastSpellTime = Time.time;
}
/// <summary>
/// Spawn a fireball from pivot towards player
/// </summary>
public void CastFireball()
{
if (!CanCastSpell()) return;
Transform pivot = spellSpawnPivot != null ? spellSpawnPivot : transform;
Vector3 targetPos = playerTransform != null ? playerTransform.position + Vector3.up * 1f : (pivot.position + pivot.forward);
Vector3 dir = (targetPos - pivot.position).normalized;
if (dir == Vector3.zero) dir = pivot.forward;
Quaternion rot = Quaternion.LookRotation(dir);
LeanPool.Spawn(fireballPrefab, pivot.position, rot);
NotifySpellCast();
if (enableDebug) Debug.Log("[SummonerAI] Cast fireball");
}
/// <summary>
@@ -327,6 +496,10 @@ namespace DemonBoss.Summoner
Gizmos.color = Color.red;
DrawCircle(transform.position, meleeEngageDistance, 16);
// Draw safe distance
Gizmos.color = Color.yellow;
DrawCircle(transform.position, safeDistance, 24);
// Draw lines to active minions
Gizmos.color = Color.green;
foreach (GameObject minion in activeMinions)
@@ -356,4 +529,4 @@ namespace DemonBoss.Summoner
}
}
}
}
}

View File

@@ -22,7 +22,7 @@ ModelImporter:
animationDoRetargetingWarnings: 0
importAnimatedCustomProperties: 0
importConstraints: 0
animationCompression: 1
animationCompression: 3
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
@@ -33,7 +33,7 @@ ModelImporter:
isReadable: 0
meshes:
lODScreenPercentages: []
globalScale: 1
globalScale: 3
meshCompression: 0
addColliders: 0
useSRGBMaterialColor: 1
@@ -88,16 +88,16 @@ ModelImporter:
armStretch: 0.05
legStretch: 0.05
feetSpacing: 0
globalScale: 1
globalScale: 3
rootMotionBoneName:
hasTranslationDoF: 0
hasExtraRoot: 0
hasExtraRoot: 1
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {instanceID: 0}
autoGenerateAvatarMappingIfUnspecified: 1
animationType: 2
animationType: 3
humanoidOversampling: 1
avatarSetup: 0
avatarSetup: 1
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
importBlendShapeDeformPercent: 1
remapMaterialsIfMaterialImportModeIsNone: 0

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
fileFormatVersion: 2
guid: 49dfe01444f3aeb409a3e3ecc971322c
timeCreated: 1511197476
licenseType: Store
guid: 729b0e7341e674748acfbe93bbe04fec
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 9100000
userData:
assetBundleName:
assetBundleVariant: