Added "ToString" methods for Items, Packages, and Actors for easier debugging. Rewrote dealing code in InventoryItem as well as the WorldMaster. Rewrote how Bazaar and Retainer inventory is stored on the DB, merging all three tables into one. Removed a bunch of DB code due to the previous point. Random Item cleanup.

This commit is contained in:
Filip Maj 2019-06-06 01:43:27 -04:00
parent e96cc0c758
commit 3dcd9af6c0
10 changed files with 656 additions and 857 deletions

View File

@ -1113,7 +1113,7 @@ namespace FFXIVClassic_Map_Server
player.GetItemPackage(ItemPackage.NORMAL).InitList(GetItemPackage(player, 0, ItemPackage.NORMAL)); player.GetItemPackage(ItemPackage.NORMAL).InitList(GetItemPackage(player, 0, ItemPackage.NORMAL));
player.GetItemPackage(ItemPackage.KEYITEMS).InitList(GetItemPackage(player, 0, ItemPackage.KEYITEMS)); player.GetItemPackage(ItemPackage.KEYITEMS).InitList(GetItemPackage(player, 0, ItemPackage.KEYITEMS));
player.GetItemPackage(ItemPackage.CURRENCY_CRYSTALS).InitList(GetItemPackage(player, 0, ItemPackage.CURRENCY_CRYSTALS)); player.GetItemPackage(ItemPackage.CURRENCY_CRYSTALS).InitList(GetItemPackage(player, 0, ItemPackage.CURRENCY_CRYSTALS));
player.GetItemPackage(ItemPackage.BAZAAR).InitList(GetBazaar(player)); player.GetItemPackage(ItemPackage.BAZAAR).InitList(GetItemPackage(player, 0, ItemPackage.BAZAAR));
player.GetItemPackage(ItemPackage.MELDREQUEST).InitList(GetItemPackage(player, 0, ItemPackage.MELDREQUEST)); player.GetItemPackage(ItemPackage.MELDREQUEST).InitList(GetItemPackage(player, 0, ItemPackage.MELDREQUEST));
player.GetItemPackage(ItemPackage.LOOT).InitList(GetItemPackage(player, 0, ItemPackage.LOOT)); player.GetItemPackage(ItemPackage.LOOT).InitList(GetItemPackage(player, 0, ItemPackage.LOOT));
@ -1435,7 +1435,7 @@ namespace FFXIVClassic_Map_Server
return slot; return slot;
} }
public static List<InventoryItem> GetItemPackage(Player player, uint slotOffset, uint type) public static List<InventoryItem> GetItemPackage(Character owner, uint slotOffset, uint type)
{ {
List<InventoryItem> items = new List<InventoryItem>(); List<InventoryItem> items = new List<InventoryItem>();
@ -1453,6 +1453,14 @@ namespace FFXIVClassic_Map_Server
quantity, quantity,
quality, quality,
dealingValue,
dealingMode,
dealingAttached1,
dealingAttached2,
dealingAttached3,
dealingTag,
bazaarMode,
durability, durability,
mainQuality, mainQuality,
subQuality1, subQuality1,
@ -1471,328 +1479,12 @@ namespace FFXIVClassic_Map_Server
FROM characters_inventory FROM characters_inventory
INNER JOIN server_items ON serverItemId = server_items.id INNER JOIN server_items ON serverItemId = server_items.id
LEFT JOIN server_items_modifiers ON server_items.id = server_items_modifiers.id LEFT JOIN server_items_modifiers ON server_items.id = server_items_modifiers.id
WHERE characterId = @charId AND itemPackage = @type"; LEFT JOIN server_items_dealing ON server_items.id = server_items_dealing.id
WHERE characterId = @charId AND itemPackage = @type
MySqlCommand cmd = new MySqlCommand(query, conn); ORDER BY slot ASC";
cmd.Parameters.AddWithValue("@charId", player.actorId);
cmd.Parameters.AddWithValue("@type", type);
ushort slot = 0;
using (MySqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
uint uniqueId = reader.GetUInt32("serverItemId");
uint itemId = reader.GetUInt32("itemId");
int quantity = reader.GetInt32("quantity");
byte qualityNumber = reader.GetByte("quality");
bool hasModifier = !reader.IsDBNull(reader.GetOrdinal("modifierId"));
InventoryItem.ItemModifier modifier = null;
if (hasModifier)
modifier = new InventoryItem.ItemModifier(reader);
InventoryItem item = new InventoryItem(uniqueId, Server.GetItemGamedata(itemId), quantity, qualityNumber, modifier);
items.Add(item);
}
}
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
return items;
}
public static bool CreateBazaarEntry(Player owner, InventoryItem reward, InventoryItem seek, int rewardAmount, int seekAmount, byte bazaarMode, int sellPrice = 0)
{
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
string query = @"
INSERT INTO characters_inventory_bazaar
(characterId, rewardId, seekId, rewardAmount, seekAmount, bazaarMode, sellPrice)
VALUES
(@characterId, @rewardId, @seekId, @rewardAmount, @seekAmount, @bazaarMode, @sellPrice);
";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@characterId", owner.actorId);
cmd.Parameters.AddWithValue("@rewardId", reward.uniqueId);
cmd.Parameters.AddWithValue("@seekId", seek.uniqueId);
cmd.Parameters.AddWithValue("@rewardAmount", rewardAmount);
cmd.Parameters.AddWithValue("@seekAmount", seekAmount);
cmd.Parameters.AddWithValue("@bazaarMode", bazaarMode);
cmd.Parameters.AddWithValue("@sellPrice", sellPrice);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
return false;
}
finally
{
conn.Dispose();
}
}
return true;
}
public static void ClearBazaarEntry(Player owner, InventoryItem reward)
{
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}; Allow User Variables=True", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
string query = @"
DELETE FROM characters_inventory_bazaar
WHERE characterId = @charId and rewardId = @rewardId;
";
MySqlCommand cmd = new MySqlCommand(query, conn); MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charId", owner.actorId); cmd.Parameters.AddWithValue("@charId", owner.actorId);
cmd.Parameters.AddWithValue("@rewardId", reward.uniqueId);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static List<InventoryItem> GetBazaar(Player player)
{
List<InventoryItem> rewardItems = new List<InventoryItem>();
Dictionary<ulong, InventoryItem> seekItems = new Dictionary<ulong, InventoryItem>();
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
string query = @"
SELECT
rewardId,
seekId,
rewardAmount,
bazaarMode,
sellPrice,
itemId,
server_items_modifiers.id AS modifierId,
quantity,
quality,
durability,
mainQuality,
subQuality1,
subQuality2,
subQuality3,
param1,
param2,
param3,
spiritbind,
materia1,
materia2,
materia3,
materia4,
materia5
FROM characters_inventory_bazaar
INNER JOIN server_items ON rewardId = server_items.id
LEFT JOIN server_items_modifiers ON server_items.id = server_items_modifiers.id
WHERE characterId = @charaId";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charaId", player.actorId);
using (MySqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
uint uniqueId = reader.GetUInt32("rewardId");
uint itemId = reader.GetUInt32("itemId");
int quantity = reader.GetInt32("quantity");
byte qualityNumber = reader.GetByte("quality");
bool hasModifier = !reader.IsDBNull(reader.GetOrdinal("modifierId"));
InventoryItem.ItemModifier modifier = null;
if (hasModifier)
modifier = new InventoryItem.ItemModifier(reader);
InventoryItem item = new InventoryItem(uniqueId, Server.GetItemGamedata(itemId), quantity, qualityNumber, modifier);
byte bazaarMode = reader.GetByte("bazaarMode");
if (bazaarMode == InventoryItem.TYPE_SINGLE || bazaarMode == InventoryItem.TYPE_MULTI || bazaarMode == InventoryItem.TYPE_STACK)
{
uint price = (uint)reader.GetInt32("sellPrice");
item.SetDealing(bazaarMode, (int)price);
}
else
{
uint seekId = reader.GetUInt32("seekId");
item.SetDealingAttached(bazaarMode, seekId);
}
rewardItems.Add(item);
}
}
string query2 = @"
SELECT
seekId,
seekAmount,
sellPrice,
itemId,
server_items_modifiers.id AS modifierId,
quantity,
quality,
durability,
mainQuality,
subQuality1,
subQuality2,
subQuality3,
param1,
param2,
param3,
spiritbind,
materia1,
materia2,
materia3,
materia4,
materia5
FROM characters_inventory_bazaar
INNER JOIN server_items ON seekId = server_items.id
LEFT JOIN server_items_modifiers ON server_items.id = server_items_modifiers.id
WHERE characterId = @charaId and bazaarMode != 11 and bazaarMode != 12 and bazaarMode != 13";
MySqlCommand cmd2 = new MySqlCommand(query2, conn);
cmd2.Parameters.AddWithValue("@charaId", player.actorId);
using (MySqlDataReader reader = cmd2.ExecuteReader())
{
while (reader.Read())
{
uint uniqueId = reader.GetUInt32("seekId");
uint itemId = reader.GetUInt32("itemId");
int quantity = reader.GetInt32("quantity");
byte qualityNumber = reader.GetByte("quality");
bool hasModifier = !reader.IsDBNull(reader.GetOrdinal("modifierId"));
InventoryItem.ItemModifier modifier = null;
if (hasModifier)
modifier = new InventoryItem.ItemModifier(reader);
InventoryItem item = new InventoryItem(uniqueId, Server.GetItemGamedata(itemId), quantity, qualityNumber, modifier);
item.SetHasAttached(true);
seekItems.Add(uniqueId, item);
}
}
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
List<InventoryItem> items = new List<InventoryItem>();
ushort slot = 0;
foreach (InventoryItem reward in rewardItems)
{
if (reward.dealingMode == InventoryItem.DEALINGMODE_PRICED)
{
reward.slot = slot++;
items.Add(reward);
}
else
{
if (seekItems.ContainsKey(reward.GetAttached()))
{
reward.slot = slot++;
items.Add(reward);
InventoryItem seek = seekItems[reward.GetAttached()];
seek.slot = slot++;
items.Add(seek);
reward.SetAttachedIndex(7, seek.slot);
}
}
}
return items;
}
public static List<InventoryItem> GetInventory(Retainer retainer, uint type)
{
List<InventoryItem> items = new List<InventoryItem>();
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
string query = @"
SELECT
serverItemId,
itemId,
server_items_modifiers.id AS modifierId,
quantity,
quality,
durability,
mainQuality,
subQuality1,
subQuality2,
subQuality3,
param1,
param2,
param3,
spiritbind,
materia1,
materia2,
materia3,
materia4,
materia5
FROM retainers_inventory
INNER JOIN server_items ON serverItemId = server_items.id
LEFT JOIN server_items_modifiers ON server_items.id = server_items_modifiers.id
WHERE retainerId = @retainerId AND itemPackage = @type";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@retainerId", retainer.GetRetainerId());
cmd.Parameters.AddWithValue("@type", type); cmd.Parameters.AddWithValue("@type", type);
ushort slot = 0; ushort slot = 0;
@ -1800,19 +1492,7 @@ namespace FFXIVClassic_Map_Server
{ {
while (reader.Read()) while (reader.Read())
{ {
uint uniqueId = reader.GetUInt32("serverItemId"); InventoryItem item = new InventoryItem(reader);
uint itemId = reader.GetUInt32("itemId");
int quantity = reader.GetInt32("quantity");
byte qualityNumber = reader.GetByte("quality");
bool hasModifier = !reader.IsDBNull(reader.GetOrdinal("modifierId"));
InventoryItem.ItemModifier modifier = null;
if (hasModifier)
modifier = new InventoryItem.ItemModifier(reader);
InventoryItem item = new InventoryItem(uniqueId, Server.GetItemGamedata(itemId), quantity, qualityNumber, modifier);
items.Add(item); items.Add(item);
} }
} }
@ -1830,6 +1510,11 @@ namespace FFXIVClassic_Map_Server
return items; return items;
} }
public static InventoryItem CreateItem(InventoryItem item, uint quantity)
{
return CreateItem(item.itemId, (int) quantity, item.quality, item.modifiers);
}
public static InventoryItem CreateItem(uint itemId, int quantity, byte quality, InventoryItem.ItemModifier modifiers = null) public static InventoryItem CreateItem(uint itemId, int quantity, byte quality, InventoryItem.ItemModifier modifiers = null)
{ {
InventoryItem insertedItem = null; InventoryItem insertedItem = null;
@ -1862,7 +1547,7 @@ namespace FFXIVClassic_Map_Server
cmd.Parameters.AddWithValue("@quality", quality); cmd.Parameters.AddWithValue("@quality", quality);
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
insertedItem = new InventoryItem((uint)cmd.LastInsertedId, Server.GetItemGamedata(itemId), quantity, quality, modifiers); insertedItem = new InventoryItem((uint)cmd.LastInsertedId, itemId, quantity, quality, modifiers);
if (modifiers != null) if (modifiers != null)
{ {
@ -1885,7 +1570,7 @@ namespace FFXIVClassic_Map_Server
return insertedItem; return insertedItem;
} }
public static void AddItem(Player player, InventoryItem addedItem, uint type) public static void AddItem(Character owner, InventoryItem addedItem, ushort itemPackage, ushort slot)
{ {
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{ {
@ -1895,16 +1580,17 @@ namespace FFXIVClassic_Map_Server
string query = @" string query = @"
INSERT INTO characters_inventory INSERT INTO characters_inventory
(characterId, itemPackage, serverItemId) (characterId, itemPackage, serverItemId, slot)
VALUES VALUES
(@charId, @itemPackage, @serverItemId) (@charId, @itemPackage, @serverItemId, @slot)
"; ";
MySqlCommand cmd = new MySqlCommand(query, conn); MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@serverItemId", addedItem.uniqueId); cmd.Parameters.AddWithValue("@serverItemId", addedItem.uniqueId);
cmd.Parameters.AddWithValue("@charId", player.actorId); cmd.Parameters.AddWithValue("@charId", owner.actorId);
cmd.Parameters.AddWithValue("@itemPackage", type); cmd.Parameters.AddWithValue("@itemPackage", itemPackage);
cmd.Parameters.AddWithValue("@slot", slot);
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
} }
@ -1919,7 +1605,35 @@ namespace FFXIVClassic_Map_Server
} }
} }
public static void RemoveItem(Character owner, ulong serverItemId)
{
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}; Allow User Variables=True", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
string query = @"
DELETE FROM characters_inventory
WHERE characterId = @charId and serverItemId = @serverItemId;
";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charId", owner.actorId);
cmd.Parameters.AddWithValue("@serverItemId", serverItemId);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static void SetQuantity(ulong serverItemId, int quantity) public static void SetQuantity(ulong serverItemId, int quantity)
{ {
@ -1953,37 +1667,7 @@ namespace FFXIVClassic_Map_Server
} }
public static void RemoveItem(Player player, ulong serverItemId) public static void SetDealingInfo(InventoryItem item)
{
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}; Allow User Variables=True", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{
try
{
conn.Open();
string query = @"
DELETE FROM characters_inventory
WHERE characterId = @charId and serverItemId = @serverItemId;
";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@charId", player.actorId);
cmd.Parameters.AddWithValue("@serverItemId", serverItemId);
cmd.ExecuteNonQuery();
}
catch (MySqlException e)
{
Program.Log.Error(e.ToString());
}
finally
{
conn.Dispose();
}
}
}
public static void AddItem(Retainer retainer, InventoryItem addedItem, uint type)
{ {
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{ {
@ -1992,18 +1676,13 @@ namespace FFXIVClassic_Map_Server
conn.Open(); conn.Open();
string query = @" string query = @"
INSERT INTO retainers_inventory REPLACE INTO server_items_dealing
(retainerId, itemPackage, serverItemId) (id, dealingValue, dealingMode, dealingAttached1, dealingAttached2, dealingAttached3, dealingTag, bazaarMode)
VALUES VALUES
(@retainerId, @itemPackage, @serverItemId) (@serverItemId, @dealingValue, @dealingMode, @dealingAttached1, @dealingAttached2, @dealingAttached3, @dealingTag, @bazaarMode);
"; ";
MySqlCommand cmd = new MySqlCommand(query, conn); MySqlCommand cmd = new MySqlCommand(query, conn);
item.SaveDealingInfo(cmd);
cmd.Parameters.AddWithValue("@serverItemId", addedItem.uniqueId);
cmd.Parameters.AddWithValue("@retainerId", retainer.GetRetainerId());
cmd.Parameters.AddWithValue("@itemPackage", type);
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
} }
catch (MySqlException e) catch (MySqlException e)
@ -2017,24 +1696,23 @@ namespace FFXIVClassic_Map_Server
} }
} }
public static void RemoveItem(Retainer retainer, ulong serverItemId) public static void ClearDealingInfo(InventoryItem item)
{ {
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}; Allow User Variables=True", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
{ {
try try
{ {
conn.Open(); conn.Open();
string query = @" string query = @"
DELETE FROM retainers_inventory DELETE FROM
WHERE retainerId = @retainerId and serverItemId = @serverItemId; server_items_dealing
WHERE
id = @serverItemId;
"; ";
MySqlCommand cmd = new MySqlCommand(query, conn); MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@retainerId", retainer.GetRetainerId()); cmd.Parameters.AddWithValue("@serverItemId", item.uniqueId);
cmd.Parameters.AddWithValue("@serverItemId", serverItemId);
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
} }
catch (MySqlException e) catch (MySqlException e)
{ {
@ -2045,7 +1723,6 @@ namespace FFXIVClassic_Map_Server
conn.Dispose(); conn.Dispose();
} }
} }
} }
public static SubPacket GetLatestAchievements(Player player) public static SubPacket GetLatestAchievements(Player player)

