装备系统完结,修复并加入很多

This commit is contained in:
2026-04-03 19:15:02 +08:00
parent 538085b64f
commit d9376833b6
378 changed files with 62464 additions and 16756 deletions
+320 -10
View File
@@ -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");
}
}
}