装备系统完结,修复并加入很多
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
@@ -12,7 +13,11 @@ namespace Bansonic
|
||||
{
|
||||
private const string EditorOutputFolder = "Assets/Resources/so/uEquip";
|
||||
private const string RuntimeOutputFolder = "so/uEquip";
|
||||
private const string NextGeneratedIdPrefsKey = "bansonic_equipment_next_id_v1";
|
||||
private const string RuntimeSaveCategory = "runtime_equipment";
|
||||
private const string RuntimeSaveKey = "generated_list";
|
||||
private static readonly List<equipmentSO> RuntimeGeneratedEquipments = new List<equipmentSO>();
|
||||
private static bool runtimeGeneratedLoaded;
|
||||
|
||||
private enum QualityRollMode { Default, High }
|
||||
|
||||
@@ -23,7 +28,81 @@ namespace Bansonic
|
||||
public int skillId;
|
||||
}
|
||||
|
||||
public static IReadOnlyList<equipmentSO> GetRuntimeGeneratedEquipments() => RuntimeGeneratedEquipments;
|
||||
[Serializable]
|
||||
private class RuntimeGeneratedEquipmentListPayload
|
||||
{
|
||||
public List<RuntimeGeneratedEquipmentPayload> items = new List<RuntimeGeneratedEquipmentPayload>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class RuntimeGeneratedEquipmentPayload
|
||||
{
|
||||
public string name;
|
||||
public int skillType;
|
||||
public int level;
|
||||
public string tierNameConfigName;
|
||||
public bool enableTypeSameEffects;
|
||||
public int saSkillId;
|
||||
public int iaSkillId;
|
||||
public StatPayload maxHp;
|
||||
public StatPayload attack;
|
||||
public StatPayload maxMana;
|
||||
public StatPayload damageResistance;
|
||||
public StatPayload scoreEfficiency;
|
||||
public List<EffectPayload> specialEffects = new List<EffectPayload>();
|
||||
public List<EffectPayload> typeSameEffects = new List<EffectPayload>();
|
||||
public List<EffectPayload> illusionEffects = new List<EffectPayload>();
|
||||
public List<EffectPayload> maxLevelEffects = new List<EffectPayload>();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class StatPayload
|
||||
{
|
||||
public float basicGain;
|
||||
public float cultivationInterval;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class EffectPayload
|
||||
{
|
||||
public int effectType;
|
||||
public float value;
|
||||
}
|
||||
|
||||
public static IReadOnlyList<equipmentSO> GetRuntimeGeneratedEquipments()
|
||||
{
|
||||
EnsureRuntimeGeneratedLoaded();
|
||||
return RuntimeGeneratedEquipments;
|
||||
}
|
||||
|
||||
public static equipmentSO RegisterGeneratedEquipment(equipmentSO generated)
|
||||
{
|
||||
return Persist(generated);
|
||||
}
|
||||
|
||||
public static string GenerateUniqueEquipmentName(equipmentSO.EquipmentSkillType type)
|
||||
{
|
||||
return BuildGeneratedName(type);
|
||||
}
|
||||
|
||||
public static void RemoveRuntimeGeneratedEquipment(equipmentSO equipment)
|
||||
{
|
||||
EnsureRuntimeGeneratedLoaded();
|
||||
if (equipment == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RuntimeGeneratedEquipments.RemoveAll(item => item == null || item == equipment || item.name == equipment.name);
|
||||
SaveRuntimeGeneratedState();
|
||||
}
|
||||
|
||||
public static void ClearRuntimeGeneratedPersistence()
|
||||
{
|
||||
RuntimeGeneratedEquipments.Clear();
|
||||
runtimeGeneratedLoaded = true;
|
||||
SecureSaveVault.Delete(RuntimeSaveCategory, RuntimeSaveKey);
|
||||
}
|
||||
|
||||
public static List<equipmentSO> generateEquipment(
|
||||
int quantity,
|
||||
@@ -64,7 +143,11 @@ namespace Bansonic
|
||||
return results;
|
||||
}
|
||||
|
||||
public static equipmentSO GenerateFromSmeltReward(smeltStageRewardSO rewardSo, smeltStageRewardSO.SmeltStageRewardRequirement requirement)
|
||||
public static equipmentSO GenerateFromSmeltReward(
|
||||
smeltStageRewardSO rewardSo,
|
||||
smeltStageRewardSO.SmeltStageRewardRequirement requirement,
|
||||
equipmentSO.EquipmentSkillType? forcedType = null,
|
||||
int forcedSkillGroupId = 0)
|
||||
{
|
||||
if (rewardSo == null || requirement == null || rewardSo.rewardRandomConfig == null)
|
||||
{
|
||||
@@ -75,9 +158,9 @@ namespace Bansonic
|
||||
config.NormalizeRuntimeData();
|
||||
|
||||
equipmentSO generated = CreateBaseEquipment(rewardSo.rewardTemplate);
|
||||
generated.skillType = requirement.equipmentType == smeltStageRewardSO.equipType.selfChosenType
|
||||
generated.skillType = forcedType ?? (requirement.equipmentType == smeltStageRewardSO.equipType.selfChosenType
|
||||
? requirement.chosenSkillType
|
||||
: RollRandomSkillType();
|
||||
: RollRandomSkillType());
|
||||
generated.name = BuildGeneratedName(generated.skillType);
|
||||
generated.level = 0;
|
||||
generated.sa_skillID = 0;
|
||||
@@ -90,7 +173,7 @@ namespace Bansonic
|
||||
ResetBasicGains(generated);
|
||||
GenerateBasicAttributes(generated, config, mode);
|
||||
GenerateTypeSameEffects(generated, config, mode);
|
||||
GenerateSpecialEffects(generated, config, mode, requirement.skillRequirement == smeltStageRewardSO.skillOwned.mustHave);
|
||||
GenerateSpecialEffects(generated, config, mode, requirement.skillRequirement == smeltStageRewardSO.skillOwned.mustHave, forcedSkillGroupId);
|
||||
GenerateIllusionEffects(generated, config, mode);
|
||||
return Persist(generated);
|
||||
}
|
||||
@@ -152,7 +235,7 @@ namespace Bansonic
|
||||
}
|
||||
generated.typeSameEffects = results.ToArray();
|
||||
}
|
||||
private static void GenerateSpecialEffects(equipmentSO generated, equipmentRandomConfigSO config, QualityRollMode mode, bool mustHaveSkill)
|
||||
private static void GenerateSpecialEffects(equipmentSO generated, equipmentRandomConfigSO config, QualityRollMode mode, bool mustHaveSkill, int forcedSkillGroupId = 0)
|
||||
{
|
||||
int count = RollSpecialEffectCount(config);
|
||||
var pool = BuildSpecialEffectPool(generated, config);
|
||||
@@ -173,9 +256,22 @@ namespace Bansonic
|
||||
}
|
||||
|
||||
ResolveDuplicateEffects(generatedEffects);
|
||||
bool hasForcedSkill = forcedSkillGroupId > 0;
|
||||
bool shouldGenerateSkill = mustHaveSkill || UnityEngine.Random.value <= config.sesp;
|
||||
if (shouldGenerateSkill && generatedEffects.Count > 0 && config.TryGetSpecialSkillId(generated.skillType, out int skillId) && skillId > 0)
|
||||
if ((hasForcedSkill || shouldGenerateSkill) && generatedEffects.Count > 0)
|
||||
{
|
||||
int skillId = 0;
|
||||
if (hasForcedSkill)
|
||||
{
|
||||
skillId = forcedSkillGroupId;
|
||||
}
|
||||
else if (!config.TryGetSpecialSkillId(generated.skillType, out skillId) || skillId <= 0)
|
||||
{
|
||||
generated.sa_skillID = 0;
|
||||
generated.specialEffects = BuildGeneratedEffects(generatedEffects);
|
||||
return;
|
||||
}
|
||||
|
||||
int replace = UnityEngine.Random.Range(0, generatedEffects.Count);
|
||||
generatedEffects[replace] = new GeneratedEffectValue { effectType = equipmentSO.EquipmentSpecialEffectType.Skill, value = 0f, skillId = skillId };
|
||||
generated.sa_skillID = skillId;
|
||||
@@ -307,8 +403,10 @@ namespace Bansonic
|
||||
}
|
||||
}
|
||||
#endif
|
||||
EnsureRuntimeGeneratedLoaded();
|
||||
RuntimeGeneratedEquipments.RemoveAll(item => item == null || item.name == generated.name);
|
||||
RuntimeGeneratedEquipments.Add(generated);
|
||||
SaveRuntimeGeneratedState();
|
||||
return generated;
|
||||
}
|
||||
|
||||
@@ -322,7 +420,8 @@ namespace Bansonic
|
||||
|
||||
private static int GetNextGeneratedId()
|
||||
{
|
||||
int maxId = 0;
|
||||
EnsureRuntimeGeneratedLoaded();
|
||||
int maxId = Mathf.Max(0, PlayerPrefs.GetInt(NextGeneratedIdPrefsKey, 0));
|
||||
for (int i = 0; i < RuntimeGeneratedEquipments.Count; i++)
|
||||
{
|
||||
if (RuntimeGeneratedEquipments[i] != null)
|
||||
@@ -350,7 +449,10 @@ namespace Bansonic
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return maxId + 1;
|
||||
int nextId = maxId + 1;
|
||||
PlayerPrefs.SetInt(NextGeneratedIdPrefsKey, nextId);
|
||||
PlayerPrefs.Save();
|
||||
return nextId;
|
||||
}
|
||||
|
||||
private static void TryUpdateMaxId(string fileName, ref int maxId)
|
||||
@@ -440,7 +542,8 @@ namespace Bansonic
|
||||
if (Mathf.Approximately(minValue, maxValue)) return AvoidZero(minValue, maxValue, minValue);
|
||||
if (maxValue < minValue) { float cached = minValue; minValue = maxValue; maxValue = cached; }
|
||||
float span = maxValue - minValue;
|
||||
return AvoidZero(minValue, maxValue, UnityEngine.Random.Range(maxValue - span * 0.2f, maxValue));
|
||||
float tail = Mathf.Max(span * 0.2f, 0.0001f);
|
||||
return AvoidZero(minValue, maxValue, UnityEngine.Random.Range(Mathf.Max(minValue, maxValue - tail), maxValue));
|
||||
}
|
||||
|
||||
private static float RollBiasedValue(float minValue, float maxValue)
|
||||
@@ -506,5 +609,212 @@ namespace Bansonic
|
||||
if (!AssetDatabase.IsValidFolder(EditorOutputFolder)) AssetDatabase.CreateFolder("Assets/Resources/so", "uEquip");
|
||||
}
|
||||
#endif
|
||||
|
||||
private static void EnsureRuntimeGeneratedLoaded()
|
||||
{
|
||||
if (runtimeGeneratedLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
runtimeGeneratedLoaded = true;
|
||||
RuntimeGeneratedEquipments.Clear();
|
||||
|
||||
RuntimeGeneratedEquipmentListPayload payload;
|
||||
if (!SecureSaveVault.TryLoadJson(RuntimeSaveCategory, RuntimeSaveKey, out payload) || payload == null || payload.items == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < payload.items.Count; i++)
|
||||
{
|
||||
RuntimeGeneratedEquipmentPayload itemPayload = payload.items[i];
|
||||
equipmentSO restored = BuildEquipmentFromPayload(itemPayload);
|
||||
if (restored != null)
|
||||
{
|
||||
RuntimeGeneratedEquipments.Add(restored);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void SaveRuntimeGeneratedState()
|
||||
{
|
||||
RuntimeGeneratedEquipmentListPayload payload = new RuntimeGeneratedEquipmentListPayload();
|
||||
for (int i = 0; i < RuntimeGeneratedEquipments.Count; i++)
|
||||
{
|
||||
equipmentSO equipment = RuntimeGeneratedEquipments[i];
|
||||
if (equipment == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
payload.items.Add(BuildPayload(equipment));
|
||||
}
|
||||
|
||||
SecureSaveVault.SaveJson(RuntimeSaveCategory, RuntimeSaveKey, payload);
|
||||
}
|
||||
|
||||
private static RuntimeGeneratedEquipmentPayload BuildPayload(equipmentSO equipment)
|
||||
{
|
||||
return new RuntimeGeneratedEquipmentPayload
|
||||
{
|
||||
name = equipment.name ?? string.Empty,
|
||||
skillType = (int)equipment.skillType,
|
||||
level = equipment.level,
|
||||
tierNameConfigName = equipment.tierNameConfig != null ? equipment.tierNameConfig.name : string.Empty,
|
||||
enableTypeSameEffects = equipment.enableTypeSameEffects,
|
||||
saSkillId = equipment.sa_skillID,
|
||||
iaSkillId = equipment.ia_skillID,
|
||||
maxHp = BuildStatPayload(equipment.maxHp),
|
||||
attack = BuildStatPayload(equipment.attack),
|
||||
maxMana = BuildStatPayload(equipment.maxMana),
|
||||
damageResistance = BuildStatPayload(equipment.damageResistance),
|
||||
scoreEfficiency = BuildStatPayload(equipment.scoreEfficiency),
|
||||
specialEffects = BuildEffectPayloads(equipment.specialEffects),
|
||||
typeSameEffects = BuildEffectPayloads(equipment.typeSameEffects),
|
||||
illusionEffects = BuildEffectPayloads(equipment.illusionEffects),
|
||||
maxLevelEffects = BuildEffectPayloads(equipment.maxLevelEffects)
|
||||
};
|
||||
}
|
||||
|
||||
private static equipmentSO BuildEquipmentFromPayload(RuntimeGeneratedEquipmentPayload payload)
|
||||
{
|
||||
if (payload == null || string.IsNullOrWhiteSpace(payload.name))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
equipmentSO equipment = ScriptableObject.CreateInstance<equipmentSO>();
|
||||
equipment.name = payload.name;
|
||||
equipment.skillType = (equipmentSO.EquipmentSkillType)Mathf.Clamp(payload.skillType, 0, Enum.GetValues(typeof(equipmentSO.EquipmentSkillType)).Length - 1);
|
||||
equipment.level = Mathf.Max(0, payload.level);
|
||||
equipment.tierNameConfig = ResolveTierNameConfig(payload.tierNameConfigName);
|
||||
equipment.enableTypeSameEffects = payload.enableTypeSameEffects;
|
||||
equipment.sa_skillID = Mathf.Max(0, payload.saSkillId);
|
||||
equipment.ia_skillID = Mathf.Max(0, payload.iaSkillId);
|
||||
ApplyStatPayload(equipment.maxHp, payload.maxHp);
|
||||
ApplyStatPayload(equipment.attack, payload.attack);
|
||||
ApplyStatPayload(equipment.maxMana, payload.maxMana);
|
||||
ApplyStatPayload(equipment.damageResistance, payload.damageResistance);
|
||||
ApplyStatPayload(equipment.scoreEfficiency, payload.scoreEfficiency);
|
||||
equipment.specialEffects = BuildEffectsFromPayload(payload.specialEffects);
|
||||
equipment.typeSameEffects = BuildEffectsFromPayload(payload.typeSameEffects);
|
||||
equipment.illusionEffects = BuildEffectsFromPayload(payload.illusionEffects);
|
||||
equipment.maxLevelEffects = BuildEffectsFromPayload(payload.maxLevelEffects);
|
||||
equipment.NormalizeIllusionEffectsInPlace();
|
||||
equipment.hideFlags = HideFlags.None;
|
||||
return equipment;
|
||||
}
|
||||
|
||||
private static StatPayload BuildStatPayload(equipmentSO.EquipmentStatTuning tuning)
|
||||
{
|
||||
return new StatPayload
|
||||
{
|
||||
basicGain = tuning != null ? tuning.basicGain : 0f,
|
||||
cultivationInterval = tuning != null ? tuning.cultivationInterval : 0f
|
||||
};
|
||||
}
|
||||
|
||||
private static void ApplyStatPayload(equipmentSO.EquipmentStatTuning tuning, StatPayload payload)
|
||||
{
|
||||
if (tuning == null || payload == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
tuning.basicGain = payload.basicGain;
|
||||
tuning.cultivationInterval = payload.cultivationInterval;
|
||||
}
|
||||
|
||||
private static List<EffectPayload> BuildEffectPayloads(equipmentSO.EquipmentSpecialEffect[] effects)
|
||||
{
|
||||
List<EffectPayload> payloads = new List<EffectPayload>();
|
||||
if (effects == null)
|
||||
{
|
||||
return payloads;
|
||||
}
|
||||
|
||||
for (int i = 0; i < effects.Length; i++)
|
||||
{
|
||||
equipmentSO.EquipmentSpecialEffect effect = effects[i];
|
||||
if (effect == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
payloads.Add(new EffectPayload
|
||||
{
|
||||
effectType = (int)effect.effectType,
|
||||
value = effect.value
|
||||
});
|
||||
}
|
||||
|
||||
return payloads;
|
||||
}
|
||||
|
||||
private static equipmentSO.EquipmentSpecialEffect[] BuildEffectsFromPayload(List<EffectPayload> payloads)
|
||||
{
|
||||
if (payloads == null || payloads.Count == 0)
|
||||
{
|
||||
return Array.Empty<equipmentSO.EquipmentSpecialEffect>();
|
||||
}
|
||||
|
||||
equipmentSO.EquipmentSpecialEffect[] effects = new equipmentSO.EquipmentSpecialEffect[payloads.Count];
|
||||
for (int i = 0; i < payloads.Count; i++)
|
||||
{
|
||||
EffectPayload payload = payloads[i];
|
||||
effects[i] = new equipmentSO.EquipmentSpecialEffect
|
||||
{
|
||||
effectType = (equipmentSO.EquipmentSpecialEffectType)Mathf.Clamp(payload.effectType, 0, Enum.GetValues(typeof(equipmentSO.EquipmentSpecialEffectType)).Length - 1),
|
||||
value = payload.value
|
||||
};
|
||||
}
|
||||
|
||||
return effects;
|
||||
}
|
||||
|
||||
private static equipmentTierNameConfigSO ResolveTierNameConfig(string configName)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(configName))
|
||||
{
|
||||
string[] guids = AssetDatabase.FindAssets($"t:equipmentTierNameConfigSO {configName}");
|
||||
for (int i = 0; i < guids.Length; i++)
|
||||
{
|
||||
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
|
||||
equipmentTierNameConfigSO config = AssetDatabase.LoadAssetAtPath<equipmentTierNameConfigSO>(path);
|
||||
if (config != null && string.Equals(config.name, configName, StringComparison.Ordinal))
|
||||
{
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
equipmentTierNameConfigSO directEditorConfig = AssetDatabase.LoadAssetAtPath<equipmentTierNameConfigSO>("Assets/_eqpmtSys/EquipmentTierNameConfig.asset");
|
||||
if (directEditorConfig != null)
|
||||
{
|
||||
return directEditorConfig;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (string.IsNullOrWhiteSpace(configName))
|
||||
{
|
||||
return Resources.Load<equipmentTierNameConfigSO>("EquipmentTierNameConfig");
|
||||
}
|
||||
|
||||
equipmentTierNameConfigSO[] configs = Resources.LoadAll<equipmentTierNameConfigSO>(string.Empty);
|
||||
for (int i = 0; i < configs.Length; i++)
|
||||
{
|
||||
if (configs[i] != null && string.Equals(configs[i].name, configName, StringComparison.Ordinal))
|
||||
{
|
||||
return configs[i];
|
||||
}
|
||||
}
|
||||
|
||||
return Resources.Load<equipmentTierNameConfigSO>("EquipmentTierNameConfig");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user