View File

@ -197,6 +197,7 @@
<Compile Include="lua\LuaScript.cs" /> <Compile Include="lua\LuaScript.cs" />
<Compile Include="lua\LuaUtils.cs" /> <Compile Include="lua\LuaUtils.cs" />
<Compile Include="PacketProcessor.cs" /> <Compile Include="PacketProcessor.cs" />
<Compile Include="packets\receive\AchievementProgressRequestPacket.cs" />
<Compile Include="packets\receive\ChatMessagePacket.cs" /> <Compile Include="packets\receive\ChatMessagePacket.cs" />
<Compile Include="packets\receive\events\EventUpdatePacket.cs" /> <Compile Include="packets\receive\events\EventUpdatePacket.cs" />
<Compile Include="packets\receive\events\EventStartPacket.cs" /> <Compile Include="packets\receive\events\EventStartPacket.cs" />

View File

@ -18,6 +18,7 @@ using FFXIVClassic_Map_Server.actors.director;
using FFXIVClassic_Map_Server.actors.chara.ai; using FFXIVClassic_Map_Server.actors.chara.ai;
using FFXIVClassic_Map_Server.actors.chara; using FFXIVClassic_Map_Server.actors.chara;
using FFXIVClassic_Map_Server.actors.chara.player; using FFXIVClassic_Map_Server.actors.chara.player;
using FFXIVClassic_Map_Server.packets.send.actor.inventory;
namespace FFXIVClassic_Map_Server namespace FFXIVClassic_Map_Server
{ {
@ -1502,7 +1503,7 @@ namespace FFXIVClassic_Map_Server
return 2; return 2;
} }
//Check if gil is max //Check if gil is max
else if (item.itemId == 100001 && item.dealingAttached3 + itemReceiver.GetCurrentGil() > item.GetItemData().maxStack) else if (item.itemId == 100001 && item.GetTradeQuantity() + itemReceiver.GetCurrentGil() > item.GetItemData().maxStack)
{ {
return 3; return 3;
} }
@ -1515,147 +1516,153 @@ namespace FFXIVClassic_Map_Server
return Database.CreateItem(itemId, amount, quality, modifiers); return Database.CreateItem(itemId, amount, quality, modifiers);
} }
public bool BazaarBuyOperation(Player bazaar, Player buyer, InventoryItem itemToBuy, int quantity, int cost) public int AddToBazaar(Player player, InventoryItem reward, InventoryItem seek, int rewardAmount, int seekAmount, byte bazaarMode)
{ {
if (bazaar == null || buyer == null || itemToBuy == null) //Selling Items
return false; if (bazaarMode == InventoryItem.MODE_SELL_SINGLE)
if (quantity <= 0)
return false;
if (cost < 0)
return false;
if (itemToBuy.GetBazaarMode() == InventoryItem.TYPE_SINGLE || itemToBuy.GetBazaarMode() == InventoryItem.TYPE_MULTI || itemToBuy.GetBazaarMode() == InventoryItem.TYPE_STACK)
{ {
itemToBuy.ChangeQuantity(-quantity); reward.SetSelling(bazaarMode, seekAmount);
buyer.AddItem(itemToBuy.itemId, quantity, itemToBuy.quality); ItemPackage originalPackage = player.GetItemPackage(reward.itemPackage);
buyer.GetItemPackage(ItemPackage.CURRENCY_CRYSTALS).RemoveItem(1000001, cost); ItemPackage bazaarPackage = player.GetItemPackage(ItemPackage.BAZAAR);
originalPackage.MoveItem(reward, bazaarPackage);
}
else if (bazaarMode == InventoryItem.MODE_SELL_PSTACK)
{
if (rewardAmount <= reward.quantity)
{
ItemPackage originalPackage = player.GetItemPackage(reward.itemPackage);
ItemPackage bazaarPackage = player.GetItemPackage(ItemPackage.BAZAAR);
InventoryItem splitItem = Database.CreateItem(reward, (uint) rewardAmount);
if (splitItem != null)
{
reward.ChangeQuantity(-rewardAmount);
splitItem.SetSelling(bazaarMode, seekAmount);
bazaarPackage.AddItem(splitItem);
}
//TODO: Refactor so that it's not a mess like V
player.QueuePacket(InventoryBeginChangePacket.BuildPacket(player.actorId));
originalPackage.SendUpdate();
player.QueuePacket(InventoryEndChangePacket.BuildPacket(player.actorId));
}
}
else if (bazaarMode == InventoryItem.MODE_SELL_FSTACK)
{
reward.SetSelling(bazaarMode, seekAmount);
ItemPackage originalPackage = player.GetItemPackage(reward.itemPackage);
ItemPackage bazaarPackage = player.GetItemPackage(ItemPackage.BAZAAR);
originalPackage.MoveItem(reward, bazaarPackage);
} }
if (itemToBuy.quantity == 0) //Seeking Items
Database.ClearBazaarEntry(bazaar, itemToBuy); else if (bazaarMode == InventoryItem.MODE_SEEK_ITEM || bazaarMode == InventoryItem.MODE_SEEK_REPAIR)
bazaar.CheckBazaarFlags();
return true;
}
public bool BazaarSellOperation(Player bazaar, Player buyer, InventoryItem reward, int rewardQuantity, InventoryItem seek, int seekQuantity)
{
if (bazaar == null || buyer == null || reward == null || seek == null)
return false;
if (rewardQuantity <= 0 || seekQuantity <= 0)
return false;
if (reward.GetBazaarMode() == InventoryItem.TYPE_SEEK_ITEM)
{ {
InventoryItem seekBazaar = bazaar.GetItemPackage(ItemPackage.BAZAAR).GetItemAttachedTo(reward); ItemPackage originalRewardPackage = player.GetItemPackage(reward.itemPackage);
bazaar.RemoveItem(reward, rewardQuantity); ItemPackage originalSeekPackage = player.GetItemPackage(seek.itemPackage);
bazaar.RemoveItem(seekBazaar, seekQuantity); ItemPackage bazaarPackage = player.GetItemPackage(ItemPackage.BAZAAR);
bazaar.AddItem(seekBazaar);
bazaar.AddItem(seek.itemId, seekQuantity, seek.quality);
buyer.RemoveItem(seek, seekQuantity); InventoryItem finalReward, finalSeek;
buyer.AddItem(reward);
}
Database.ClearBazaarEntry(bazaar, reward); /////REWARD/////
bazaar.CheckBazaarFlags(); //No Split, just move
if (rewardAmount == reward.itemData.maxStack)
return true;
}
public void AddToBazaar(Player player, InventoryItem reward, InventoryItem seek, int rewardAmount, int seekAmount, byte bazaarMode)
{
bool succ = false;
if (bazaarMode == InventoryItem.TYPE_SINGLE || bazaarMode == InventoryItem.TYPE_MULTI || bazaarMode == InventoryItem.TYPE_STACK)
succ = Database.CreateBazaarEntry(player, reward, seek, rewardAmount, 0, bazaarMode, seekAmount);
else
succ = Database.CreateBazaarEntry(player, reward, seek, rewardAmount, seekAmount, bazaarMode);
if (succ)
{
if (bazaarMode != InventoryItem.TYPE_SINGLE && bazaarMode != InventoryItem.TYPE_MULTI && bazaarMode != InventoryItem.TYPE_STACK)
{ {
reward.SetDealingAttached(bazaarMode, seek.uniqueId); finalReward = reward;
seek.SetHasAttached(true); originalRewardPackage.RemoveItem(reward);
player.GetItemPackage(ItemPackage.BAZAAR).StartSendUpdate();
player.GetItemPackage(ItemPackage.BAZAAR).AddItem(reward);
player.GetItemPackage(ItemPackage.BAZAAR).AddItem(seek);
reward.SetAttachedIndex(ItemPackage.BAZAAR, seek.slot);
player.GetItemPackage(ItemPackage.BAZAAR).DoneSendUpdate();
} }
else else //Splitting (ughh)
{ {
reward.SetDealing(bazaarMode, seekAmount); InventoryItem splitItem = Database.CreateItem(reward, (uint)rewardAmount);
player.GetItemPackage(ItemPackage.BAZAAR).StartSendUpdate();
player.GetItemPackage(ItemPackage.BAZAAR).AddItem(reward); if (splitItem != null)
player.GetItemPackage(ItemPackage.BAZAAR).DoneSendUpdate(); {
reward.ChangeQuantity(-rewardAmount);
finalReward = splitItem;
player.QueuePacket(InventoryBeginChangePacket.BuildPacket(player.actorId));
originalRewardPackage.SendUpdate();
player.QueuePacket(InventoryEndChangePacket.BuildPacket(player.actorId));
}
else
return ItemPackage.ERROR_SYSTEM;
} }
/////SEEK/////
//No Split, just move
if (seekAmount == seek.itemData.maxStack)
{
finalSeek = seek;
originalSeekPackage.RemoveItem(seek);
}
else //Splitting (ughh)
{
InventoryItem splitItem = Database.CreateItem(seek, (uint)seekAmount);
if (splitItem != null)
{
seek.ChangeQuantity(-seekAmount);
finalSeek = splitItem;
player.QueuePacket(InventoryBeginChangePacket.BuildPacket(player.actorId));
originalSeekPackage.SendUpdate();
player.QueuePacket(InventoryEndChangePacket.BuildPacket(player.actorId));
}
else
return ItemPackage.ERROR_SYSTEM;
}
/////FINAL/////
bazaarPackage.AddItem(finalReward);
bazaarPackage.AddItem(finalSeek);
finalReward.SetAsOfferTo(bazaarMode, finalSeek);
player.QueuePacket(InventoryBeginChangePacket.BuildPacket(player.actorId));
bazaarPackage.SendUpdate();
player.QueuePacket(InventoryEndChangePacket.BuildPacket(player.actorId));
} }
player.CheckBazaarFlags(); player.CheckBazaarFlags();
return ItemPackage.ERROR_SUCCESS;
} }
public int RemoveFromBazaar(Player player, InventoryItem reward)
public void RemoveFromBazaar(Player player, InventoryItem rewardRef)
{ {
ushort attachedItemPackage = (ushort)((rewardRef.dealingAttached1 >> 16) & 0xFF); InventoryItem seek = reward.GetOfferedTo();
ushort attachedSlot = (ushort) (rewardRef.dealingAttached1 & 0xFF); ItemPackage bazaarPackage = player.GetItemPackage(ItemPackage.BAZAAR);
InventoryItem seekRef = rewardRef.IsSelling() ? null : player.GetItemPackage(attachedItemPackage).GetItemAtSlot(attachedSlot); bazaarPackage.RemoveItem(reward);
reward.SetNormal();
player.AddItem(reward);
Database.ClearDealingInfo(reward);
Database.ClearBazaarEntry(player, rewardRef); if (seek != null)
player.GetItemPackage(ItemPackage.BAZAAR).RemoveItem(rewardRef);
bool isSelling = rewardRef.IsSelling();
rewardRef.SetNormal();
if (seekRef != null)
player.GetItemPackage(ItemPackage.BAZAAR).RemoveItem(seekRef);
player.AddItem(rewardRef);
if (!isSelling)
{ {
seekRef.SetNormal(); bazaarPackage.RemoveItem(seek);
player.AddItem(seekRef); seek.SetNormal();
player.AddItem(seek);
Database.ClearDealingInfo(seek);
} }
player.CheckBazaarFlags(); player.CheckBazaarFlags();
return ItemPackage.ERROR_SUCCESS;
} }
/*
public void TransactionBazaar(Player owner, Player other, InventoryItem reward, InventoryItem seek, int rewardAmount, int seekAmount) public int BazaarBuyOperation(Player bazaar, Player buyer, InventoryItem itemToBuy, int quantity, int cost)
{ {
Database.ClearBazaarEntry(owner, reward, seek); //TODO: Implement
return ItemPackage.ERROR_SYSTEM;
}
//Remove Bazaar Items from owner public int BazaarSellOperation(Player bazaar, Player buyer, InventoryItem reward, int rewardQuantity, InventoryItem seek, int seekQuantity)
owner.GetInventory(Inventory.BAZAAR).RemoveItem(reward); {
owner.GetInventory(Inventory.BAZAAR).RemoveItem(seek); //TODO: Implement
return ItemPackage.ERROR_SYSTEM;
//Remove Seek item from other }
if (seek.GetItemData().IsMoney())
other.GetInventory(Inventory.CURRENCY_CRYSTALS).RemoveItem(seek.itemId, seekAmount);
else
other.GetInventory(Inventory.NORMAL).RemoveItem(seek.itemId, seekAmount);
//Add reward to other, seek to owner
if (reward.GetItemData().IsMoney())
other.GetInventory(Inventory.CURRENCY_CRYSTALS).AddItem(reward.itemId, rewardAmount);
else
other.GetInventory(Inventory.NORMAL).AddItem(reward);
if (seek.GetItemData().IsMoney())
owner.GetInventory(Inventory.CURRENCY_CRYSTALS).AddItem(seek.itemId, seekAmount);
else
other.GetInventory(Inventory.NORMAL).AddItem(seek);
}*/
public bool SendGroupInit(Session session, ulong groupId) public bool SendGroupInit(Session session, ulong groupId)
{ {

View File

@ -744,6 +744,17 @@ namespace FFXIVClassic_Map_Server.Actors
} }
#endregion #endregion
public override string ToString()
{
if (className != null)
{
return string.Format("{0} [0x{1:X}]", className, actorId);
}
else
{
return string.Format("Unknown [0x{0:X}]", actorId);
}
}
} }
} }

