많은 작업을 했지만 요약하면
DB에 아이템 정보를 넣어주고
Item Sheet에도 아이템 정보를 넣어주고
로그인을 할 때 메모리에 아이템 정보를 할당하고 클라이언트에도 전달하는 작업까지 완료
이어서는 몬스터가 아이템을 드랍
{
"weapons": [
{
"id": "1",
"name": "견습생의 검",
"weaponType" : "Sword",
"damage": "10"
},
{
"id": "2",
"name": "견습생의 활",
"weaponType" : "Bow",
"damage": "5"
}
],
"armors": [
{
"id": "100",
"name": "뼈 값옷",
"weaponType" : "Armor",
"defence": "15"
},
{
"id": "101",
"name": "뼈 투구",
"weaponType" : "Helmet",
"defence": "5"
}
],
"consumables": [
{
"id": "200",
"name": "HP 물약",
"consumableType" : "Potion",
"damage": "10"
}
]
}
using System;
using System.Collections.Generic;
using System.Text;
namespace Server.Game
{
// 진짜 아이템 인벤토리만 해당할지는 나중에
// 착용 아이템, 보관 아이템 등을 똑같이 관리 가능하기 때문
// lock이 필요하지 않을까?
// => Inventory class를 어디서 사용할지가 관건
// => 실제로는 player 안에서 사용할 예정
// => 따라서 GameRoom 안에서 접근을 하기 때문에 하나의 쓰레드에서만 접근을 하게 된다. (lock x)
public class Inventory
{
Dictionary<int, Item> _items = new Dictionary<int, Item>();
public void Add(Item item)
{
_items.Add(item.ItemDbId, item);
}
public Item Get(int itemDbId)
{
Item item = null;
_items.TryGetValue(itemDbId, out item);
return item;
}
public Item Find(Func<Item, bool> condition)
{
foreach (Item item in _items.Values)
{
if (condition.Invoke(item))
return item;
}
return null;
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using Google.Protobuf.Protocol;
using Server.Data;
using Server.DB;
namespace Server.Game
{
public class Item
{
public ItemInfo Info { get; } = new ItemInfo();
public int ItemDbId
{
get { return Info.ItemDbId; }
set { Info.ItemDbId = value; }
}
public int TemplateId
{
get { return Info.TemplateId; }
set { Info.TemplateId = value; }
}
public int Count
{
get { return Info.Count; }
set { Info.Count = value; }
}
public ItemType ItemType { get; private set; }
// 이 아이템이 겹쳐지는 여부를 판단
// 일종의 캐싱의 용도
// TemplateId를 알면 DataManager에 접근해서 해당하는 Max count를 보는 식으로
// 겹쳐지는 여부를 알 수가 있다.
// 마찬가지로 아이템 타입만 알면 Stackable인지 어느정도 확인할 수가 있다.
public bool Stackable { get; protected set; }
public Item(ItemType itemType)
{
ItemType = ItemType;
}
public static Item MakeItem(ItemDb itemDb)
{
Item item = null;
ItemData itemData = null;
DataManager.ItemDict.TryGetValue(itemDb.TemplateId, out itemData);
if (itemData == null)
return null;
switch (itemData.itemType)
{
case ItemType.Weapon:
item = new Weapon(itemDb.TemplateId);
break;
case ItemType.Armor:
item = new Armor(itemDb.TemplateId);
break;
case ItemType.Consumable:
item = new Consumable(itemDb.TemplateId);
break;
}
if (item != null)
{
item.ItemDbId = itemDb.ItemDbId;
item.Count = itemDb.Count;
}
return item;
}
}
public class Weapon : Item
{
public WeaponType WeaponType { get; private set; }
public int Damage { get; private set; }
// TemplateId에 따라 WeaponType과 Damage를 채워줘야 한다.
public Weapon(int templateId) : base(ItemType.Weapon)
{
}
void Init(int templateId)
{
ItemData itemData = null;
DataManager.ItemDict.TryGetValue(templateId, out itemData);
if (itemData.itemType != ItemType.Weapon)
return;
WeaponData data = (WeaponData)itemData;
{
TemplateId = data.id;
// 무기는 겹치는 개념이 아니기 때문
Count = 1;
WeaponType = data.weaponType;
Damage = data.damage;
Stackable = false;
}
}
}
public class Armor : Item
{
public ArmorType ArmorType { get; private set; }
public int Defence { get; private set; }
// TemplateId에 따라 WeaponType과 Damage를 채워줘야 한다.
public Armor(int templateId) : base(ItemType.Armor)
{
Init(templateId);
}
void Init(int templateId)
{
ItemData itemData = null;
DataManager.ItemDict.TryGetValue(templateId, out itemData);
if (itemData.itemType != ItemType.Armor)
return;
ArmorData data = (ArmorData)itemData;
{
TemplateId = data.id;
// 무기는 겹치는 개념이 아니기 때문
Count = 1;
ArmorType = data.armorType;
Defence = data.defence;
Stackable = false;
}
}
}
public class Consumable : Item
{
public ConsumableType ConsumableType { get; private set; }
public int MaxCount { get; private set; }
// TemplateId에 따라 WeaponType과 Damage를 채워줘야 한다.
public Consumable(int templateId) : base(ItemType.Consumable)
{
Init(templateId);
}
void Init(int templateId)
{
ItemData itemData = null;
DataManager.ItemDict.TryGetValue(templateId, out itemData);
if (itemData.itemType != ItemType.Consumable)
return;
ConsumableData data = (ConsumableData)itemData;
{
TemplateId = data.id;
// 무기는 겹치는 개념이 아니기 때문
Count = 1;
MaxCount = data.maxCount;
ConsumableType = data.consumableType;
Stackable = (data.maxCount > 1);
}
}
}
}
// 클라쪽에서 player를 선택 한 다음 Game에 들어올 때 작업
public void HandleEnterGame(C_EnterGame enterGamePacket)
{
if (ServerState != PlayerServerState.ServerStateLobby)
return;
LobbyPlayerInfo playerInfo = LobbyPlayers.Find(p => p.Name == enterGamePacket.Name);
if (playerInfo == null)
return;
MyPlayer = ObjectManager.Instance.Add<Player>();
{
MyPlayer.PlayerDbId = playerInfo.PlayerDbId;
MyPlayer.Info.Name = playerInfo.Name;
MyPlayer.Info.PosInfo.State = CreatureState.Idle;
MyPlayer.Info.PosInfo.MoveDir = MoveDir.Down;
MyPlayer.Info.PosInfo.PosX = 0;
MyPlayer.Info.PosInfo.PosY = 0;
MyPlayer.Stat.MergeFrom(playerInfo.StatInfo);
MyPlayer.Session = this;
S_ItemList itemListPacket = new S_ItemList();
// 이 부분은 게임에 들어가기 이전 상태이다 보니
// 여기서 바로 DB에 접근을 해도 크게 문제가 없는 상황
// PreGame은 DB 접근 안전지대와 같다.
// Item 목록을 갖고 온다.
using (AppDbContext db = new AppDbContext())
{
List<ItemDb> items = db.Items
.Where(i => i.OwnerDbId == playerInfo.PlayerDbId)
.ToList();
foreach (ItemDb itemDb in items)
{
Item item = Item.MakeItem(itemDb);
if (item != null)
{
MyPlayer.Inven.Add(item);
ItemInfo info = new ItemInfo();
info.MergeFrom(item.Info);
itemListPacket.Items.Add(info);
}
}
}
// TODO 클라한테도 아이템 목록을 전달
Send(itemListPacket);
}
ServerState = PlayerServerState.ServerStateGame;
GameRoom room = RoomManager.Instance.Find(1);
room.Push(room.EnterGame, MyPlayer);
}