8.30
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
/// <summary>
|
||||
/// 存档中的角色。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public struct CharacterSave
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色 ID,对应 CharacterConfig.Id。
|
||||
/// </summary>
|
||||
public int characterId;
|
||||
|
||||
/// <summary>
|
||||
/// 武器栏物品 ID,0 表示空栏。
|
||||
/// </summary>
|
||||
public int weaponItemId;
|
||||
|
||||
/// <summary>
|
||||
/// 防具栏物品 ID,0 表示空栏。
|
||||
/// </summary>
|
||||
public int armorItemId;
|
||||
|
||||
public CharacterSave(int characterId, int weaponItemId, int armorItemId)
|
||||
{
|
||||
this.characterId = characterId;
|
||||
this.weaponItemId = weaponItemId;
|
||||
this.armorItemId = armorItemId;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f585fae70a14d446ba433f3244efded1
|
||||
guid: 431023ff1288d45a9a8a3713cd38593e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
/// <summary>
|
||||
/// 物品堆叠。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public struct ItemStack
|
||||
{
|
||||
/// <summary>
|
||||
/// 物品 ID,对应 ItemConfig.Id。
|
||||
/// </summary>
|
||||
public int itemId;
|
||||
|
||||
/// <summary>
|
||||
/// 数量,不超过配表 ItemConfig.StackLimit。
|
||||
/// </summary>
|
||||
public int count;
|
||||
|
||||
public ItemStack(int itemId, int count)
|
||||
{
|
||||
this.itemId = itemId;
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4774c8ef6d24f489c8c5858aa014ff13
|
||||
guid: 48bca35b200a444218a36ce1a49a76ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
/// <summary>
|
||||
/// 战备配置。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public sealed class LoadoutSave
|
||||
{
|
||||
/// <summary>
|
||||
/// 出战角色 ID 及顺序,1~4 人,顺序决定同速时的行动次序。
|
||||
/// </summary>
|
||||
public int[] partyCharacterIds;
|
||||
|
||||
/// <summary>
|
||||
/// 携带进入地图的物品,开局时填充共享背包;首版无局内效果。
|
||||
/// </summary>
|
||||
public List<ItemStack> carriedItems;
|
||||
|
||||
/// <summary>
|
||||
/// 本局难度,对应 DifficultyConfig 主键。
|
||||
/// </summary>
|
||||
public DifficultyTier difficultyId;
|
||||
|
||||
/// <summary>
|
||||
/// 补齐缺失字段,避免反序列化后出现空引用。
|
||||
/// </summary>
|
||||
public void Normalize()
|
||||
{
|
||||
if (partyCharacterIds == null)
|
||||
{
|
||||
partyCharacterIds = System.Array.Empty<int>();
|
||||
}
|
||||
|
||||
if (carriedItems == null)
|
||||
{
|
||||
carriedItems = new List<ItemStack>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba271361c636f48edb5d7d8ba15a595c
|
||||
guid: bb9f7c288b0da4b88b83e82c87418550
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,43 @@
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
/// <summary>
|
||||
/// 已结束单局的结算记录。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public struct RunRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// 结算结果。
|
||||
/// </summary>
|
||||
public RunResultType outcome;
|
||||
|
||||
/// <summary>
|
||||
/// 本局难度。
|
||||
/// </summary>
|
||||
public DifficultyTier difficultyId;
|
||||
|
||||
/// <summary>
|
||||
/// 本局使用的随机数。
|
||||
/// </summary>
|
||||
public long seed;
|
||||
|
||||
/// <summary>
|
||||
/// 进入单局时间,Unix 毫秒。
|
||||
/// </summary>
|
||||
public long startedAt;
|
||||
|
||||
/// <summary>
|
||||
/// 结算时间,Unix 毫秒。
|
||||
/// </summary>
|
||||
public long endedAt;
|
||||
|
||||
public RunRecord(RunResultType outcome, DifficultyTier difficultyId, long seed, long startedAt, long endedAt)
|
||||
{
|
||||
this.outcome = outcome;
|
||||
this.difficultyId = difficultyId;
|
||||
this.seed = seed;
|
||||
this.startedAt = startedAt;
|
||||
this.endedAt = endedAt;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bffe339530c484a4b83162e20f163ed8
|
||||
guid: 591a205ef9e5c4f5f9fadcbc5b0db979
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,104 @@
|
||||
using System.Collections.Generic;
|
||||
using GameFramework;
|
||||
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
/// <summary>
|
||||
/// 游戏存档根数据。
|
||||
/// 对应 Docs/Tech/02_SaveData.md。
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public sealed class SaveData
|
||||
{
|
||||
/// <summary>
|
||||
/// 当前存档结构版本。
|
||||
/// </summary>
|
||||
public const int CurrentVersion = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 存档结构版本。
|
||||
/// </summary>
|
||||
public int version = CurrentVersion;
|
||||
|
||||
/// <summary>
|
||||
/// 最后写入时间,Unix 毫秒。
|
||||
/// </summary>
|
||||
public long updatedAt;
|
||||
|
||||
/// <summary>
|
||||
/// 主仓库内容,无容量上限。
|
||||
/// </summary>
|
||||
public List<ItemStack> mainWarehouse;
|
||||
|
||||
/// <summary>
|
||||
/// 拥有的角色,数组顺序即入队顺序。
|
||||
/// </summary>
|
||||
public List<CharacterSave> characters;
|
||||
|
||||
/// <summary>
|
||||
/// 当前战备配置。
|
||||
/// </summary>
|
||||
public LoadoutSave loadout;
|
||||
|
||||
/// <summary>
|
||||
/// 已结束单局的结算记录。
|
||||
/// </summary>
|
||||
public List<RunRecord> runHistory;
|
||||
|
||||
/// <summary>
|
||||
/// 序列化为 JSON 字符串。
|
||||
/// </summary>
|
||||
public string ToJson()
|
||||
{
|
||||
return GameFramework.Utility.Json.ToJson(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从 JSON 字符串反序列化;json 为空或反序列化失败时返回 null。
|
||||
/// </summary>
|
||||
public static SaveData FromJson(string json)
|
||||
{
|
||||
if (string.IsNullOrEmpty(json))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
SaveData saveData = GameFramework.Utility.Json.ToObject<SaveData>(json);
|
||||
if (saveData == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
saveData.Normalize();
|
||||
return saveData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 补齐缺失字段,避免反序列化后出现空引用。
|
||||
/// </summary>
|
||||
private void Normalize()
|
||||
{
|
||||
if (mainWarehouse == null)
|
||||
{
|
||||
mainWarehouse = new List<ItemStack>();
|
||||
}
|
||||
|
||||
if (characters == null)
|
||||
{
|
||||
characters = new List<CharacterSave>();
|
||||
}
|
||||
|
||||
if (loadout == null)
|
||||
{
|
||||
loadout = new LoadoutSave();
|
||||
}
|
||||
|
||||
loadout.Normalize();
|
||||
|
||||
if (runHistory == null)
|
||||
{
|
||||
runHistory = new List<RunRecord>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2bfe2058edce460abc5e5054b5f7a7a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
public enum SceneType : byte
|
||||
{
|
||||
Launch = 0,
|
||||
Menu = 1,
|
||||
Main = 2,
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20fc28f41ef04f8fa4fbfb9189b58d0d
|
||||
timeCreated: 1768899171
|
||||
@@ -1,30 +0,0 @@
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
/// <summary>
|
||||
/// 界面编号。
|
||||
/// </summary>
|
||||
public enum UIFormType : byte
|
||||
{
|
||||
Undefined = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 弹出框。
|
||||
/// </summary>
|
||||
DialogForm = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 主菜单。
|
||||
/// </summary>
|
||||
MenuForm = 100,
|
||||
|
||||
/// <summary>
|
||||
/// 设置。
|
||||
/// </summary>
|
||||
SettingForm = 101,
|
||||
|
||||
/// <summary>
|
||||
/// 关于。
|
||||
/// </summary>
|
||||
AboutForm = 102,
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75fd10c7585513846ab25372be0590b7
|
||||
timeCreated: 1528026162
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ceade84509cfa498a91c9a2fe55cc189
|
||||
guid: ef320c3d6ef364abc8210ec6e2be2be6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9618a0e69480c40b383585e41cda54a1
|
||||
guid: 4dccdfac7eea44c07b87a556527040b6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,34 @@
|
||||
using GameFramework;
|
||||
using GameFramework.Event;
|
||||
|
||||
namespace SepCore.Base
|
||||
{
|
||||
public class WarehouseSlotItemClickEventArgs : GameEventArgs
|
||||
{
|
||||
public static int EventId => typeof(WarehouseSlotItemClickEventArgs).GetHashCode();
|
||||
|
||||
public override int Id => EventId;
|
||||
|
||||
/// <summary>
|
||||
/// 被点击格子在整个固定网格中的索引,唯一对应一个格子。
|
||||
/// </summary>
|
||||
public int SlotId { get; private set; }
|
||||
|
||||
public WarehouseSlotItemClickEventArgs()
|
||||
{
|
||||
SlotId = 0;
|
||||
}
|
||||
|
||||
public static WarehouseSlotItemClickEventArgs Create(int slotId)
|
||||
{
|
||||
var args = ReferencePool.Acquire<WarehouseSlotItemClickEventArgs>();
|
||||
args.SlotId = slotId;
|
||||
return args;
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
SlotId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 196c6541cd4d447d6b951f3e8f06c083
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Luban;
|
||||
|
||||
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
public sealed partial class FormatText : Luban.BeanBase
|
||||
{
|
||||
public FormatText(ByteBuf _buf)
|
||||
{
|
||||
Name = _buf.ReadString();
|
||||
Format = _buf.ReadString();
|
||||
}
|
||||
|
||||
public static FormatText DeserializeFormatText(ByteBuf _buf)
|
||||
{
|
||||
return new FormatText(_buf);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文本名
|
||||
/// </summary>
|
||||
public readonly string Name;
|
||||
/// <summary>
|
||||
/// 格式化字符串
|
||||
/// </summary>
|
||||
public readonly string Format;
|
||||
|
||||
public const int __ID__ = -1977697820;
|
||||
public override int GetTypeId() => __ID__;
|
||||
|
||||
public void ResolveRef(Tables tables)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{ "
|
||||
+ "name:" + Name + ","
|
||||
+ "format:" + Format + ","
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5b0b070e5621408e9aa0b909cab1f1b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -22,6 +22,7 @@ public sealed partial class GlobalConfig : Luban.BeanBase
|
||||
EnemyLoseTargetMs = _buf.ReadInt();
|
||||
EnemyFrontViewAngle = _buf.ReadInt();
|
||||
AlertMax = _buf.ReadInt();
|
||||
WarehouseSlotCount = _buf.ReadInt();
|
||||
BackpackSlotCount = _buf.ReadInt();
|
||||
SecureSlotCount = _buf.ReadInt();
|
||||
MinPlayerPartySize = _buf.ReadInt();
|
||||
@@ -67,6 +68,10 @@ public sealed partial class GlobalConfig : Luban.BeanBase
|
||||
/// </summary>
|
||||
public readonly int AlertMax;
|
||||
/// <summary>
|
||||
/// 仓库格子数
|
||||
/// </summary>
|
||||
public readonly int WarehouseSlotCount;
|
||||
/// <summary>
|
||||
/// 共享背包格子数
|
||||
/// </summary>
|
||||
public readonly int BackpackSlotCount;
|
||||
@@ -143,6 +148,7 @@ public sealed partial class GlobalConfig : Luban.BeanBase
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@@ -154,6 +160,7 @@ public sealed partial class GlobalConfig : Luban.BeanBase
|
||||
+ "enemyLoseTargetMs:" + EnemyLoseTargetMs + ","
|
||||
+ "enemyFrontViewAngle:" + EnemyFrontViewAngle + ","
|
||||
+ "alertMax:" + AlertMax + ","
|
||||
+ "warehouseSlotCount:" + WarehouseSlotCount + ","
|
||||
+ "backpackSlotCount:" + BackpackSlotCount + ","
|
||||
+ "secureSlotCount:" + SecureSlotCount + ","
|
||||
+ "minPlayerPartySize:" + MinPlayerPartySize + ","
|
||||
|
||||
@@ -26,6 +26,7 @@ public sealed partial class ItemConfig : Luban.BeanBase
|
||||
MaxMpBonus = _buf.ReadInt();
|
||||
AtkBonus = _buf.ReadInt();
|
||||
MatBonus = _buf.ReadInt();
|
||||
SpeedBonus = _buf.ReadInt();
|
||||
}
|
||||
|
||||
public static ItemConfig DeserializeItemConfig(ByteBuf _buf)
|
||||
@@ -73,6 +74,10 @@ public sealed partial class ItemConfig : Luban.BeanBase
|
||||
/// MAT修正
|
||||
/// </summary>
|
||||
public readonly int MatBonus;
|
||||
/// <summary>
|
||||
/// SPD修正
|
||||
/// </summary>
|
||||
public readonly int SpeedBonus;
|
||||
|
||||
public const int __ID__ = -764023723;
|
||||
public override int GetTypeId() => __ID__;
|
||||
@@ -89,6 +94,7 @@ public sealed partial class ItemConfig : Luban.BeanBase
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
@@ -104,6 +110,7 @@ public sealed partial class ItemConfig : Luban.BeanBase
|
||||
+ "maxMpBonus:" + MaxMpBonus + ","
|
||||
+ "atkBonus:" + AtkBonus + ","
|
||||
+ "matBonus:" + MatBonus + ","
|
||||
+ "speedBonus:" + SpeedBonus + ","
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public sealed partial class SceneConfig : Luban.BeanBase
|
||||
{
|
||||
public SceneConfig(ByteBuf _buf)
|
||||
{
|
||||
Id = _buf.ReadInt();
|
||||
Id = (SceneType)_buf.ReadInt();
|
||||
AssetName = _buf.ReadString();
|
||||
BackgroundMusicId = _buf.ReadInt();
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public sealed partial class SceneConfig : Luban.BeanBase
|
||||
/// <summary>
|
||||
/// 场景编号
|
||||
/// </summary>
|
||||
public readonly int Id;
|
||||
public readonly SceneType Id;
|
||||
/// <summary>
|
||||
/// 资源名称
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
/// <summary>
|
||||
/// 场景类型
|
||||
/// </summary>
|
||||
public enum SceneType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 启动场景
|
||||
/// </summary>
|
||||
Launch = 0,
|
||||
/// <summary>
|
||||
/// 菜单场景
|
||||
/// </summary>
|
||||
Menu = 1,
|
||||
/// <summary>
|
||||
/// 主场景
|
||||
/// </summary>
|
||||
Main = 2,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab1610b60f3ea4315a395afa38cc1ca5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -14,9 +14,10 @@ namespace SepCore.Definition
|
||||
public partial class Tables
|
||||
{
|
||||
/// <summary>
|
||||
/// 全局固定规则
|
||||
/// 全局零散配置(单例)
|
||||
/// </summary>
|
||||
public TbGlobalConfig TbGlobalConfig {get; }
|
||||
public TbFormatText TbFormatText {get; }
|
||||
/// <summary>
|
||||
/// 稀有度搜索时间
|
||||
/// </summary>
|
||||
@@ -85,6 +86,7 @@ public partial class Tables
|
||||
public Tables(System.Func<string, ByteBuf> loader)
|
||||
{
|
||||
TbGlobalConfig = new TbGlobalConfig(loader("tbglobalconfig"));
|
||||
TbFormatText = new TbFormatText(loader("tbformattext"));
|
||||
TbRarityConfig = new TbRarityConfig(loader("tbrarityconfig"));
|
||||
TbDifficultyConfig = new TbDifficultyConfig(loader("tbdifficultyconfig"));
|
||||
TbCharacterConfig = new TbCharacterConfig(loader("tbcharacterconfig"));
|
||||
@@ -107,6 +109,7 @@ public partial class Tables
|
||||
private void ResolveRef()
|
||||
{
|
||||
TbGlobalConfig.ResolveRef(this);
|
||||
TbFormatText.ResolveRef(this);
|
||||
TbRarityConfig.ResolveRef(this);
|
||||
TbDifficultyConfig.ResolveRef(this);
|
||||
TbCharacterConfig.ResolveRef(this);
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Luban;
|
||||
|
||||
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
public partial class TbFormatText
|
||||
{
|
||||
private readonly System.Collections.Generic.Dictionary<string, FormatText> _dataMap;
|
||||
private readonly System.Collections.Generic.List<FormatText> _dataList;
|
||||
|
||||
public TbFormatText(ByteBuf _buf)
|
||||
{
|
||||
_dataMap = new System.Collections.Generic.Dictionary<string, FormatText>();
|
||||
_dataList = new System.Collections.Generic.List<FormatText>();
|
||||
|
||||
for(int n = _buf.ReadSize() ; n > 0 ; --n)
|
||||
{
|
||||
FormatText _v;
|
||||
_v = FormatText.DeserializeFormatText(_buf);
|
||||
_dataList.Add(_v);
|
||||
_dataMap.Add(_v.Name, _v);
|
||||
}
|
||||
}
|
||||
|
||||
public System.Collections.Generic.Dictionary<string, FormatText> DataMap => _dataMap;
|
||||
public System.Collections.Generic.List<FormatText> DataList => _dataList;
|
||||
|
||||
public FormatText GetOrDefault(string key) => _dataMap.TryGetValue(key, out var v) ? v : null;
|
||||
public FormatText Get(string key) => _dataMap[key];
|
||||
public FormatText this[string key] => _dataMap[key];
|
||||
|
||||
public void ResolveRef(Tables tables)
|
||||
{
|
||||
foreach(var _v in _dataList)
|
||||
{
|
||||
_v.ResolveRef(tables);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d39bcaec55e074ab7a226678e837d3e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -13,7 +13,7 @@ using Luban;
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
/// <summary>
|
||||
/// 全局固定规则
|
||||
/// 全局零散配置(单例)
|
||||
/// </summary>
|
||||
public partial class TbGlobalConfig
|
||||
{
|
||||
@@ -55,6 +55,10 @@ public partial class TbGlobalConfig
|
||||
/// </summary>
|
||||
public int AlertMax => _data.AlertMax;
|
||||
/// <summary>
|
||||
/// 仓库格子数
|
||||
/// </summary>
|
||||
public int WarehouseSlotCount => _data.WarehouseSlotCount;
|
||||
/// <summary>
|
||||
/// 共享背包格子数
|
||||
/// </summary>
|
||||
public int BackpackSlotCount => _data.BackpackSlotCount;
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace SepCore.Definition
|
||||
/// </summary>
|
||||
public partial class TbSceneConfig
|
||||
{
|
||||
private readonly System.Collections.Generic.Dictionary<int, SceneConfig> _dataMap;
|
||||
private readonly System.Collections.Generic.Dictionary<SceneType, SceneConfig> _dataMap;
|
||||
private readonly System.Collections.Generic.List<SceneConfig> _dataList;
|
||||
|
||||
public TbSceneConfig(ByteBuf _buf)
|
||||
{
|
||||
_dataMap = new System.Collections.Generic.Dictionary<int, SceneConfig>();
|
||||
_dataMap = new System.Collections.Generic.Dictionary<SceneType, SceneConfig>();
|
||||
_dataList = new System.Collections.Generic.List<SceneConfig>();
|
||||
|
||||
for(int n = _buf.ReadSize() ; n > 0 ; --n)
|
||||
@@ -34,12 +34,12 @@ public partial class TbSceneConfig
|
||||
}
|
||||
}
|
||||
|
||||
public System.Collections.Generic.Dictionary<int, SceneConfig> DataMap => _dataMap;
|
||||
public System.Collections.Generic.Dictionary<SceneType, SceneConfig> DataMap => _dataMap;
|
||||
public System.Collections.Generic.List<SceneConfig> DataList => _dataList;
|
||||
|
||||
public SceneConfig GetOrDefault(int key) => _dataMap.TryGetValue(key, out var v) ? v : null;
|
||||
public SceneConfig Get(int key) => _dataMap[key];
|
||||
public SceneConfig this[int key] => _dataMap[key];
|
||||
public SceneConfig GetOrDefault(SceneType key) => _dataMap.TryGetValue(key, out var v) ? v : null;
|
||||
public SceneConfig Get(SceneType key) => _dataMap[key];
|
||||
public SceneConfig this[SceneType key] => _dataMap[key];
|
||||
|
||||
public void ResolveRef(Tables tables)
|
||||
{
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace SepCore.Definition
|
||||
/// </summary>
|
||||
public partial class TbUIFormConfig
|
||||
{
|
||||
private readonly System.Collections.Generic.Dictionary<int, UIFormConfig> _dataMap;
|
||||
private readonly System.Collections.Generic.Dictionary<UIFormType, UIFormConfig> _dataMap;
|
||||
private readonly System.Collections.Generic.List<UIFormConfig> _dataList;
|
||||
|
||||
public TbUIFormConfig(ByteBuf _buf)
|
||||
{
|
||||
_dataMap = new System.Collections.Generic.Dictionary<int, UIFormConfig>();
|
||||
_dataMap = new System.Collections.Generic.Dictionary<UIFormType, UIFormConfig>();
|
||||
_dataList = new System.Collections.Generic.List<UIFormConfig>();
|
||||
|
||||
for(int n = _buf.ReadSize() ; n > 0 ; --n)
|
||||
@@ -34,12 +34,12 @@ public partial class TbUIFormConfig
|
||||
}
|
||||
}
|
||||
|
||||
public System.Collections.Generic.Dictionary<int, UIFormConfig> DataMap => _dataMap;
|
||||
public System.Collections.Generic.Dictionary<UIFormType, UIFormConfig> DataMap => _dataMap;
|
||||
public System.Collections.Generic.List<UIFormConfig> DataList => _dataList;
|
||||
|
||||
public UIFormConfig GetOrDefault(int key) => _dataMap.TryGetValue(key, out var v) ? v : null;
|
||||
public UIFormConfig Get(int key) => _dataMap[key];
|
||||
public UIFormConfig this[int key] => _dataMap[key];
|
||||
public UIFormConfig GetOrDefault(UIFormType key) => _dataMap.TryGetValue(key, out var v) ? v : null;
|
||||
public UIFormConfig Get(UIFormType key) => _dataMap[key];
|
||||
public UIFormConfig this[UIFormType key] => _dataMap[key];
|
||||
|
||||
public void ResolveRef(Tables tables)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ public sealed partial class UIFormConfig : Luban.BeanBase
|
||||
{
|
||||
public UIFormConfig(ByteBuf _buf)
|
||||
{
|
||||
Id = _buf.ReadInt();
|
||||
Id = (UIFormType)_buf.ReadInt();
|
||||
AssetName = _buf.ReadString();
|
||||
UIGroupName = _buf.ReadString();
|
||||
AllowMultiInstance = _buf.ReadBool();
|
||||
@@ -31,7 +31,7 @@ public sealed partial class UIFormConfig : Luban.BeanBase
|
||||
/// <summary>
|
||||
/// 界面编号
|
||||
/// </summary>
|
||||
public readonly int Id;
|
||||
public readonly UIFormType Id;
|
||||
/// <summary>
|
||||
/// 资源名称
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
/// <summary>
|
||||
/// 界面类型
|
||||
/// </summary>
|
||||
public enum UIFormType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 未定义
|
||||
/// </summary>
|
||||
Undefined = 0,
|
||||
/// <summary>
|
||||
/// 弹出框
|
||||
/// </summary>
|
||||
DialogForm = 1,
|
||||
/// <summary>
|
||||
/// 大厅界面
|
||||
/// </summary>
|
||||
LobbyForm = 100,
|
||||
/// <summary>
|
||||
/// 设置
|
||||
/// </summary>
|
||||
SettingForm = 101,
|
||||
/// <summary>
|
||||
/// 关于
|
||||
/// </summary>
|
||||
AboutForm = 102,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d9c04bb114b74ef4a6c4e0985d7b31a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -326,14 +326,14 @@ namespace SepCore.Editor
|
||||
for (int i = 0; i < batch.entries.Count; i++)
|
||||
{
|
||||
PendingGeneration pending = batch.entries[i];
|
||||
Type viewType = FindViewType(pending.viewClassFullName);
|
||||
Type viewType = FindGeneratedType(pending.viewClassFullName);
|
||||
if (viewType == null)
|
||||
{
|
||||
Debug.LogError("Generated UI view type was not found after compilation: " + pending.viewClassFullName);
|
||||
return;
|
||||
}
|
||||
|
||||
Type formType = FindViewType(pending.formClassFullName);
|
||||
Type formType = FindGeneratedType(pending.formClassFullName);
|
||||
if (formType == null)
|
||||
{
|
||||
Debug.LogError("Generated UI form type was not found after compilation: " + pending.formClassFullName);
|
||||
@@ -401,9 +401,9 @@ namespace SepCore.Editor
|
||||
}
|
||||
|
||||
current.RefreshItems();
|
||||
for (int i = 0; i < current.NestedViewReferences.Count; i++)
|
||||
for (int i = 0; i < current.NestedFormReferences.Count; i++)
|
||||
{
|
||||
UISerializationRoot nestedRoot = current.NestedViewReferences[i].Root;
|
||||
UISerializationRoot nestedRoot = current.NestedFormReferences[i].Root;
|
||||
if (nestedRoot != null)
|
||||
{
|
||||
CollectGenerationRootsRecursive(nestedRoot, persistentContext, visited, result);
|
||||
@@ -519,9 +519,9 @@ namespace SepCore.Editor
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < root.NestedViewReferences.Count; i++)
|
||||
for (int i = 0; i < root.NestedFormReferences.Count; i++)
|
||||
{
|
||||
UISerializationRoot.NestedViewReference reference = root.NestedViewReferences[i];
|
||||
UISerializationRoot.NestedFormReference reference = root.NestedFormReferences[i];
|
||||
if (reference == null || !reference.GenerateReference)
|
||||
{
|
||||
continue;
|
||||
@@ -530,7 +530,7 @@ namespace SepCore.Editor
|
||||
UISerializationRoot nestedRoot = reference.Root;
|
||||
if (nestedRoot == null)
|
||||
{
|
||||
throw new InvalidOperationException("A nested UI View reference is missing below " + GetHierarchyPath(root.transform) + ".");
|
||||
throw new InvalidOperationException("A nested UI Form reference is missing below " + GetHierarchyPath(root.transform) + ".");
|
||||
}
|
||||
|
||||
string variableName = NormalizeAndValidateVariableName(reference.VariableName, nestedRoot.transform, names);
|
||||
@@ -538,7 +538,7 @@ namespace SepCore.Editor
|
||||
{
|
||||
nestedRoot = nestedRoot,
|
||||
variableName = variableName,
|
||||
csharpTypeName = "global::" + GeneratedNamespace + "." + GetViewClassName(nestedRoot)
|
||||
csharpTypeName = "global::" + GeneratedNamespace + "." + GetFormClassName(nestedRoot)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -679,17 +679,17 @@ namespace SepCore.Editor
|
||||
}
|
||||
|
||||
root.RefreshItems();
|
||||
for (int i = 0; i < root.NestedViewReferences.Count; i++)
|
||||
for (int i = 0; i < root.NestedFormReferences.Count; i++)
|
||||
{
|
||||
UISerializationRoot nestedRoot = root.NestedViewReferences[i].Root;
|
||||
UISerializationRoot nestedRoot = root.NestedFormReferences[i].Root;
|
||||
if (nestedRoot != null)
|
||||
{
|
||||
ApplyGeneratedComponentsToRoot(nestedRoot);
|
||||
}
|
||||
}
|
||||
|
||||
Type viewType = FindViewType(GeneratedNamespace + "." + GetViewClassName(root));
|
||||
Type formType = FindViewType(GeneratedNamespace + "." + GetFormClassName(root));
|
||||
Type viewType = FindGeneratedType(GeneratedNamespace + "." + GetViewClassName(root));
|
||||
Type formType = FindGeneratedType(GeneratedNamespace + "." + GetFormClassName(root));
|
||||
if (viewType == null || formType == null)
|
||||
{
|
||||
return;
|
||||
@@ -757,19 +757,19 @@ namespace SepCore.Editor
|
||||
UnityEngine.Object target = binding.component;
|
||||
if (binding.nestedRoot != null)
|
||||
{
|
||||
string nestedViewFullName = GeneratedNamespace + "." + GetViewClassName(binding.nestedRoot);
|
||||
Type nestedViewType = FindViewType(nestedViewFullName);
|
||||
if (nestedViewType == null)
|
||||
string nestedFormFullName = GeneratedNamespace + "." + GetFormClassName(binding.nestedRoot);
|
||||
Type nestedFormType = FindGeneratedType(nestedFormFullName);
|
||||
if (nestedFormType == null)
|
||||
{
|
||||
throw new InvalidOperationException("Nested UI view type was not found: " + nestedViewFullName + ".");
|
||||
throw new InvalidOperationException("Nested UI form type was not found: " + nestedFormFullName + ".");
|
||||
}
|
||||
|
||||
target = binding.nestedRoot.GetComponent(nestedViewType);
|
||||
target = binding.nestedRoot.GetComponent(nestedFormType);
|
||||
if (target == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Nested UI root '" + GetHierarchyPath(binding.nestedRoot.transform) +
|
||||
"' does not have its generated View component '" + nestedViewFullName + "'.");
|
||||
"' does not have its generated Form component '" + nestedFormFullName + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -786,7 +786,7 @@ namespace SepCore.Editor
|
||||
return view;
|
||||
}
|
||||
|
||||
private static Type FindViewType(string fullName)
|
||||
private static Type FindGeneratedType(string fullName)
|
||||
{
|
||||
return TypeCache.GetTypesDerivedFrom<MonoBehaviour>()
|
||||
.FirstOrDefault(type => type.FullName == fullName);
|
||||
|
||||
@@ -40,10 +40,10 @@ namespace SepCore.Editor
|
||||
}
|
||||
}
|
||||
|
||||
SerializedProperty nestedViews = serializedObject.FindProperty("nestedViewReferences");
|
||||
for (int i = 0; i < nestedViews.arraySize; i++)
|
||||
SerializedProperty nestedForms = serializedObject.FindProperty("nestedFormReferences");
|
||||
for (int i = 0; i < nestedForms.arraySize; i++)
|
||||
{
|
||||
SerializedProperty entry = nestedViews.GetArrayElementAtIndex(i);
|
||||
SerializedProperty entry = nestedForms.GetArrayElementAtIndex(i);
|
||||
if (entry.FindPropertyRelative("generateReference").boolValue)
|
||||
{
|
||||
referenceCount++;
|
||||
@@ -53,7 +53,7 @@ namespace SepCore.Editor
|
||||
EditorGUILayout.LabelField("View Class", UIAssetsTools.GetViewClassName(root));
|
||||
EditorGUILayout.LabelField("Form Class", UIAssetsTools.GetFormClassName(root));
|
||||
EditorGUILayout.LabelField("Owned Items", root.SerializationItems.Count.ToString());
|
||||
EditorGUILayout.LabelField("Nested Views", nestedViews.arraySize.ToString());
|
||||
EditorGUILayout.LabelField("Nested Forms", nestedForms.arraySize.ToString());
|
||||
EditorGUILayout.LabelField("Generated References", referenceCount.ToString());
|
||||
EditorGUILayout.Space(4f);
|
||||
|
||||
@@ -77,15 +77,15 @@ namespace SepCore.Editor
|
||||
}
|
||||
|
||||
EditorGUILayout.Space(4f);
|
||||
EditorGUILayout.LabelField("Nested Views", EditorStyles.boldLabel);
|
||||
if (nestedViews.arraySize == 0)
|
||||
EditorGUILayout.LabelField("Nested Forms", EditorStyles.boldLabel);
|
||||
if (nestedForms.arraySize == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Nested UISerializationRoot components will appear here and form serialization boundaries.", MessageType.Info);
|
||||
EditorGUILayout.HelpBox("Nested UISerializationRoot components will appear here as child Form references and form serialization boundaries.", MessageType.Info);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nestedViews.arraySize; i++)
|
||||
for (int i = 0; i < nestedForms.arraySize; i++)
|
||||
{
|
||||
SerializedProperty entry = nestedViews.GetArrayElementAtIndex(i);
|
||||
SerializedProperty entry = nestedForms.GetArrayElementAtIndex(i);
|
||||
SerializedProperty nestedRootProperty = entry.FindPropertyRelative("root");
|
||||
SerializedProperty generate = entry.FindPropertyRelative("generateReference");
|
||||
SerializedProperty variableName = entry.FindPropertyRelative("variableName");
|
||||
@@ -107,7 +107,7 @@ namespace SepCore.Editor
|
||||
|
||||
if (nestedRoot != null)
|
||||
{
|
||||
EditorGUILayout.LabelField("View Class", UIAssetsTools.GetViewClassName(nestedRoot));
|
||||
EditorGUILayout.LabelField("Form Class", UIAssetsTools.GetFormClassName(nestedRoot));
|
||||
}
|
||||
|
||||
if (generate.boolValue)
|
||||
|
||||
@@ -68,6 +68,14 @@ namespace SepCore.Procedure
|
||||
() =>
|
||||
{
|
||||
_loadedFlag[LubanTablesFlag] = true;
|
||||
|
||||
// Load save data; create a new game if no save exists
|
||||
GameEntry.Save.Load();
|
||||
if (!GameEntry.Save.HasSave && !GameEntry.Save.IsReady)
|
||||
{
|
||||
GameEntry.Save.CreateNewGame();
|
||||
}
|
||||
|
||||
Log.Info("Load Luban data tables OK.");
|
||||
},
|
||||
errorMessage =>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using GameFramework.Fsm;
|
||||
using GameFramework.Procedure;
|
||||
using SepCore.Definition;
|
||||
using SepCore.UI;
|
||||
|
||||
namespace SepCore.Procedure
|
||||
@@ -15,15 +16,7 @@ namespace SepCore.Procedure
|
||||
{
|
||||
base.OnEnter(procedureOwner);
|
||||
|
||||
DialogParams context = new DialogParams()
|
||||
{
|
||||
Message = "This is a test dialog.",
|
||||
Title = "This is a test dialog.",
|
||||
Mode = 2,
|
||||
ConfirmText = "确认",
|
||||
CancelText = "取消",
|
||||
};
|
||||
GameEntry.UI.OpenDialog(context);
|
||||
GameEntry.UI.OpenUIForm(UIFormType.LobbyForm);
|
||||
}
|
||||
|
||||
protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds,
|
||||
@@ -34,6 +27,8 @@ namespace SepCore.Procedure
|
||||
|
||||
protected override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown)
|
||||
{
|
||||
GameEntry.UI.CloseAllLoadedUIForms();
|
||||
|
||||
base.OnLeave(procedureOwner, isShutdown);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,12 @@ public partial class GameEntry : MonoBehaviour
|
||||
|
||||
public static LubanComponent Luban { get; private set; }
|
||||
|
||||
public static SaveComponent Save { get; private set; }
|
||||
|
||||
private static void InitCustomComponents()
|
||||
{
|
||||
BuiltinData = UnityGameFramework.Runtime.GameEntry.GetComponent<BuiltinDataComponent>();
|
||||
Luban = UnityGameFramework.Runtime.GameEntry.GetComponent<LubanComponent>();
|
||||
Save = UnityGameFramework.Runtime.GameEntry.GetComponent<SaveComponent>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using GameFramework.Resource;
|
||||
using UnityGameFramework.Runtime;
|
||||
using ResourceApplySuccessEventArgs = UnityGameFramework.Runtime.ResourceApplySuccessEventArgs;
|
||||
using ResourceUpdateAllCompleteEventArgs = UnityGameFramework.Runtime.ResourceUpdateAllCompleteEventArgs;
|
||||
@@ -58,5 +61,42 @@ namespace SepCore.AsyncTask
|
||||
timeout
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步加载资源
|
||||
/// </summary>
|
||||
/// <typeparam name="T">资源类型</typeparam>
|
||||
/// <param name="resourceComponent">资源组件</param>
|
||||
/// <param name="assetName">资源名称</param>
|
||||
/// <param name="priority">加载优先级</param>
|
||||
/// <param name="userData">用户自定义数据</param>
|
||||
/// <param name="progress">加载进度</param>
|
||||
/// <param name="timeout">超时时间(秒),0表示不超时</param>
|
||||
/// <returns>加载的资源</returns>
|
||||
public static UniTask<T> LoadAssetAsync<T>(this ResourceComponent resourceComponent,
|
||||
string assetName,
|
||||
int priority = 0,
|
||||
object userData = null,
|
||||
IProgress<float> progress = null,
|
||||
float timeout = 0f) where T : class
|
||||
{
|
||||
var tcs = new UniTaskCompletionSource<T>();
|
||||
|
||||
var callbacks = new LoadAssetCallbacks(
|
||||
(name, asset, duration, ud) => tcs.TrySetResult((T)asset),
|
||||
(name, status, errorMessage, ud) => tcs.TrySetException(new Exception($"加载资源失败: {name}, status: {status}, error: {errorMessage}")),
|
||||
(name, p, ud) => progress?.Report(p)
|
||||
);
|
||||
|
||||
resourceComponent.LoadAsset(assetName, typeof(T), priority, callbacks, userData);
|
||||
|
||||
if (timeout > 0f)
|
||||
{
|
||||
UniTask.Delay(TimeSpan.FromSeconds(timeout), cancellationToken: CancellationToken.None)
|
||||
.ContinueWith(() => tcs.TrySetException(new TimeoutException($"加载资源超时: {assetName}, {timeout}秒")));
|
||||
}
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,7 @@ namespace SepCore.CustomComponent
|
||||
"tbsoundconfig",
|
||||
"tbuiformconfig",
|
||||
"tbuisoundconfig",
|
||||
"tbformattext"
|
||||
};
|
||||
|
||||
private sealed class TableAccessor
|
||||
@@ -44,24 +45,88 @@ namespace SepCore.CustomComponent
|
||||
}
|
||||
|
||||
private static readonly Dictionary<Type, TableAccessor> TableAccessors =
|
||||
new Dictionary<Type, TableAccessor>
|
||||
new()
|
||||
{
|
||||
{ typeof(CharacterConfig), Accessor(tables => id => tables.TbCharacterConfig.GetOrDefault(id), tables => tables.TbCharacterConfig.DataList) },
|
||||
{ typeof(BattleActionConfig), Accessor(tables => id => tables.TbBattleActionConfig.GetOrDefault(id), tables => tables.TbBattleActionConfig.DataList) },
|
||||
{ typeof(ThreatLevelConfig), Accessor(tables => id => tables.TbThreatLevelConfig.GetOrDefault(id), tables => tables.TbThreatLevelConfig.DataList) },
|
||||
{ typeof(EnemyConfig), Accessor(tables => id => tables.TbEnemyConfig.GetOrDefault(id), tables => tables.TbEnemyConfig.DataList) },
|
||||
{ typeof(EnemyPartyConfig), Accessor(tables => id => tables.TbEnemyPartyConfig.GetOrDefault(id), tables => tables.TbEnemyPartyConfig.DataList) },
|
||||
{ typeof(ItemConfig), Accessor(tables => id => tables.TbItemConfig.GetOrDefault(id), tables => tables.TbItemConfig.DataList) },
|
||||
{ typeof(ResourcePointConfig), Accessor(tables => id => tables.TbResourcePointConfig.GetOrDefault(id), tables => tables.TbResourcePointConfig.DataList) },
|
||||
{ typeof(EnemyDropConfig), Accessor(tables => id => tables.TbEnemyDropConfig.GetOrDefault(id), tables => tables.TbEnemyDropConfig.DataList) },
|
||||
{ typeof(RarityConfig), Accessor(tables => id => tables.TbRarityConfig.GetOrDefault((Rarity)id), tables => tables.TbRarityConfig.DataList) },
|
||||
{ typeof(DifficultyConfig), Accessor(tables => id => tables.TbDifficultyConfig.GetOrDefault((DifficultyTier)id), tables => tables.TbDifficultyConfig.DataList) },
|
||||
{ typeof(EntityConfig), Accessor(tables => id => tables.TbEntityConfig.GetOrDefault(id), tables => tables.TbEntityConfig.DataList) },
|
||||
{ typeof(MusicConfig), Accessor(tables => id => tables.TbMusicConfig.GetOrDefault(id), tables => tables.TbMusicConfig.DataList) },
|
||||
{ typeof(SceneConfig), Accessor(tables => id => tables.TbSceneConfig.GetOrDefault(id), tables => tables.TbSceneConfig.DataList) },
|
||||
{ typeof(SoundConfig), Accessor(tables => id => tables.TbSoundConfig.GetOrDefault(id), tables => tables.TbSoundConfig.DataList) },
|
||||
{ typeof(UIFormConfig), Accessor(tables => id => tables.TbUIFormConfig.GetOrDefault(id), tables => tables.TbUIFormConfig.DataList) },
|
||||
{ typeof(UISoundConfig), Accessor(tables => id => tables.TbUISoundConfig.GetOrDefault(id), tables => tables.TbUISoundConfig.DataList) },
|
||||
{
|
||||
typeof(CharacterConfig),
|
||||
Accessor(tables => id => tables.TbCharacterConfig.GetOrDefault(id),
|
||||
tables => tables.TbCharacterConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(BattleActionConfig),
|
||||
Accessor(tables => id => tables.TbBattleActionConfig.GetOrDefault(id),
|
||||
tables => tables.TbBattleActionConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(ThreatLevelConfig),
|
||||
Accessor(tables => id => tables.TbThreatLevelConfig.GetOrDefault(id),
|
||||
tables => tables.TbThreatLevelConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(EnemyConfig),
|
||||
Accessor(tables => id => tables.TbEnemyConfig.GetOrDefault(id),
|
||||
tables => tables.TbEnemyConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(EnemyPartyConfig),
|
||||
Accessor(tables => id => tables.TbEnemyPartyConfig.GetOrDefault(id),
|
||||
tables => tables.TbEnemyPartyConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(ItemConfig),
|
||||
Accessor(tables => id => tables.TbItemConfig.GetOrDefault(id),
|
||||
tables => tables.TbItemConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(ResourcePointConfig),
|
||||
Accessor(tables => id => tables.TbResourcePointConfig.GetOrDefault(id),
|
||||
tables => tables.TbResourcePointConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(EnemyDropConfig),
|
||||
Accessor(tables => id => tables.TbEnemyDropConfig.GetOrDefault(id),
|
||||
tables => tables.TbEnemyDropConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(RarityConfig),
|
||||
Accessor(tables => id => tables.TbRarityConfig.GetOrDefault((Rarity)id),
|
||||
tables => tables.TbRarityConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(DifficultyConfig),
|
||||
Accessor(tables => id => tables.TbDifficultyConfig.GetOrDefault((DifficultyTier)id),
|
||||
tables => tables.TbDifficultyConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(EntityConfig),
|
||||
Accessor(tables => id => tables.TbEntityConfig.GetOrDefault(id),
|
||||
tables => tables.TbEntityConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(MusicConfig),
|
||||
Accessor(tables => id => tables.TbMusicConfig.GetOrDefault(id),
|
||||
tables => tables.TbMusicConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(SceneConfig),
|
||||
Accessor(tables => id => tables.TbSceneConfig.GetOrDefault((SceneType)id),
|
||||
tables => tables.TbSceneConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(SoundConfig),
|
||||
Accessor(tables => id => tables.TbSoundConfig.GetOrDefault(id),
|
||||
tables => tables.TbSoundConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(UIFormConfig),
|
||||
Accessor(tables => id => tables.TbUIFormConfig.GetOrDefault((UIFormType)id),
|
||||
tables => tables.TbUIFormConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(UISoundConfig),
|
||||
Accessor(tables => id => tables.TbUISoundConfig.GetOrDefault(id),
|
||||
tables => tables.TbUISoundConfig.DataList)
|
||||
},
|
||||
};
|
||||
|
||||
private static TableAccessor Accessor<TValue>(Func<Tables, Func<int, object>> rowGetterFactory,
|
||||
@@ -82,13 +147,15 @@ namespace SepCore.CustomComponent
|
||||
/// <summary>
|
||||
/// 获取 Luban 数据表管理器,加载完成后可用。
|
||||
/// </summary>
|
||||
public SepCore.Definition.Tables Tables { get; private set; }
|
||||
public Tables Tables { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据表是否已加载完成。
|
||||
/// </summary>
|
||||
public bool IsReady => Tables != null;
|
||||
|
||||
public TbGlobalConfig Global => Tables.TbGlobalConfig;
|
||||
|
||||
/// <summary>
|
||||
/// 按 id 获取数据行,未找到时返回 null。
|
||||
/// </summary>
|
||||
@@ -193,7 +260,8 @@ namespace SepCore.CustomComponent
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLoadTableFailure(string assetName, LoadResourceStatus status, string errorMessage, object userData)
|
||||
private void OnLoadTableFailure(string assetName, LoadResourceStatus status, string errorMessage,
|
||||
object userData)
|
||||
{
|
||||
Log.Error("Can not load data table '{0}' from '{1}' with error message '{2}'.", (string)userData, assetName,
|
||||
errorMessage);
|
||||
@@ -208,4 +276,4 @@ namespace SepCore.CustomComponent
|
||||
return GameFramework.Utility.Text.Format("Assets/GameMain/DataTables/{0}.bytes", tableName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 233579b69c85c4f9db143fcf0368c36a
|
||||
guid: 8247612c245cc47be82009199a823d68
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,192 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.CustomComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// 存档组件。
|
||||
/// 负责游戏存档的读取与写入,数据结构见 Docs/Tech/02_SaveData.md。
|
||||
/// 存档只包含局外状态与已结束单局的结算记录;进行中的单局使用临时状态,不写入存档。
|
||||
/// </summary>
|
||||
public class SaveComponent : GameFrameworkComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// 存档文件名。
|
||||
/// </summary>
|
||||
[SerializeField] private string _fileName = "save.json";
|
||||
|
||||
private SaveData _data = null;
|
||||
private bool _hasSave = false;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前内存中的存档数据;未加载或未创建时为 null。
|
||||
/// </summary>
|
||||
public SaveData Data => _data;
|
||||
|
||||
/// <summary>
|
||||
/// 获取磁盘上是否已存在存档文件。
|
||||
/// </summary>
|
||||
public bool HasSave => _hasSave;
|
||||
|
||||
/// <summary>
|
||||
/// 获取存档数据是否可用。
|
||||
/// </summary>
|
||||
public bool IsReady => _data != null;
|
||||
|
||||
/// <summary>
|
||||
/// 获取存档文件的完整路径。
|
||||
/// </summary>
|
||||
public string SaveFilePath => GameFramework.Utility.Path.GetRegularPath(
|
||||
Path.Combine(Application.persistentDataPath, _fileName));
|
||||
|
||||
/// <summary>
|
||||
/// 从磁盘加载存档。
|
||||
/// 文件不存在时返回 true 且 HasSave 为 false;解析失败时返回 false。
|
||||
/// </summary>
|
||||
public bool Load()
|
||||
{
|
||||
string path = SaveFilePath;
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
_hasSave = false;
|
||||
_data = null;
|
||||
Log.Info("Save file '{0}' does not exist.", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string json = File.ReadAllText(path);
|
||||
SaveData data = SaveData.FromJson(json);
|
||||
if (data == null)
|
||||
{
|
||||
Log.Error("Parse save file '{0}' failure.", path);
|
||||
_hasSave = true;
|
||||
_data = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.version != SaveData.CurrentVersion)
|
||||
{
|
||||
Log.Warning("Save file '{0}' version '{1}' does not match current version '{2}'.",
|
||||
path, data.version, SaveData.CurrentVersion);
|
||||
}
|
||||
|
||||
_data = data;
|
||||
_hasSave = true;
|
||||
Log.Info("Load save file '{0}' OK.", path);
|
||||
return true;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Error("Load save file '{0}' failure with exception '{1}'.", path, exception);
|
||||
_hasSave = true;
|
||||
_data = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建新存档数据(不写盘)。
|
||||
/// 角色与初始装备来自配表:GlobalConfig.NewGameCharacterIds 与 CharacterConfig 的初始装备栏。
|
||||
/// </summary>
|
||||
public bool CreateNewGame()
|
||||
{
|
||||
if (!GameEntry.Luban.IsReady)
|
||||
{
|
||||
Log.Error("Can not create new game before Luban data tables are loaded.");
|
||||
return false;
|
||||
}
|
||||
|
||||
GlobalConfig global = GameEntry.Luban.Global.Data;
|
||||
SaveData data = new SaveData
|
||||
{
|
||||
version = SaveData.CurrentVersion,
|
||||
updatedAt = GetTimestamp(),
|
||||
mainWarehouse = CreateInitialWarehouse(),
|
||||
characters = new List<CharacterSave>(),
|
||||
loadout = new LoadoutSave(),
|
||||
runHistory = new List<RunRecord>(),
|
||||
};
|
||||
|
||||
foreach (int characterId in global.NewGameCharacterIds)
|
||||
{
|
||||
CharacterConfig config = GameEntry.Luban.Get<CharacterConfig>(characterId);
|
||||
int weaponItemId = config != null ? config.WeaponItemId : 0;
|
||||
int armorItemId = config != null ? config.ArmorItemId : 0;
|
||||
data.characters.Add(new CharacterSave(characterId, weaponItemId, armorItemId));
|
||||
}
|
||||
|
||||
data.loadout.Normalize();
|
||||
_data = data;
|
||||
_hasSave = false;
|
||||
Log.Info("Create new game save data OK.");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将当前存档数据写入磁盘。
|
||||
/// 写入前自动更新 updatedAt;使用临时文件替换,避免写入中断损坏存档。
|
||||
/// </summary>
|
||||
public bool Save()
|
||||
{
|
||||
if (_data == null)
|
||||
{
|
||||
Log.Warning("Can not save because save data does not exist.");
|
||||
return false;
|
||||
}
|
||||
|
||||
_data.updatedAt = GetTimestamp();
|
||||
string json = _data.ToJson();
|
||||
|
||||
string path = SaveFilePath;
|
||||
string tempPath = path + ".tmp";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(tempPath, json);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
|
||||
File.Move(tempPath, path);
|
||||
_hasSave = true;
|
||||
Log.Info("Save save file '{0}' OK.", path);
|
||||
return true;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Error("Save save file '{0}' failure with exception '{1}'.", path, exception);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<ItemStack> CreateInitialWarehouse()
|
||||
{
|
||||
// 原型调试种子:覆盖全部物品类型与稀有度,用于筛选等功能开发。
|
||||
// 后续由配表或正式新存档规则替代。
|
||||
return new List<ItemStack>
|
||||
{
|
||||
new ItemStack(5001, 20), // 旧硬币 战利品/白
|
||||
new ItemStack(5002, 7), // 宝石碎片 战利品/绿
|
||||
new ItemStack(5003, 3), // 古代零件 战利品/蓝
|
||||
new ItemStack(5004, 1), // 精致核心 战利品/金
|
||||
new ItemStack(5005, 1), // 神秘遗物 战利品/红
|
||||
new ItemStack(5101, 1), // 训练剑 装备/白
|
||||
new ItemStack(5102, 1), // 法杖 装备/蓝
|
||||
new ItemStack(5201, 1), // 布甲 装备/绿
|
||||
new ItemStack(5202, 1), // 术士长袍 装备/金
|
||||
new ItemStack(5301, 5), // 恢复药 消耗品/白
|
||||
};
|
||||
}
|
||||
|
||||
private static long GetTimestamp()
|
||||
{
|
||||
return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e65ab245d7674846b4409282a610b3a9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -101,10 +101,6 @@ namespace SepCore.UI
|
||||
foreach (var text in tmp_texts)
|
||||
{
|
||||
text.font = _mainTMPFont;
|
||||
if (!string.IsNullOrEmpty(text.text))
|
||||
{
|
||||
text.text = GameEntry.Localization.GetString(text.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -1,9 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2fc27161191c61549a74f80fd54e9645
|
||||
guid: 4df8f90e8698941068b8d0dd7c3af46e
|
||||
folderAsset: yes
|
||||
timeCreated: 1528026150
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,41 @@
|
||||
using SepCore.Definition;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用 Luban 格式化文本表(TbFormatText)驱动 TextMeshProUGUI 的组件。
|
||||
/// 在 Inspector 上填写 Key,调用 Set 传入格式化参数即可更新文本。
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(TextMeshProUGUI))]
|
||||
public class FormatTextUI : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private string key;
|
||||
|
||||
private TextMeshProUGUI _text;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_text = GetComponent<TextMeshProUGUI>();
|
||||
}
|
||||
|
||||
public void Set(params object[] args)
|
||||
{
|
||||
FormatText format = GameEntry.Luban.Tables.TbFormatText.GetOrDefault(key);
|
||||
if (format == null)
|
||||
{
|
||||
Log.Warning("Can not find format text '{0}'.", key);
|
||||
return;
|
||||
}
|
||||
|
||||
_text.SetText(string.Format(format.Format, args));
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_text.SetText(string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6566a3a7cfd184008ab2282feea295f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,16 +6,8 @@ namespace SepCore.UI
|
||||
[DisallowMultipleComponent]
|
||||
public partial class CombatReadinessView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI squadMemberText;
|
||||
[SerializeField] public global::UnityEngine.RectTransform characterSlotRoot;
|
||||
[SerializeField] public global::SepCore.UI.CharacterSlotItem characterSlotTemplate;
|
||||
[SerializeField] public global::UnityEngine.UI.ToggleGroup difficultyTabsToggleGroup;
|
||||
[SerializeField] public global::TMPro.TMP_InputField seedInput;
|
||||
[SerializeField] public global::UnityEngine.UI.Button randomizeButton;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI partySizeText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI mapIdText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI timeLimitText;
|
||||
[SerializeField] public global::UnityEngine.UI.Button beginRunButton;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI storageText;
|
||||
[SerializeField] public global::SepCore.UI.SquadForm squadForm;
|
||||
[SerializeField] public global::SepCore.UI.DeploymentForm deploymentForm;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9d3ff59008964126bb0c8052f0626e0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class DeploymentForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private DeploymentView _view = null;
|
||||
|
||||
public DeploymentView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37901c3791a804ff6b35692ab2f67f04
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class DeploymentView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle tier1Toggle;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle tier2Toggle;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle tier3Toggle;
|
||||
[SerializeField] public global::TMPro.TMP_InputField seedInput;
|
||||
[SerializeField] public global::UnityEngine.UI.Button randomizeButton;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI partySizeText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI mapIdText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI timeLimitText;
|
||||
[SerializeField] public global::UnityEngine.UI.Button beginRunButton;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e9a8d6edf3794bc69f3b822e538ff96
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,195 @@
|
||||
using System.Collections.Generic;
|
||||
using SepCore.Base;
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 物品列表界面逻辑(手写 partial,与自动生成的 InventoryForm.cs 合并)。
|
||||
/// 支持按物品类型筛选(ALL / 战利品 / 装备 / 消耗品)。
|
||||
/// 注意:本表单作为嵌套表单挂在 LobbyForm/WarehouseForm 下,UGF 生命周期(OnInit/OnOpen)
|
||||
/// 不会被框架调用,事件绑定改为幂等式(EnsureListenersBound)。
|
||||
/// </summary>
|
||||
public partial class InventoryForm : UGuiForm
|
||||
{
|
||||
private bool _listenersBound = false;
|
||||
private IReadOnlyList<ItemStack> _stacks = null;
|
||||
private ItemType? _filterType = null;
|
||||
private List<ItemStack> _visibleStacks = new List<ItemStack>();
|
||||
private readonly List<WarehouseSlotItem> _slots = new List<WarehouseSlotItem>();
|
||||
|
||||
private void EnsureListenersBound()
|
||||
{
|
||||
if (_listenersBound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_listenersBound = true;
|
||||
View.allToggle.onValueChanged.AddListener(OnAllToggleValueChanged);
|
||||
View.lootToggle.onValueChanged.AddListener(OnLootToggleValueChanged);
|
||||
View.equipmentToggle.onValueChanged.AddListener(OnEquipmentToggleValueChanged);
|
||||
View.consumablesToggle.onValueChanged.AddListener(OnConsumablesToggleValueChanged);
|
||||
}
|
||||
|
||||
private void OnAllToggleValueChanged(bool isOn)
|
||||
{
|
||||
if (isOn)
|
||||
{
|
||||
SetFilter(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLootToggleValueChanged(bool isOn)
|
||||
{
|
||||
if (isOn)
|
||||
{
|
||||
SetFilter(ItemType.Loot);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEquipmentToggleValueChanged(bool isOn)
|
||||
{
|
||||
if (isOn)
|
||||
{
|
||||
SetFilter(ItemType.Equipment);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnConsumablesToggleValueChanged(bool isOn)
|
||||
{
|
||||
if (isOn)
|
||||
{
|
||||
SetFilter(ItemType.Consumable);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetFilter(ItemType? filterType)
|
||||
{
|
||||
_filterType = filterType;
|
||||
RebuildGrid();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置列表数据并重建网格,保留当前筛选。
|
||||
/// </summary>
|
||||
public void RefreshList(IReadOnlyList<ItemStack> stacks)
|
||||
{
|
||||
EnsureListenersBound();
|
||||
|
||||
_stacks = stacks;
|
||||
RebuildGrid();
|
||||
}
|
||||
|
||||
private void RebuildGrid()
|
||||
{
|
||||
InventoryView inventoryView = View;
|
||||
if (inventoryView == null || inventoryView.warehouseSlotRoot == null ||
|
||||
inventoryView.warehouseSlotTemplate == null)
|
||||
{
|
||||
Log.Warning("InventoryForm is not fully configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
int slotCount = GameEntry.Luban.Global.Data.WarehouseSlotCount;
|
||||
if (slotCount <= 0)
|
||||
{
|
||||
Log.Warning("Warehouse slot count from global config is invalid: {0}.", slotCount);
|
||||
return;
|
||||
}
|
||||
|
||||
_visibleStacks = CollectVisibleStacks();
|
||||
_slots.Clear();
|
||||
|
||||
WarehouseSlotItem template = inventoryView.warehouseSlotTemplate;
|
||||
template.gameObject.SetActive(false);
|
||||
|
||||
for (int i = inventoryView.warehouseSlotRoot.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
Transform child = inventoryView.warehouseSlotRoot.GetChild(i);
|
||||
if (child == template.transform)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
for (int i = 0; i < slotCount; i++)
|
||||
{
|
||||
WarehouseSlotItem slot = Instantiate(template, inventoryView.warehouseSlotRoot);
|
||||
slot.gameObject.SetActive(true);
|
||||
slot.SetSlotId(i);
|
||||
if (i < _visibleStacks.Count)
|
||||
{
|
||||
slot.SetItem(_visibleStacks[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
slot.SetEmpty();
|
||||
}
|
||||
|
||||
_slots.Add(slot);
|
||||
}
|
||||
|
||||
if (inventoryView.itemCountFormatText != null)
|
||||
{
|
||||
int usedSlotCount = _stacks != null ? _stacks.Count : 0;
|
||||
inventoryView.itemCountFormatText.Set(usedSlotCount, slotCount);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 按网格索引高亮对应格子,其余格子清除选中。
|
||||
/// </summary>
|
||||
public void SetSelectedSlot(int slotId)
|
||||
{
|
||||
for (int i = 0; i < _slots.Count; i++)
|
||||
{
|
||||
_slots[i].SetSelected(i == slotId);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定网格索引对应的物品 ID;空格或越界返回 0。
|
||||
/// </summary>
|
||||
public int GetItemIdAtSlot(int slotId)
|
||||
{
|
||||
if (slotId < 0 || slotId >= _visibleStacks.Count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _visibleStacks[slotId].itemId;
|
||||
}
|
||||
|
||||
private List<ItemStack> CollectVisibleStacks()
|
||||
{
|
||||
List<ItemStack> visible = new List<ItemStack>();
|
||||
if (_stacks == null)
|
||||
{
|
||||
return visible;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _stacks.Count; i++)
|
||||
{
|
||||
ItemStack stack = _stacks[i];
|
||||
if (_filterType.HasValue)
|
||||
{
|
||||
ItemConfig config = GameEntry.Luban.Get<ItemConfig>(stack.itemId);
|
||||
if (config == null || config.ItemType != _filterType.Value)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
visible.Add(stack);
|
||||
}
|
||||
|
||||
return visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0452e5e692a1e42118fa2097e6575eaa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,10 +6,15 @@ namespace SepCore.UI
|
||||
[DisallowMultipleComponent]
|
||||
public partial class InventoryView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle allToggle;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle lootToggle;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle equipmentToggle;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle consumablesToggle;
|
||||
[SerializeField] public global::TMPro.TMP_InputField searchInput;
|
||||
[SerializeField] public global::UnityEngine.UI.Button sortButton;
|
||||
[SerializeField] public global::UnityEngine.UI.ScrollRect itemScroll;
|
||||
[SerializeField] public global::UnityEngine.RectTransform warehouseSlotRoot;
|
||||
[SerializeField] public global::SepCore.UI.WarehouseSlotItem warehouseSlotTemplate;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI itemCountFormatText;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class InventoryPanelForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private InventoryPanelView _view = null;
|
||||
|
||||
public InventoryPanelView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class InventoryPanelView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.UI.InputField searchInput;
|
||||
[SerializeField] public global::UnityEngine.UI.Button sortButton;
|
||||
[SerializeField] public global::UnityEngine.UI.ScrollRect itemScroll;
|
||||
[SerializeField] public global::UnityEngine.RectTransform warehouseSlotRoot;
|
||||
[SerializeField] public global::SepCore.UI.WarehouseSlotItem warehouseSlotTemplate;
|
||||
[SerializeField] public global::UnityEngine.UI.Text itemCountText;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using SepCore.Definition;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
@@ -11,10 +11,57 @@ namespace SepCore.UI
|
||||
[SerializeField] private Image bg;
|
||||
[SerializeField] private Image icon;
|
||||
[SerializeField] private TextMeshProUGUI characterName;
|
||||
[SerializeField] private TextMeshProUGUI hpText;
|
||||
[SerializeField] private TextMeshProUGUI mpText;
|
||||
[SerializeField] private TextMeshProUGUI speedText;
|
||||
[SerializeField] private TextMeshProUGUI atkText;
|
||||
[SerializeField] private TextMeshProUGUI matText;
|
||||
[SerializeField] private FormatTextUI hpText;
|
||||
[SerializeField] private FormatTextUI mpText;
|
||||
[SerializeField] private FormatTextUI speedText;
|
||||
[SerializeField] private FormatTextUI atkText;
|
||||
[SerializeField] private FormatTextUI matText;
|
||||
|
||||
/// <summary>
|
||||
/// 用存档角色填充格子;角色配置不存在时按空格子显示。
|
||||
/// </summary>
|
||||
public void SetCharacter(CharacterSave save)
|
||||
{
|
||||
CharacterConfig config = GameEntry.Luban.Get<CharacterConfig>(save.characterId);
|
||||
if (config == null)
|
||||
{
|
||||
Log.Warning("Can not find character config '{0}' for squad slot.", save.characterId);
|
||||
SetEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
characterName.text = config.Name;
|
||||
hpText.Set(config.MaxHp);
|
||||
mpText.Set(config.MaxMp);
|
||||
speedText.Set(config.Speed);
|
||||
atkText.Set(config.Atk);
|
||||
matText.Set(config.Mat);
|
||||
HideIcon();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示为空格子。
|
||||
/// </summary>
|
||||
public void SetEmpty()
|
||||
{
|
||||
characterName.text = string.Empty;
|
||||
hpText.Clear();
|
||||
mpText.Clear();
|
||||
speedText.Clear();
|
||||
atkText.Clear();
|
||||
matText.Clear();
|
||||
HideIcon();
|
||||
}
|
||||
|
||||
private void HideIcon()
|
||||
{
|
||||
if (icon == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
icon.sprite = null;
|
||||
icon.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,137 @@
|
||||
using SepCore.Base;
|
||||
using SepCore.Definition;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public class WarehouseSlotItem : MonoBehaviour
|
||||
{
|
||||
private static readonly Color RarityWhite = new Color32(245, 247, 248, 255);
|
||||
private static readonly Color RarityGreen = new Color32(93, 155, 97, 255);
|
||||
private static readonly Color RarityBlue = new Color32(52, 127, 168, 255);
|
||||
private static readonly Color RarityGold = new Color32(214, 169, 61, 255);
|
||||
private static readonly Color RarityRed = new Color32(185, 87, 79, 255);
|
||||
private static readonly Color RarityEmpty = new Color32(111, 101, 90, 255);
|
||||
private static readonly Color SelectedBgColor = new Color(0.86f, 0.95f, 1f, 1f);
|
||||
|
||||
[SerializeField] private Image bg;
|
||||
[SerializeField] private Button button;
|
||||
[SerializeField] private Image icon;
|
||||
[SerializeField] private Image rarity;
|
||||
[SerializeField] private TextMeshProUGUI quantityText;
|
||||
|
||||
private int _slotId = 0;
|
||||
private bool _filled = false;
|
||||
private bool _clickBound = false;
|
||||
|
||||
/// <summary>
|
||||
/// 设置格子在固定网格中的索引,点击事件以此作为唯一标识。
|
||||
/// </summary>
|
||||
public void SetSlotId(int slotId)
|
||||
{
|
||||
_slotId = slotId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用物品堆叠填充格子;物品配置不存在时按空格子显示。
|
||||
/// </summary>
|
||||
public void SetItem(ItemStack stack)
|
||||
{
|
||||
ItemConfig config = GameEntry.Luban.Get<ItemConfig>(stack.itemId);
|
||||
if (config == null)
|
||||
{
|
||||
Log.Warning("Can not find item config '{0}' for warehouse slot.", stack.itemId);
|
||||
SetEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
_filled = true;
|
||||
rarity.color = GetRarityColor(config.Rarity);
|
||||
quantityText.text = stack.count.ToString();
|
||||
HideIcon();
|
||||
BindClick();
|
||||
if (button != null)
|
||||
{
|
||||
button.interactable = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 显示为空格子。
|
||||
/// </summary>
|
||||
public void SetEmpty()
|
||||
{
|
||||
_filled = false;
|
||||
rarity.color = RarityEmpty;
|
||||
quantityText.text = string.Empty;
|
||||
HideIcon();
|
||||
if (button != null)
|
||||
{
|
||||
button.interactable = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置选中高亮。
|
||||
/// </summary>
|
||||
public void SetSelected(bool selected)
|
||||
{
|
||||
if (bg != null)
|
||||
{
|
||||
bg.color = selected ? SelectedBgColor : Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
private void BindClick()
|
||||
{
|
||||
if (_clickBound || button == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_clickBound = true;
|
||||
button.onClick.AddListener(OnClick);
|
||||
}
|
||||
|
||||
private void OnClick()
|
||||
{
|
||||
if (!_filled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, WarehouseSlotItemClickEventArgs.Create(_slotId));
|
||||
}
|
||||
|
||||
private void HideIcon()
|
||||
{
|
||||
if (icon == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
icon.sprite = null;
|
||||
icon.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
private static Color GetRarityColor(Rarity rarity)
|
||||
{
|
||||
switch (rarity)
|
||||
{
|
||||
case Rarity.Green:
|
||||
return RarityGreen;
|
||||
case Rarity.Blue:
|
||||
return RarityBlue;
|
||||
case Rarity.Gold:
|
||||
return RarityGold;
|
||||
case Rarity.Red:
|
||||
return RarityRed;
|
||||
default:
|
||||
return RarityWhite;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 道具详情界面逻辑(手写 partial,与自动生成的 ItemDetailsForm.cs 合并)。
|
||||
/// 只提供详情显示能力,由调用方(WarehouseForm)传入物品 ID 后刷新。
|
||||
/// </summary>
|
||||
public partial class ItemDetailsForm : UGuiForm
|
||||
{
|
||||
/// <summary>
|
||||
/// 按物品 ID 刷新详情界面;配置不存在时清空显示。
|
||||
/// </summary>
|
||||
public void Refresh(int itemId)
|
||||
{
|
||||
ItemDetailsView view = View;
|
||||
if (view == null)
|
||||
{
|
||||
Log.Warning("ItemDetailsForm view is not configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
ItemConfig config = GameEntry.Luban.Get<ItemConfig>(itemId);
|
||||
if (config == null)
|
||||
{
|
||||
Log.Warning("Can not find item config '{0}' for item details.", itemId);
|
||||
ClearDetails(view);
|
||||
return;
|
||||
}
|
||||
|
||||
if (view.itemDetailNameText != null)
|
||||
{
|
||||
view.itemDetailNameText.text = config.Name;
|
||||
}
|
||||
|
||||
if (view.itemDetailTypeText != null)
|
||||
{
|
||||
view.itemDetailTypeText.text = GetItemTypeName(config.ItemType) + " / " + GetRarityName(config.Rarity);
|
||||
}
|
||||
|
||||
if (view.hpFormatText != null)
|
||||
{
|
||||
view.hpFormatText.Set(config.MaxHpBonus);
|
||||
}
|
||||
|
||||
if (view.atkFormatText != null)
|
||||
{
|
||||
view.atkFormatText.Set(config.AtkBonus);
|
||||
}
|
||||
|
||||
if (view.mpFormatText != null)
|
||||
{
|
||||
view.mpFormatText.Set(config.MaxMpBonus);
|
||||
}
|
||||
|
||||
if (view.matFormatText != null)
|
||||
{
|
||||
view.matFormatText.Set(config.MatBonus);
|
||||
}
|
||||
|
||||
if (view.speedFormatText != null)
|
||||
{
|
||||
view.speedFormatText.Set(0);
|
||||
}
|
||||
|
||||
if (view.stackFormatText != null)
|
||||
{
|
||||
view.stackFormatText.Set(config.StackLimit);
|
||||
}
|
||||
|
||||
if (view.itemDetailDescriptionText != null)
|
||||
{
|
||||
view.itemDetailDescriptionText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (view.itemDetailIcon != null)
|
||||
{
|
||||
view.itemDetailIcon.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ClearDetails(ItemDetailsView view)
|
||||
{
|
||||
if (view.itemDetailNameText != null)
|
||||
{
|
||||
view.itemDetailNameText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (view.itemDetailTypeText != null)
|
||||
{
|
||||
view.itemDetailTypeText.text = string.Empty;
|
||||
}
|
||||
|
||||
if (view.itemDetailDescriptionText != null)
|
||||
{
|
||||
view.itemDetailDescriptionText.text = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetItemTypeName(ItemType itemType)
|
||||
{
|
||||
switch (itemType)
|
||||
{
|
||||
case ItemType.Loot:
|
||||
return "战利品";
|
||||
case ItemType.Equipment:
|
||||
return "装备";
|
||||
case ItemType.Consumable:
|
||||
return "消耗品";
|
||||
default:
|
||||
return "未知";
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetRarityName(Rarity rarity)
|
||||
{
|
||||
switch (rarity)
|
||||
{
|
||||
case Rarity.White:
|
||||
return "白";
|
||||
case Rarity.Green:
|
||||
return "绿";
|
||||
case Rarity.Blue:
|
||||
return "蓝";
|
||||
case Rarity.Gold:
|
||||
return "金";
|
||||
case Rarity.Red:
|
||||
return "红";
|
||||
default:
|
||||
return "无";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33d70aa8e73294a65b7b132a8a0619af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -9,12 +9,12 @@ namespace SepCore.UI
|
||||
[SerializeField] public global::UnityEngine.UI.Image itemDetailIcon;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI itemDetailNameText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI itemDetailTypeText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI hpText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI atkText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI mpText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI matText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI speedText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI stackText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI hpFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI atkFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI mpFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI matFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI speedFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI stackFormatText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI itemDetailDescriptionText;
|
||||
[SerializeField] public global::UnityEngine.UI.Button openLoadoutButton;
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class ItemDetailsPanelForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private ItemDetailsPanelView _view = null;
|
||||
|
||||
public ItemDetailsPanelView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class ItemDetailsPanelView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.UI.Image itemDetailIcon;
|
||||
[SerializeField] public global::UnityEngine.UI.Text nameText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text typeText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text hpText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text atkText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text mpText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text matText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text speedText;
|
||||
[SerializeField] public global::UnityEngine.UI.Text stackText;
|
||||
[SerializeField] public global::UnityEngine.UI.Button openLoadoutButton;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
using DG.Tweening;
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 大厅界面逻辑(手写 partial,与自动生成的 LobbyForm.cs 合并)。
|
||||
/// 导航使用 Toggle + ToggleGroup 管理选中状态;本类只负责页面切换与标记动画。
|
||||
/// </summary>
|
||||
public partial class LobbyForm : UGuiForm
|
||||
{
|
||||
private const float SelectionMarkerMoveDuration = 0.25f;
|
||||
|
||||
private enum LobbyPage
|
||||
{
|
||||
CombatReadiness,
|
||||
Warehouse,
|
||||
}
|
||||
|
||||
protected override void OnInit(object userData)
|
||||
{
|
||||
base.OnInit(userData);
|
||||
|
||||
View.homeToggle.onValueChanged.AddListener(OnHomeToggleValueChanged);
|
||||
View.warehouseToggle.onValueChanged.AddListener(OnWarehouseToggleValueChanged);
|
||||
View.loadoutToggle.onValueChanged.AddListener(OnLoadoutToggleValueChanged);
|
||||
}
|
||||
|
||||
protected override void OnOpen(object userData)
|
||||
{
|
||||
base.OnOpen(userData);
|
||||
SwitchPage(LobbyPage.CombatReadiness, View.homeToggle);
|
||||
}
|
||||
|
||||
protected override void OnClose(bool isShutdown, object userData)
|
||||
{
|
||||
if (View.selectionMarkerObject != null)
|
||||
{
|
||||
View.selectionMarkerObject.DOKill();
|
||||
}
|
||||
|
||||
View.homeToggle.onValueChanged.RemoveListener(OnHomeToggleValueChanged);
|
||||
View.warehouseToggle.onValueChanged.RemoveListener(OnWarehouseToggleValueChanged);
|
||||
View.loadoutToggle.onValueChanged.RemoveListener(OnLoadoutToggleValueChanged);
|
||||
|
||||
base.OnClose(isShutdown, userData);
|
||||
}
|
||||
|
||||
private void OnHomeToggleValueChanged(bool isOn)
|
||||
{
|
||||
if (isOn)
|
||||
{
|
||||
SwitchPage(LobbyPage.CombatReadiness, View.homeToggle);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWarehouseToggleValueChanged(bool isOn)
|
||||
{
|
||||
if (isOn)
|
||||
{
|
||||
SwitchPage(LobbyPage.Warehouse, View.warehouseToggle);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnLoadoutToggleValueChanged(bool isOn)
|
||||
{
|
||||
// 战备页暂无对应界面,选中状态由 ToggleGroup 维护,仅预留切换入口
|
||||
}
|
||||
|
||||
private void SwitchPage(LobbyPage page, Toggle activeToggle)
|
||||
{
|
||||
bool showCombatReadiness = page == LobbyPage.CombatReadiness;
|
||||
bool showWarehouse = page == LobbyPage.Warehouse;
|
||||
|
||||
if (View.combatRandinessForm != null)
|
||||
{
|
||||
View.combatRandinessForm.gameObject.SetActive(showCombatReadiness);
|
||||
}
|
||||
|
||||
if (View.warehouseForm != null)
|
||||
{
|
||||
View.warehouseForm.gameObject.SetActive(showWarehouse);
|
||||
}
|
||||
|
||||
MoveSelectionMarker(activeToggle.transform as RectTransform);
|
||||
|
||||
if (showCombatReadiness)
|
||||
{
|
||||
RefreshCombatReadiness();
|
||||
}
|
||||
|
||||
if (showWarehouse)
|
||||
{
|
||||
RefreshWarehouse();
|
||||
}
|
||||
}
|
||||
|
||||
private void MoveSelectionMarker(RectTransform targetToggle)
|
||||
{
|
||||
RectTransform marker = View.selectionMarkerObject;
|
||||
if (marker == null || targetToggle == null || marker.parent == targetToggle)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 把标记相对目标 Toggle 锚点(anchorMin)的偏移,换算到 Toggle pivot 的局部坐标空间:
|
||||
// 锚点相对 pivot 的偏移 = (anchor - pivot) * rect 尺寸。
|
||||
Vector3 targetLocalPosition = new Vector3(
|
||||
marker.anchoredPosition.x + (marker.anchorMin.x - targetToggle.pivot.x) * targetToggle.rect.width,
|
||||
marker.anchoredPosition.y + (marker.anchorMin.y - targetToggle.pivot.y) * targetToggle.rect.height,
|
||||
0f);
|
||||
Vector3 targetWorldPosition = targetToggle.TransformPoint(targetLocalPosition);
|
||||
marker.DOKill();
|
||||
marker.DOMove(targetWorldPosition, SelectionMarkerMoveDuration)
|
||||
.SetEase(Ease.OutCubic)
|
||||
.OnComplete(() => marker.SetParent(targetToggle, true));
|
||||
}
|
||||
|
||||
private void RefreshCombatReadiness()
|
||||
{
|
||||
CombatReadinessForm form = View.combatRandinessForm;
|
||||
if (form == null)
|
||||
{
|
||||
Log.Warning("LobbyForm combat readiness form is not configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
SaveData save = GameEntry.Save.Data;
|
||||
if (save == null || form.View == null || form.View.squadForm == null)
|
||||
{
|
||||
Log.Warning("LobbyForm can not refresh combat readiness.");
|
||||
return;
|
||||
}
|
||||
|
||||
form.View.squadForm.RefreshCharacterList(save.characters);
|
||||
}
|
||||
|
||||
private void RefreshWarehouse()
|
||||
{
|
||||
if (View.warehouseForm == null)
|
||||
{
|
||||
Log.Warning("LobbyForm warehouse form is not configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
SaveData save = GameEntry.Save.Data;
|
||||
View.warehouseForm.Refresh(save != null ? save.mainWarehouse : null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d236e85e2eab43f6904de56f9e5246d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,11 +6,11 @@ namespace SepCore.UI
|
||||
[DisallowMultipleComponent]
|
||||
public partial class LobbyView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.UI.Button homeButton;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle homeToggle;
|
||||
[SerializeField] public global::UnityEngine.RectTransform selectionMarkerObject;
|
||||
[SerializeField] public global::UnityEngine.UI.Button warehouseButton;
|
||||
[SerializeField] public global::UnityEngine.UI.Button loadoutButton;
|
||||
[SerializeField] public global::SepCore.UI.WarehouseView warehouseView;
|
||||
[SerializeField] public global::SepCore.UI.CombatReadinessView combatRandinessView;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle warehouseToggle;
|
||||
[SerializeField] public global::UnityEngine.UI.Toggle loadoutToggle;
|
||||
[SerializeField] public global::SepCore.UI.CombatReadinessForm combatRandinessForm;
|
||||
[SerializeField] public global::SepCore.UI.WarehouseForm warehouseForm;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class MainWarehouseForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private MainWarehouseView _view = null;
|
||||
|
||||
public MainWarehouseView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca70f33fa4f2c4a989b89f280e24201a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,20 +0,0 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class MainWarehouseView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.UI.Button homeButton;
|
||||
[SerializeField] public global::UnityEngine.UI.Button warehouseButton;
|
||||
[SerializeField] public global::UnityEngine.UI.Button loadoutButton;
|
||||
[SerializeField] public global::UnityEngine.UI.InputField searchInput;
|
||||
[SerializeField] public global::UnityEngine.UI.Button sortButton;
|
||||
[SerializeField] public global::UnityEngine.UI.ScrollRect itemScroll;
|
||||
[SerializeField] public global::UnityEngine.RectTransform warehouseSlotRoot;
|
||||
[SerializeField] public global::SepCore.UI.WarehouseSlotItem warehouseSlotTemplate;
|
||||
[SerializeField] public global::UnityEngine.UI.Text itemCountText;
|
||||
[SerializeField] public global::SepCore.UI.ItemDetailsView itemDetailsView;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f169da115e10a47e4b0b3bfefaff0d71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,6 +6,7 @@
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f",
|
||||
"GUID:11ec41dbc3557e6499b2845ba531a9b0",
|
||||
"GUID:363c5eb08ff8e6a439b85e37b8c20d96",
|
||||
"GUID:3bb549212964b4192b427888ac9382e7",
|
||||
"GUID:f51ebe6a0ceec4240a699833d6309b23",
|
||||
"GUID:d54b9488b03814a44ab937f0aeb738b1"
|
||||
],
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
@@ -10,7 +11,7 @@ namespace SepCore.UI
|
||||
public sealed class UISerializationRoot : MonoBehaviour
|
||||
{
|
||||
[Serializable]
|
||||
public sealed class NestedViewReference
|
||||
public sealed class NestedFormReference
|
||||
{
|
||||
[SerializeField] private UISerializationRoot root;
|
||||
[SerializeField] private bool generateReference;
|
||||
@@ -21,7 +22,7 @@ namespace SepCore.UI
|
||||
public string VariableName => variableName;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal NestedViewReference(UISerializationRoot nestedRoot, string defaultVariableName)
|
||||
internal NestedFormReference(UISerializationRoot nestedRoot, string defaultVariableName)
|
||||
{
|
||||
root = nestedRoot;
|
||||
generateReference = true;
|
||||
@@ -33,6 +34,19 @@ namespace SepCore.UI
|
||||
generateReference = shouldGenerate;
|
||||
variableName = generatedVariableName;
|
||||
}
|
||||
|
||||
internal bool MigrateLegacyVariableName()
|
||||
{
|
||||
if (string.IsNullOrEmpty(variableName) ||
|
||||
!variableName.EndsWith("View", StringComparison.Ordinal) ||
|
||||
variableName.Length <= 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
variableName = variableName.Substring(0, variableName.Length - 4) + "Form";
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -40,10 +54,11 @@ namespace SepCore.UI
|
||||
private List<UISerializationItem> serializationItems = new List<UISerializationItem>();
|
||||
|
||||
[SerializeField, HideInInspector]
|
||||
private List<NestedViewReference> nestedViewReferences = new List<NestedViewReference>();
|
||||
[FormerlySerializedAs("nestedViewReferences")]
|
||||
private List<NestedFormReference> nestedFormReferences = new List<NestedFormReference>();
|
||||
|
||||
public IReadOnlyList<UISerializationItem> SerializationItems => serializationItems;
|
||||
public IReadOnlyList<NestedViewReference> NestedViewReferences => nestedViewReferences;
|
||||
public IReadOnlyList<NestedFormReference> NestedFormReferences => nestedFormReferences;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private bool refreshQueued;
|
||||
@@ -76,8 +91,18 @@ namespace SepCore.UI
|
||||
}
|
||||
|
||||
bool itemsChanged = !HasSameItems(ownedItems);
|
||||
bool nestedViewsChanged = !HasSameNestedViews(directNestedRoots);
|
||||
if (!itemsChanged && !nestedViewsChanged)
|
||||
bool nestedFormsChanged = !HasSameNestedForms(directNestedRoots);
|
||||
bool nestedNamesChanged = false;
|
||||
for (int i = 0; i < directNestedRoots.Count; i++)
|
||||
{
|
||||
NestedFormReference existing = FindNestedForm(directNestedRoots[i]);
|
||||
if (existing != null)
|
||||
{
|
||||
nestedNamesChanged |= existing.MigrateLegacyVariableName();
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemsChanged && !nestedFormsChanged && !nestedNamesChanged)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -88,24 +113,24 @@ namespace SepCore.UI
|
||||
serializationItems.AddRange(ownedItems);
|
||||
}
|
||||
|
||||
if (nestedViewsChanged)
|
||||
if (nestedFormsChanged)
|
||||
{
|
||||
var next = new List<NestedViewReference>(directNestedRoots.Count);
|
||||
var next = new List<NestedFormReference>(directNestedRoots.Count);
|
||||
for (int i = 0; i < directNestedRoots.Count; i++)
|
||||
{
|
||||
UISerializationRoot nestedRoot = directNestedRoots[i];
|
||||
NestedViewReference existing = FindNestedView(nestedRoot);
|
||||
next.Add(existing ?? new NestedViewReference(nestedRoot, CreateDefaultNestedViewVariableName(nestedRoot)));
|
||||
NestedFormReference existing = FindNestedForm(nestedRoot);
|
||||
next.Add(existing ?? new NestedFormReference(nestedRoot, CreateDefaultNestedFormVariableName(nestedRoot)));
|
||||
}
|
||||
|
||||
nestedViewReferences = next;
|
||||
nestedFormReferences = next;
|
||||
}
|
||||
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetNestedViewReference(UISerializationRoot nestedRoot, bool shouldGenerate, string variableName)
|
||||
public bool SetNestedFormReference(UISerializationRoot nestedRoot, bool shouldGenerate, string variableName)
|
||||
{
|
||||
if (nestedRoot == null || FindNearestParentRoot(nestedRoot.transform) != this)
|
||||
{
|
||||
@@ -113,7 +138,7 @@ namespace SepCore.UI
|
||||
}
|
||||
|
||||
RefreshItems();
|
||||
NestedViewReference reference = FindNestedView(nestedRoot);
|
||||
NestedFormReference reference = FindNestedForm(nestedRoot);
|
||||
if (reference == null)
|
||||
{
|
||||
throw new InvalidOperationException("The nested root is not registered.");
|
||||
@@ -130,7 +155,7 @@ namespace SepCore.UI
|
||||
return true;
|
||||
}
|
||||
|
||||
public static string CreateDefaultNestedViewVariableName(UISerializationRoot nestedRoot)
|
||||
public static string CreateDefaultNestedFormVariableName(UISerializationRoot nestedRoot)
|
||||
{
|
||||
string sourceName = nestedRoot == null ? "nested" : nestedRoot.gameObject.name.Replace("(Clone)", string.Empty).Trim();
|
||||
if (sourceName.EndsWith("Form", StringComparison.Ordinal) && sourceName.Length > 4)
|
||||
@@ -148,7 +173,7 @@ namespace SepCore.UI
|
||||
identifier = "Nested";
|
||||
}
|
||||
|
||||
return char.ToLowerInvariant(identifier[0]) + identifier.Substring(1) + "View";
|
||||
return char.ToLowerInvariant(identifier[0]) + identifier.Substring(1) + "Form";
|
||||
}
|
||||
|
||||
internal void QueueRefresh()
|
||||
@@ -220,16 +245,16 @@ namespace SepCore.UI
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HasSameNestedViews(List<UISerializationRoot> found)
|
||||
private bool HasSameNestedForms(List<UISerializationRoot> found)
|
||||
{
|
||||
if (nestedViewReferences.Count != found.Count)
|
||||
if (nestedFormReferences.Count != found.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < found.Count; i++)
|
||||
{
|
||||
if (nestedViewReferences[i] == null || nestedViewReferences[i].Root != found[i])
|
||||
if (nestedFormReferences[i] == null || nestedFormReferences[i].Root != found[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -238,11 +263,11 @@ namespace SepCore.UI
|
||||
return true;
|
||||
}
|
||||
|
||||
private NestedViewReference FindNestedView(UISerializationRoot nestedRoot)
|
||||
private NestedFormReference FindNestedForm(UISerializationRoot nestedRoot)
|
||||
{
|
||||
for (int i = 0; i < nestedViewReferences.Count; i++)
|
||||
for (int i = 0; i < nestedFormReferences.Count; i++)
|
||||
{
|
||||
NestedViewReference reference = nestedViewReferences[i];
|
||||
NestedFormReference reference = nestedFormReferences[i];
|
||||
if (reference != null && reference.Root == nestedRoot)
|
||||
{
|
||||
return reference;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82e9f2ea2a9254e848f8afcf5ff556e9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Collections.Generic;
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 编队界面逻辑(手写 partial,与自动生成的 SquadForm.cs 合并)。
|
||||
/// 以传入的角色列表重建角色槽列表,模板槽来自 SquadView.characterSlotTemplate。
|
||||
/// </summary>
|
||||
public partial class SquadForm : UGuiForm
|
||||
{
|
||||
/// <summary>
|
||||
/// 按传入的角色列表重建角色槽列表 UI,每名角色一个槽位。
|
||||
/// </summary>
|
||||
public void RefreshCharacterList(IReadOnlyList<CharacterSave> characters)
|
||||
{
|
||||
SquadView squadView = View;
|
||||
if (squadView == null || squadView.characterSlotRoot == null ||
|
||||
squadView.characterSlotTemplate == null)
|
||||
{
|
||||
Log.Warning("SquadForm is not fully configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterSlotItem template = squadView.characterSlotTemplate;
|
||||
template.gameObject.SetActive(false);
|
||||
|
||||
for (int i = squadView.characterSlotRoot.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
Transform child = squadView.characterSlotRoot.GetChild(i);
|
||||
if (child == template.transform)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
int characterCount = characters != null ? characters.Count : 0;
|
||||
for (int i = 0; i < characterCount; i++)
|
||||
{
|
||||
CharacterSlotItem slot = Instantiate(template, squadView.characterSlotRoot);
|
||||
slot.gameObject.SetActive(true);
|
||||
slot.SetCharacter(characters[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a629f39601d3456ca1a8228059fa845
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class SquadForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private SquadView _view = null;
|
||||
|
||||
public SquadView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6542ec01d550457587508eff74a6957
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class SquadView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI squadMemberText;
|
||||
[SerializeField] public global::UnityEngine.RectTransform characterSlotRoot;
|
||||
[SerializeField] public global::SepCore.UI.CharacterSlotItem characterSlotTemplate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6eacd1573559d4784862ed9c21d5928c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,73 @@
|
||||
using System.Collections.Generic;
|
||||
using GameFramework.Event;
|
||||
using SepCore.Base;
|
||||
using SepCore.Definition;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 主仓库界面逻辑(手写 partial,与自动生成的 WarehouseForm.cs 合并)。
|
||||
/// 只提供仓库界面能力,数据由调用方(LobbyForm)传入;
|
||||
/// 监听格子点击事件,驱动选中高亮与详情界面刷新。
|
||||
/// 注意:本表单作为嵌套表单使用,UGF 生命周期不会被框架调用,
|
||||
/// 事件订阅改为幂等式(EnsureEventBound)。
|
||||
/// </summary>
|
||||
public partial class WarehouseForm : UGuiForm
|
||||
{
|
||||
private bool _eventBound = false;
|
||||
|
||||
/// <summary>
|
||||
/// 用主仓库内容刷新整个仓库界面(物品列表)。
|
||||
/// </summary>
|
||||
public void Refresh(IReadOnlyList<ItemStack> stacks)
|
||||
{
|
||||
EnsureEventBound();
|
||||
|
||||
InventoryForm inventoryForm = View.inventoryPanelForm;
|
||||
if (inventoryForm == null)
|
||||
{
|
||||
Log.Warning("WarehouseForm inventory panel form is not configured.");
|
||||
return;
|
||||
}
|
||||
|
||||
inventoryForm.RefreshList(stacks);
|
||||
}
|
||||
|
||||
private void EnsureEventBound()
|
||||
{
|
||||
if (_eventBound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_eventBound = true;
|
||||
GameEntry.Event.Subscribe(WarehouseSlotItemClickEventArgs.EventId, OnWarehouseSlotItemClick);
|
||||
}
|
||||
|
||||
private void OnWarehouseSlotItemClick(object sender, GameEventArgs e)
|
||||
{
|
||||
if (this == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WarehouseSlotItemClickEventArgs ne = (WarehouseSlotItemClickEventArgs)e;
|
||||
int slotId = ne.SlotId;
|
||||
|
||||
if (View.inventoryPanelForm == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
View.inventoryPanelForm.SetSelectedSlot(slotId);
|
||||
|
||||
int itemId = View.inventoryPanelForm.GetItemIdAtSlot(slotId);
|
||||
if (itemId != 0 && View.itemDetailsPanelForm != null)
|
||||
{
|
||||
View.itemDetailsPanelForm.Refresh(itemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be961300f50004e35ad24b4ff3368124
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,7 +6,7 @@ namespace SepCore.UI
|
||||
[DisallowMultipleComponent]
|
||||
public partial class WarehouseView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::SepCore.UI.InventoryView inventoryPanelView;
|
||||
[SerializeField] public global::SepCore.UI.ItemDetailsView itemDetailsPanelView;
|
||||
[SerializeField] public global::SepCore.UI.InventoryForm inventoryPanelForm;
|
||||
[SerializeField] public global::SepCore.UI.ItemDetailsForm itemDetailsPanelForm;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user