View File

@ -1147,7 +1147,7 @@ namespace FFXIVClassic_Map_Server.Actors
return; return;
player.QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId, true)); player.QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId, true));
itemPackages[(ushort)id].SendUpdate(player); itemPackages[(ushort)id].SendFullPackage(player);
player.QueuePacket(InventoryEndChangePacket.BuildPacket(actorId)); player.QueuePacket(InventoryEndChangePacket.BuildPacket(actorId));
} }
@ -1179,14 +1179,6 @@ namespace FFXIVClassic_Map_Server.Actors
} }
} }
public void SetItem(InventoryItem item, ushort itemPackage, ushort slot)
{
if (itemPackages.ContainsKey(itemPackage))
{
itemPackages[itemPackage].SetItem(slot, item);
}
}
public void MoveItem(InventoryItem item, ushort destinationPackage) public void MoveItem(InventoryItem item, ushort destinationPackage)
{ {
ushort sourcePackage = item.itemPackage; ushort sourcePackage = item.itemPackage;
@ -1194,8 +1186,7 @@ namespace FFXIVClassic_Map_Server.Actors
if (!itemPackages.ContainsKey(sourcePackage) && !itemPackages.ContainsKey(destinationPackage)) if (!itemPackages.ContainsKey(sourcePackage) && !itemPackages.ContainsKey(destinationPackage))
return; return;
itemPackages[sourcePackage].RemoveItem(item); itemPackages[sourcePackage].MoveItem(item, itemPackages[destinationPackage]);
itemPackages[destinationPackage].AddItem(item);
} }
public void RemoveItem(uint catalogID) public void RemoveItem(uint catalogID)
@ -1227,15 +1218,7 @@ namespace FFXIVClassic_Map_Server.Actors
public void RemoveItem(InventoryItem item) public void RemoveItem(InventoryItem item)
{ {
RemoveItem(item, 1); itemPackages[item.itemPackage].RemoveItem(item);
}
public void RemoveItem(InventoryItem item, int quantity)
{
if (itemPackages.ContainsKey(item.itemPackage))
{
itemPackages[item.itemPackage].RemoveItem(item, quantity);
}
} }
public bool HasItem(uint catalogID) public bool HasItem(uint catalogID)
@ -1270,7 +1253,6 @@ namespace FFXIVClassic_Map_Server.Actors
return false; return false;
} }
public InventoryItem GetItem(LuaUtils.ItemRefParam reference) public InventoryItem GetItem(LuaUtils.ItemRefParam reference)
{ {
if (reference.actorId != actorId) if (reference.actorId != actorId)

View File

@ -63,7 +63,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
int i = 0; int i = 0;
foreach (InventoryItem item in itemsFromDB) foreach (InventoryItem item in itemsFromDB)
{ {
item.RefreshPositioning(owner, itemPackageCode, (ushort) i); item.SetOwner(owner, itemPackageCode, (ushort) i);
list[i++] = item; list[i++] = item;
} }
endOfListIndex = i; endOfListIndex = i;
@ -105,20 +105,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
return null; return null;
} }
public InventoryItem GetItemAttachedTo(InventoryItem attachedTo)
{
for (int i = 0; i < endOfListIndex; i++)
{
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (attachedTo.GetAttached() == item.uniqueId)
return item;
}
return null;
}
public int AddItem(uint itemId) public int AddItem(uint itemId)
{ {
return AddItem(itemId, 1, 1); return AddItem(itemId, 1, 1);
@ -129,6 +115,74 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
return AddItem(itemId, quantity, 1); return AddItem(itemId, quantity, 1);
} }
public int AddItem(uint itemId, int quantity, byte quality)
{
if (!IsSpaceForAdd(itemId, quantity, quality))
return ERROR_FULL;
ItemData gItem = Server.GetItemGamedata(itemId);
//If it's unique, abort
if (HasItem(itemId) && gItem.isExclusive)
return ERROR_HAS_UNIQUE;
if (gItem == null)
{
Program.Log.Error("Inventory.AddItem: unable to find item %u", itemId);
return ERROR_SYSTEM;
}
//Check if item id exists
int quantityCount = quantity;
for (int i = 0; i < endOfListIndex; i++)
{
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == itemId && item.quality == quality && item.quantity < gItem.maxStack)
{
int oldQuantity = item.quantity;
item.quantity = Math.Min(item.quantity + quantityCount, gItem.maxStack);
isDirty[i] = true;
quantityCount -= (gItem.maxStack - oldQuantity);
DoDatabaseQuantity(item.uniqueId, item.quantity);
if (quantityCount <= 0)
break;
}
}
//New item that spilled over
while (quantityCount > 0)
{
InventoryItem.ItemModifier modifiers = null;
if (gItem.durability != 0)
{
modifiers = new InventoryItem.ItemModifier();
modifiers.durability = (uint)gItem.durability;
}
InventoryItem addedItem = Database.CreateItem(itemId, Math.Min(quantityCount, gItem.maxStack), quality, modifiers);
addedItem.SetOwner(owner, itemPackageCode, (ushort)endOfListIndex);
isDirty[endOfListIndex] = true;
list[endOfListIndex++] = addedItem;
quantityCount -= gItem.maxStack;
DoDatabaseAdd(addedItem);
}
if (owner is Player)
{
(owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
SendUpdate();
(owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
return ERROR_SUCCESS;
}
public int AddItems(uint[] itemIds, uint[] quantity = null, byte[] quality = null) public int AddItems(uint[] itemIds, uint[] quantity = null, byte[] quality = null)
{ {
//Check if has space //Check if has space
@ -187,7 +241,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
byte setQuality = quality != null ? quality[i] : (byte)1; byte setQuality = quality != null ? quality[i] : (byte)1;
InventoryItem addedItem = Database.CreateItem(itemIds[i], Math.Min(quantityCount, gItem.maxStack), setQuality, modifiers); InventoryItem addedItem = Database.CreateItem(itemIds[i], Math.Min(quantityCount, gItem.maxStack), setQuality, modifiers);
addedItem.RefreshPositioning(owner, itemPackageCode, (ushort)endOfListIndex); addedItem.SetOwner(owner, itemPackageCode, (ushort)endOfListIndex);
isDirty[endOfListIndex] = true; isDirty[endOfListIndex] = true;
list[endOfListIndex++] = addedItem; list[endOfListIndex++] = addedItem;
quantityCount -= gItem.maxStack; quantityCount -= gItem.maxStack;
@ -206,44 +260,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
public bool CanAdd(uint[] itemIds, uint[] quantity, byte[] quality)
{
int tempInvSize = GetCount();
for (int i = 0; i < itemIds.Length; i++)
{
ItemData gItem = Server.GetItemGamedata(itemIds[i]);
//Check if item id exists and fill up til maxstack
int quantityCount = (int) (quantity != null ? quantity[i] : 1);
for (int j = 0; j < endOfListIndex; j++)
{
InventoryItem item = list[j];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == itemIds[i] && item.quality == (quality != null ? quality[i] : 1) && item.quantity < gItem.maxStack)
{
quantityCount -= (gItem.maxStack - item.quantity);
if (quantityCount <= 0)
break;
}
}
//New items that spilled over creating new stacks
while (quantityCount > 0)
{
quantityCount -= gItem.maxStack;
tempInvSize++;
}
//If the new stacks push us over capacity, can't add these items
if (tempInvSize > itemPackageCapacity)
return false;
}
return true;
}
public int AddItem(InventoryItem itemRef) public int AddItem(InventoryItem itemRef)
{ {
//If it isn't a single item (ie: armor) just add like normal (not valid for BAZAAR) //If it isn't a single item (ie: armor) just add like normal (not valid for BAZAAR)
@ -261,7 +277,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
return ERROR_SYSTEM; return ERROR_SYSTEM;
} }
itemRef.RefreshPositioning(owner, itemPackageCode, (ushort)endOfListIndex); itemRef.SetOwner(owner, itemPackageCode, (ushort)endOfListIndex);
isDirty[endOfListIndex] = true; isDirty[endOfListIndex] = true;
list[endOfListIndex++] = itemRef; list[endOfListIndex++] = itemRef;
@ -277,84 +293,31 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
public int AddItem(uint itemId, int quantity, byte quality) public int MoveItem(ushort position, ItemPackage destinationPackage)
{ {
if (!IsSpaceForAdd(itemId, quantity, quality)) InventoryItem item = GetItemAtSlot(position);
return ERROR_FULL;
ItemData gItem = Server.GetItemGamedata(itemId); if (destinationPackage.CanAdd(item))
//If it's unique, abort
if (HasItem(itemId) && gItem.isExclusive)
return ERROR_HAS_UNIQUE;
if (gItem == null)
{ {
Program.Log.Error("Inventory.AddItem: unable to find item %u", itemId); RemoveItemAtSlot(position);
return ERROR_SYSTEM; destinationPackage.AddItem(item);
return ERROR_SUCCESS;
} }
return ERROR_FULL;
//Check if item id exists
int quantityCount = quantity;
for (int i = 0; i < endOfListIndex; i++)
{
InventoryItem item = list[i];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == itemId && item.quality == quality && item.quantity < gItem.maxStack)
{
int oldQuantity = item.quantity;
item.quantity = Math.Min(item.quantity + quantityCount, gItem.maxStack);
isDirty[i] = true;
quantityCount -= (gItem.maxStack - oldQuantity);
DoDatabaseQuantity(item.uniqueId, item.quantity);
if (quantityCount <= 0)
break;
}
}
//New item that spilled over
while (quantityCount > 0)
{
InventoryItem.ItemModifier modifiers = null;
if (gItem.durability != 0)
{
modifiers = new InventoryItem.ItemModifier();
modifiers.durability = (uint)gItem.durability;
}
InventoryItem addedItem = Database.CreateItem(itemId, Math.Min(quantityCount, gItem.maxStack), quality, modifiers);
addedItem.RefreshPositioning(owner, itemPackageCode, (ushort)endOfListIndex);
isDirty[endOfListIndex] = true;
list[endOfListIndex++] = addedItem;
quantityCount -= gItem.maxStack;
DoDatabaseAdd(addedItem);
}
if (owner is Player)
{
(owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
SendUpdate();
(owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
return ERROR_SUCCESS;
} }
public void SetItem(ushort slot, InventoryItem item) public int MoveItem(InventoryItem item, ItemPackage destinationPackage)
{ {
list[slot] = item; if (destinationPackage == null || item == null)
if (owner is Player) return ERROR_SYSTEM;
if (destinationPackage.CanAdd(item))
{ {
(owner as Player).QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId)); RemoveItem(item);
SendUpdate(); destinationPackage.AddItem(item);
(owner as Player).QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId)); return ERROR_SUCCESS;
} }
item.RefreshPositioning(owner, itemPackageCode, slot); return ERROR_FULL;
} }
public void RemoveItem(uint itemId) public void RemoveItem(uint itemId)
@ -423,12 +386,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
public void RemoveItem(InventoryItem item) public void RemoveItem(InventoryItem item)
{ {
RemoveItemByUniqueId(item.uniqueId, item.quantity); if (itemPackageCode == item.itemPackage)
} RemoveItemAtSlot(item.slot);
public void RemoveItem(InventoryItem item, int quantity)
{
RemoveItemByUniqueId(item.uniqueId, quantity);
} }
public void RemoveItemByUniqueId(ulong itemDBId, int quantity) public void RemoveItemByUniqueId(ulong itemDBId, int quantity)
@ -455,7 +414,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
if (quantity >= toDelete.quantity) if (quantity >= toDelete.quantity)
{ {
DoDatabaseRemove(toDelete.uniqueId); DoDatabaseRemove(toDelete.uniqueId);
list[slot].RefreshPositioning(null, 0xFFFF, 0xFFFF); list[slot].ClearOwner();
list[slot] = null; list[slot] = null;
} }
else else
@ -483,7 +442,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
DoDatabaseRemove(list[slot].uniqueId); DoDatabaseRemove(list[slot].uniqueId);
list[slot].RefreshPositioning(null, 0xFFFF, 0xFFFF); list[slot].ClearOwner();
list[slot] = null; list[slot] = null;
isDirty[slot] = true; isDirty[slot] = true;
@ -510,7 +469,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
{ {
DoDatabaseRemove(list[slot].uniqueId); DoDatabaseRemove(list[slot].uniqueId);
list[slot].RefreshPositioning(null, 0xFFFF, 0xFFFF); list[slot].ClearOwner();
list[slot] = null; list[slot] = null;
DoRealign(); DoRealign();
} }
@ -532,7 +491,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
{ {
for (int i = 0; i < endOfListIndex; i++) for (int i = 0; i < endOfListIndex; i++)
{ {
list[i].RefreshPositioning(null, 0xFFFF, 0xFFFF); list[i].ClearOwner();
list[i] = null; list[i] = null;
isDirty[i] = true; isDirty[i] = true;
} }
@ -546,6 +505,49 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
} }
} }
public bool CanAdd(InventoryItem item)
{
return itemPackageCapacity - GetCount() > 0;
}
public bool CanAdd(uint[] itemIds, uint[] quantity, byte[] quality)
{
int tempInvSize = GetCount();
for (int i = 0; i < itemIds.Length; i++)
{
ItemData gItem = Server.GetItemGamedata(itemIds[i]);
//Check if item id exists and fill up til maxstack
int quantityCount = (int)(quantity != null ? quantity[i] : 1);
for (int j = 0; j < endOfListIndex; j++)
{
InventoryItem item = list[j];
Debug.Assert(item != null, "Item slot was null!!!");
if (item.itemId == itemIds[i] && item.quality == (quality != null ? quality[i] : 1) && item.quantity < gItem.maxStack)
{
quantityCount -= (gItem.maxStack - item.quantity);
if (quantityCount <= 0)
break;
}
}
//New items that spilled over creating new stacks
while (quantityCount > 0)
{
quantityCount -= gItem.maxStack;
tempInvSize++;
}
//If the new stacks push us over capacity, can't add these items
if (tempInvSize > itemPackageCapacity)
return false;
}
return true;
}
public void MarkDirty(InventoryItem item) public void MarkDirty(InventoryItem item)
{ {
if (item.itemPackage != itemPackageCode || list[item.slot] == null) if (item.itemPackage != itemPackageCode || list[item.slot] == null)
@ -724,13 +726,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
if (isTemporary) if (isTemporary)
return; return;
if (itemPackageCode == BAZAAR) Database.AddItem(owner, addedItem, itemPackageCode, addedItem.slot);
return;
if (owner is Player)
Database.AddItem((Player)owner, addedItem, itemPackageCode);
else if (owner is Retainer)
Database.AddItem((Retainer)owner, addedItem, itemPackageCode);
} }
private void DoDatabaseQuantity(ulong itemDBId, int quantity) private void DoDatabaseQuantity(ulong itemDBId, int quantity)
@ -738,10 +734,6 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
if (isTemporary) if (isTemporary)
return; return;
if (itemPackageCode == BAZAAR)
return;
Database.SetQuantity(itemDBId, quantity); Database.SetQuantity(itemDBId, quantity);
} }
@ -750,13 +742,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
if (isTemporary) if (isTemporary)
return; return;
if (itemPackageCode == BAZAAR) Database.RemoveItem(owner, itemDBId);
return;
if (owner is Player)
Database.RemoveItem((Player)owner, itemDBId);
else if (owner is Retainer)
Database.RemoveItem((Retainer)owner, itemDBId);
} }
public void StartSendUpdate() public void StartSendUpdate()
@ -870,5 +856,45 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
{ {
return endOfListIndex; return endOfListIndex;
} }
public override string ToString()
{
string packageName;
switch (itemPackageCode)
{
case NORMAL:
packageName = "Inventory";
break;
case LOOT:
packageName = "Loot";
break;
case MELDREQUEST:
packageName = "Meld Request";
break;
case BAZAAR:
packageName = "Bazaar";
break;
case CURRENCY_CRYSTALS:
packageName = "Currency";
break;
case KEYITEMS:
packageName = "KeyItems";
break;
case EQUIPMENT:
packageName = "Equipment";
break;
case TRADE:
packageName = "Trade";
break;
case EQUIPMENT_OTHERPLAYER:
packageName = "CheckEquip";
break;
default:
packageName = "Unknown";
break;
}
return string.Format("{0} Package", packageName);
}
} }
} }

View File

@ -24,9 +24,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.npc
itemPackages[ItemPackage.CURRENCY_CRYSTALS] = new ItemPackage(this, MAXSIZE_INVENTORY_CURRANCY, ItemPackage.CURRENCY_CRYSTALS); itemPackages[ItemPackage.CURRENCY_CRYSTALS] = new ItemPackage(this, MAXSIZE_INVENTORY_CURRANCY, ItemPackage.CURRENCY_CRYSTALS);
itemPackages[ItemPackage.BAZAAR] = new ItemPackage(this, MAXSIZE_INVENTORY_BAZAAR, ItemPackage.BAZAAR); itemPackages[ItemPackage.BAZAAR] = new ItemPackage(this, MAXSIZE_INVENTORY_BAZAAR, ItemPackage.BAZAAR);
itemPackages[ItemPackage.NORMAL].InitList(Database.GetInventory(this, ItemPackage.NORMAL)); itemPackages[ItemPackage.NORMAL].InitList(Database.GetItemPackage(this, 0, ItemPackage.NORMAL));
itemPackages[ItemPackage.CURRENCY_CRYSTALS].InitList(Database.GetInventory(this, ItemPackage.CURRENCY_CRYSTALS)); itemPackages[ItemPackage.CURRENCY_CRYSTALS].InitList(Database.GetItemPackage(this, 0, ItemPackage.CURRENCY_CRYSTALS));
itemPackages[ItemPackage.BAZAAR].InitList(Database.GetInventory(this, ItemPackage.BAZAAR)); itemPackages[ItemPackage.BAZAAR].InitList(Database.GetItemPackage(this, 0, ItemPackage.BAZAAR));
} }
public uint GetRetainerId() public uint GetRetainerId()

View File

@ -1131,11 +1131,11 @@ namespace FFXIVClassic_Map_Server.Actors
if (item == null) if (item == null)
break; break;
if (item.GetBazaarMode() == InventoryItem.TYPE_SINGLE || item.GetBazaarMode() == InventoryItem.TYPE_MULTI || item.GetBazaarMode() == InventoryItem.TYPE_STACK) if (item.GetBazaarMode() == InventoryItem.MODE_SELL_SINGLE || item.GetBazaarMode() == InventoryItem.MODE_SELL_PSTACK || item.GetBazaarMode() == InventoryItem.MODE_SELL_FSTACK)
isDealing = true; isDealing = true;
if (item.GetBazaarMode() == InventoryItem.TYPE_SEEK_REPAIR) if (item.GetBazaarMode() == InventoryItem.MODE_SEEK_REPAIR)
isRepairing = true; isRepairing = true;
if (item.GetBazaarMode() == InventoryItem.TYPE_SEEK_ITEM) if (item.GetBazaarMode() == InventoryItem.MODE_SEEK_ITEM)
isDealing = true; isDealing = true;
if (isDealing && isRepairing && seekingItem) if (isDealing && isRepairing && seekingItem)

View File

@ -1,4 +1,6 @@
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.actors.chara.player;
using FFXIVClassic_Map_Server.Actors;
using MySql.Data.MySqlClient;
using System; using System;
using System.IO; using System.IO;
@ -14,29 +16,28 @@ namespace FFXIVClassic_Map_Server.dataobjects
public const byte TAG_DEALING = 0xC9; public const byte TAG_DEALING = 0xC9;
public const byte TAG_ATTACHED = 0xCA; public const byte TAG_ATTACHED = 0xCA;
public const byte TYPE_SINGLE = 11; public const byte MODE_SELL_SINGLE = 11; //0xB
public const byte TYPE_MULTI = 12; public const byte MODE_SELL_PSTACK = 12; //0xC
public const byte TYPE_STACK = 13; public const byte MODE_SELL_FSTACK = 13; //0xD
public const byte TYPE_SEEK_ITEM = 20; public const byte MODE_SEEK_ITEM = 20; //0x14
public const byte TYPE_SEEK_REPAIR = 30; public const byte MODE_SEEK_REPAIR = 30; //0x1E
public const byte MODE_SEEK_MELD = 40; //0x28
public ulong uniqueId; public ulong uniqueId;
public uint itemId; public uint itemId;
public int quantity = 1; public int quantity = 1;
public byte dealingVal = 0; private byte dealingVal = 0;
public byte dealingMode = DEALINGMODE_NONE; private byte dealingMode = DEALINGMODE_NONE;
public int dealingAttached1 = 0; private int dealingAttached1 = 0;
public int dealingAttached2 = 0; private int dealingAttached2 = 0;
public int dealingAttached3 = 0; private int dealingAttached3 = 0;
public byte[] tags = new byte[4]; private byte[] tags = new byte[4];
public byte[] tagValues = new byte[4]; private byte[] tagValues = new byte[4];
public byte quality = 1; public byte quality = 1;
private ulong attachedTo = 0;
public ItemModifier modifiers; public ItemModifier modifiers;
public readonly ItemData itemData; public readonly ItemData itemData;
@ -123,22 +124,40 @@ namespace FFXIVClassic_Map_Server.dataobjects
} }
} }
//Bare Minimum //For loading already existing items
public InventoryItem(uint id, ItemData data) public InventoryItem(MySqlDataReader reader)
{ {
this.uniqueId = id; uniqueId = reader.GetUInt32("serverItemId");
this.itemId = data.catalogID; itemId = reader.GetUInt32("itemId");
this.itemData = data; itemData = Server.GetItemGamedata(itemId);
this.quantity = 1; quantity = reader.GetInt32("quantity");
quality = reader.GetByte("quality");
bool hasDealing = !reader.IsDBNull(reader.GetOrdinal("bazaarMode"));
if (hasDealing)
{
dealingVal = reader.GetByte("dealingValue");
dealingMode = reader.GetByte("dealingMode");
dealingAttached1 = reader.GetInt32("dealingAttached1");
dealingAttached2 = reader.GetInt32("dealingAttached2");
dealingAttached3 = reader.GetInt32("dealingAttached3");
tags[0] = reader.GetByte("dealingTag");
tagValues[0] = reader.GetByte("bazaarMode");
}
bool hasModifiers = !reader.IsDBNull(reader.GetOrdinal("modifierId"));
if (hasModifiers)
modifiers = new InventoryItem.ItemModifier(reader);
tags[1] = itemData.isExclusive ? TAG_EXCLUSIVE : (byte)0; tags[1] = itemData.isExclusive ? TAG_EXCLUSIVE : (byte)0;
} }
public InventoryItem(uint uniqueId, ItemData itemData, int quantity, byte qualityNumber, ItemModifier modifiers = null) //For creating new items (only should be called by the DB)
public InventoryItem(uint uniqueId, uint itemId, int quantity, byte qualityNumber, ItemModifier modifiers = null)
{ {
this.uniqueId = uniqueId; this.uniqueId = uniqueId;
this.itemId = itemData.catalogID; this.itemId = itemId;
this.itemData = itemData; this.itemData = Server.GetItemGamedata(itemId);
this.quantity = quantity; this.quantity = quantity;
this.quality = qualityNumber; this.quality = qualityNumber;
this.modifiers = modifiers; this.modifiers = modifiers;
@ -146,6 +165,18 @@ namespace FFXIVClassic_Map_Server.dataobjects
tags[1] = itemData.isExclusive ? TAG_EXCLUSIVE : (byte)0; tags[1] = itemData.isExclusive ? TAG_EXCLUSIVE : (byte)0;
} }
public void SaveDealingInfo(MySqlCommand cmd)
{
cmd.Parameters.AddWithValue("@serverItemId", uniqueId);
cmd.Parameters.AddWithValue("@dealingValue", dealingVal);
cmd.Parameters.AddWithValue("@dealingMode", dealingMode);
cmd.Parameters.AddWithValue("@dealingAttached1", dealingAttached1);
cmd.Parameters.AddWithValue("@dealingAttached2", dealingAttached2);
cmd.Parameters.AddWithValue("@dealingAttached3", dealingAttached3);
cmd.Parameters.AddWithValue("@dealingTag", tags[0]);
cmd.Parameters.AddWithValue("@bazaarMode", tagValues[0]);
}
public byte[] ToPacketBytes() public byte[] ToPacketBytes()
{ {
byte[] data = new byte[0x70]; byte[] data = new byte[0x70];
@ -224,23 +255,24 @@ namespace FFXIVClassic_Map_Server.dataobjects
} }
} }
public void RefreshPositioning(Character owner, ushort itemPackage, ushort slot) public void SetOwner(Character owner, ushort itemPackage, ushort slot)
{ {
this.owner = owner; this.owner = owner;
this.itemPackage = itemPackage; this.itemPackage = itemPackage;
this.slot = slot; this.slot = slot;
} }
public void SetHasAttached(bool isAttached) public void ClearOwner()
{ {
tags[0] = isAttached ? TAG_ATTACHED : (byte)0; owner = null;
itemPackage = 0xFFFF;
slot = 0xFFFF;
} }
public void SetNormal() public void SetNormal()
{ {
tags[0] = 0; tags[0] = 0;
tagValues[0] = 0; tagValues[0] = 0;
attachedTo = 0;
dealingVal = 0; dealingVal = 0;
dealingMode = 0; dealingMode = 0;
dealingAttached1 = 0; dealingAttached1 = 0;
@ -251,53 +283,68 @@ namespace FFXIVClassic_Map_Server.dataobjects
owner.GetItemPackage(itemPackage).MarkDirty(this); owner.GetItemPackage(itemPackage).MarkDirty(this);
} }
public void SetDealing(byte mode, int price) public void SetSelling(byte mode, int price)
{ {
tags[0] = TAG_DEALING; tags[0] = TAG_DEALING;
tagValues[0] = mode; tagValues[0] = mode;
if (mode == TYPE_SINGLE || mode == TYPE_MULTI || mode == TYPE_STACK) dealingVal = 0;
{ dealingMode = DEALINGMODE_PRICED;
dealingVal = 1; dealingAttached1 = 0;
dealingMode = DEALINGMODE_PRICED; dealingAttached2 = price;
dealingAttached1 = 1; dealingAttached3 = 0;
dealingAttached2 = price;
dealingAttached3 = 0;
}
if (owner != null) if (owner != null)
owner.GetItemPackage(itemPackage).MarkDirty(this); owner.GetItemPackage(itemPackage).MarkDirty(this);
Database.SetDealingInfo(this);
} }
public void SetDealingAttached(byte mode, ulong attached) public void SetAsOfferTo(byte mode, InventoryItem seeked)
{ {
tags[0] = TAG_DEALING; tags[0] = TAG_DEALING;
tagValues[0] = mode; tagValues[0] = mode;
attachedTo = attached;
if (owner != null) dealingVal = 0;
owner.GetItemPackage(itemPackage).MarkDirty(this);
}
public ulong GetAttached()
{
return attachedTo;
}
public void SetAttachedIndex(ushort package, ushort index)
{
dealingVal = 1;
dealingMode = DEALINGMODE_REFERENCED; dealingMode = DEALINGMODE_REFERENCED;
dealingAttached1 = ((package << 16) | index); dealingAttached1 = ((seeked.itemPackage << 16) | seeked.slot);
dealingAttached2 = 0;
dealingAttached3 = 0;
seeked.SetSeeking();
if (owner != null)
owner.GetItemPackage(itemPackage).MarkDirty(this);
Database.SetDealingInfo(this);
}
protected void SetSeeking()
{
tags[0] = TAG_ATTACHED;
tagValues[0] = 0;
dealingVal = 0;
dealingMode = DEALINGMODE_NONE;
dealingAttached1 = 0;
dealingAttached2 = 0; dealingAttached2 = 0;
dealingAttached3 = 0; dealingAttached3 = 0;
if (owner != null) if (owner != null)
owner.GetItemPackage(itemPackage).MarkDirty(this); owner.GetItemPackage(itemPackage).MarkDirty(this);
Database.SetDealingInfo(this);
} }
public void SetTradeQuantity(int quantity) public void SetTradeQuantity(int quantity)
{ {
tags[0] = 0;
tagValues[0] = 0;
dealingVal = 0;
dealingMode = DEALINGMODE_NONE;
dealingAttached1 = 0;
dealingAttached2 = 0;
dealingAttached3 = quantity; dealingAttached3 = quantity;
if (owner != null) if (owner != null)
@ -309,9 +356,19 @@ namespace FFXIVClassic_Map_Server.dataobjects
return dealingAttached3; return dealingAttached3;
} }
public ItemData GetItemData() public InventoryItem GetOfferedTo()
{ {
return itemData; if (dealingMode != DEALINGMODE_REFERENCED)
return null;
ushort attachedItemPackage = (ushort)((dealingAttached1 >> 16) & 0xFF);
ushort attachedSlot = (ushort)(dealingAttached1 & 0xFF);
return owner.GetItemPackage(attachedItemPackage).GetItemAtSlot(attachedSlot);
}
public bool IsSelling()
{
return GetBazaarMode() == MODE_SELL_SINGLE || GetBazaarMode() == MODE_SELL_PSTACK || GetBazaarMode() == MODE_SELL_FSTACK;
} }
public byte GetBazaarMode() public byte GetBazaarMode()
@ -321,9 +378,22 @@ namespace FFXIVClassic_Map_Server.dataobjects
return 0; return 0;
} }
public bool IsSelling() public ItemData GetItemData()
{ {
return GetBazaarMode() == TYPE_SINGLE || GetBazaarMode() == TYPE_MULTI || GetBazaarMode() == TYPE_STACK; return itemData;
}
public override string ToString()
{
if (itemData != null)
{
if (quantity <= 1)
return string.Format("{0}+{1} ({2}/{3})", itemData.name, quality-1, quantity, itemData.maxStack);
else
return string.Format("{0} ({1}/{2})", itemData.name, quantity, itemData.maxStack);
}
else
return "Invalid Item";
} }
} }

View File

@ -32,16 +32,20 @@ namespace FFXIVClassic_Map_Server
{ {
public uint actorId; public uint actorId;
public ushort offerSlot; public ushort offerSlot;
public ushort unknown1; public byte offerPackageId;
public byte unknown1;
public ushort seekSlot; public ushort seekSlot;
public ushort unknown2; public byte seekPackageId;
public byte unknown2;
public ItemOfferParam(uint actorId, ushort unknown1, ushort offerSlot, ushort seekSlot, ushort unknown2) public ItemOfferParam(uint actorId, ushort offerSlot, byte offerPackageId, byte unknown1, ushort seekSlot, byte seekPackageId, byte unknown2)
{ {
this.actorId = actorId; this.actorId = actorId;
this.unknown1 = unknown1;
this.offerSlot = offerSlot; this.offerSlot = offerSlot;
this.offerPackageId = offerPackageId;
this.unknown1 = unknown1;
this.seekSlot = seekSlot; this.seekSlot = seekSlot;
this.seekPackageId = seekPackageId;
this.unknown2 = unknown2; this.unknown2 = unknown2;
} }
} }
@ -111,11 +115,13 @@ namespace FFXIVClassic_Map_Server
case 0x8: //Used for offering case 0x8: //Used for offering
{ {
uint actorId = Utils.SwapEndian(reader.ReadUInt32()); uint actorId = Utils.SwapEndian(reader.ReadUInt32());
ushort unk1 = Utils.SwapEndian(reader.ReadUInt16()); ushort rewardSlot = Utils.SwapEndian(reader.ReadUInt16());
ushort offerSlot = Utils.SwapEndian(reader.ReadUInt16()); byte rewardPackageId = reader.ReadByte();
byte unk1 = reader.ReadByte(); //Always 0x2?
ushort seekSlot = Utils.SwapEndian(reader.ReadUInt16()); ushort seekSlot = Utils.SwapEndian(reader.ReadUInt16());
ushort unk2 = Utils.SwapEndian(reader.ReadUInt16()); byte seekPackageId = reader.ReadByte();
value = new ItemOfferParam(actorId, unk1, offerSlot, seekSlot, unk2); byte unk2 = reader.ReadByte(); //Always 0xD?
value = new ItemOfferParam(actorId, rewardSlot, rewardPackageId, unk1, seekSlot, seekPackageId, unk2);
} }
break; break;
case 0x9: //Two Longs (only storing first one) case 0x9: //Two Longs (only storing first one)
@ -130,6 +136,8 @@ namespace FFXIVClassic_Map_Server
case 0xF: //End case 0xF: //End
isDone = true; isDone = true;
continue; continue;
default:
throw new ArgumentException("Unknown lua param...");
} }
if (isDone) if (isDone)
@ -139,7 +147,7 @@ namespace FFXIVClassic_Map_Server
if (value != null && value is ItemOfferParam) if (value != null && value is ItemOfferParam)
{ {
luaParams.Add(new LuaParam(code, value)); luaParams.Add(new LuaParam(code, value));
luaParams.Add(new LuaParam(5, null)); luaParams.Add(new LuaParam(0x5, null)); //This is to clean up the seek script as it fucks with the args.
} }
else if (value != null) else if (value != null)
luaParams.Add(new LuaParam(code, value)); luaParams.Add(new LuaParam(code, value));
@ -150,6 +158,103 @@ namespace FFXIVClassic_Map_Server
return luaParams; return luaParams;
} }
public static List<LuaParam> ReadLuaParams(byte[] bytesIn)
{
List<LuaParam> luaParams = new List<LuaParam>();
using (MemoryStream memStream = new MemoryStream(bytesIn))
{
using (BinaryReader reader = new BinaryReader(memStream))
{
bool isDone = false;
while (true)
{
byte code = reader.ReadByte();
object value = null;
bool wasNil = false;
switch (code)
{
case 0x0: //Int32
value = Utils.SwapEndian(reader.ReadInt32());
break;
case 0x1: //Int32
value = Utils.SwapEndian(reader.ReadUInt32());
break;
case 0x2: //Null Termed String
List<byte> list = new List<byte>();
while (true)
{
byte readByte = reader.ReadByte();
if (readByte == 0)
break;
list.Add(readByte);
}
value = Encoding.ASCII.GetString(list.ToArray());
break;
case 0x3: //Boolean True
value = true;
break;
case 0x4: //Boolean False
value = false;
break;
case 0x5: //Nil
wasNil = true;
break;
case 0x6: //Actor (By Id)
value = Utils.SwapEndian(reader.ReadUInt32());
break;
case 0x7: //Weird one used for inventory
uint type7ActorId = Utils.SwapEndian(reader.ReadUInt32());
byte type7Unknown = reader.ReadByte();
byte type7Slot = reader.ReadByte();
byte type7InventoryType = reader.ReadByte();
value = new ItemRefParam(type7ActorId, type7Unknown, type7Slot, type7InventoryType);
break;
case 0x8:
uint actorId = Utils.SwapEndian(reader.ReadUInt32());
ushort rewardSlot = Utils.SwapEndian(reader.ReadUInt16());
byte rewardPackageId = reader.ReadByte();
byte unk1 = reader.ReadByte(); //Always 0x2?
ushort seekSlot = Utils.SwapEndian(reader.ReadUInt16());
byte seekPackageId = reader.ReadByte();
byte unk2 = reader.ReadByte(); //Always 0xD?
value = new ItemOfferParam(actorId, rewardSlot, rewardPackageId, unk1, seekSlot, seekPackageId, unk2);
break;
case 0x9: //Two Longs (only storing first one)
value = new Type9Param(Utils.SwapEndian(reader.ReadUInt64()), Utils.SwapEndian(reader.ReadUInt64()));
break;
case 0xC: //Byte
value = reader.ReadByte();
break;
case 0x1B: //Short?
value = reader.ReadUInt16();
break;
case 0xF: //End
isDone = true;
continue;
default:
throw new ArgumentException("Unknown lua param...");
}
if (isDone)
break;
if (value != null && value is ItemOfferParam)
{
luaParams.Add(new LuaParam(code, value));
luaParams.Add(new LuaParam(0x5, null)); //This is to clean up the seek script as it fucks with the args.
}
else if (value != null)
luaParams.Add(new LuaParam(code, value));
else if (wasNil)
luaParams.Add(new LuaParam(code, value));
}
}
}
return luaParams;
}
public static void WriteLuaParams(BinaryWriter writer, List<LuaParam> luaParams) public static void WriteLuaParams(BinaryWriter writer, List<LuaParam> luaParams)
{ {
if (luaParams == null) if (luaParams == null)
@ -211,86 +316,6 @@ namespace FFXIVClassic_Map_Server
writer.Write((Byte)0xF); writer.Write((Byte)0xF);
} }
public static List<LuaParam> ReadLuaParams(byte[] bytesIn)
{
List<LuaParam> luaParams = new List<LuaParam>();
using (MemoryStream memStream = new MemoryStream(bytesIn))
{
using (BinaryReader reader = new BinaryReader(memStream))
{
bool isDone = false;
while (true)
{
byte code = reader.ReadByte();
object value = null;
bool wasNil = false;
switch (code)
{
case 0x0: //Int32
value = Utils.SwapEndian(reader.ReadInt32());
break;
case 0x1: //Int32
value = Utils.SwapEndian(reader.ReadUInt32());
break;
case 0x2: //Null Termed String
List<byte> list = new List<byte>();
while (true)
{
byte readByte = reader.ReadByte();
if (readByte == 0)
break;
list.Add(readByte);
}
value = Encoding.ASCII.GetString(list.ToArray());
break;
case 0x3: //Boolean True
value = true;
break;
case 0x4: //Boolean False
value = false;
break;
case 0x5: //Nil
wasNil = true;
break;
case 0x6: //Actor (By Id)
value = Utils.SwapEndian(reader.ReadUInt32());
break;
case 0x7: //Weird one used for inventory
uint type7ActorId = Utils.SwapEndian(reader.ReadUInt32());
byte type7Unknown = reader.ReadByte();
byte type7Slot = reader.ReadByte();
byte type7InventoryType = reader.ReadByte();
value = new ItemRefParam(type7ActorId, type7Unknown, type7Slot, type7InventoryType);
break;
case 0x9: //Two Longs (only storing first one)
value = new Type9Param(Utils.SwapEndian(reader.ReadUInt64()), Utils.SwapEndian(reader.ReadUInt64()));
break;
case 0xC: //Byte
value = reader.ReadByte();
break;
case 0x1B: //Short?
value = reader.ReadUInt16();
break;
case 0xF: //End
isDone = true;
continue;
}
if (isDone)
break;
if (value != null)
luaParams.Add(new LuaParam(code, value));
else if (wasNil)
luaParams.Add(new LuaParam(code, value));
}
}
}
return luaParams;
}
public static List<LuaParam> CreateLuaParamList(DynValue fromScript) public static List<LuaParam> CreateLuaParamList(DynValue fromScript)
{ {
List<LuaParam> luaParams = new List<LuaParam>(); List<LuaParam> luaParams = new List<LuaParam>();
@ -461,7 +486,7 @@ namespace FFXIVClassic_Map_Server
break; break;
case 0x8: //Weird one used for inventory case 0x8: //Weird one used for inventory
ItemOfferParam itemOfferParam = ((ItemOfferParam)lParams[i].value); ItemOfferParam itemOfferParam = ((ItemOfferParam)lParams[i].value);
dumpString += String.Format("Type8 Param: (0x{0:X}, 0x{1:X}, 0x{2:X}, 0x{3:X}, 0x{4:X})", itemOfferParam.actorId, itemOfferParam.unknown1, itemOfferParam.offerSlot, itemOfferParam.seekSlot, itemOfferParam.unknown2); dumpString += String.Format("Type8 Param: (0x{0:X}, 0x{1:X}, 0x{2:X}, 0x{3:X}, 0x{4:X}, 0x{5:X}, 0x{6:X})", itemOfferParam.actorId, itemOfferParam.offerSlot, itemOfferParam.offerPackageId, itemOfferParam.unknown1, itemOfferParam.seekSlot, itemOfferParam.seekPackageId, itemOfferParam.unknown2);
break; break;
case 0x9: //Long (+ 8 bytes ignored) case 0x9: //Long (+ 8 bytes ignored)
Type9Param type9Param = ((Type9Param)lParams[i].value); Type9Param type9Param = ((Type9Param)lParams[i].value);