Implemented mode trade methods. Figured out the modifiers portion of the item packet and rewrote how they are stored.

This commit is contained in:
Filip Maj 2017-10-08 12:26:22 -04:00
parent 94491903f7
commit 59e3b2379a
6 changed files with 300 additions and 116 deletions

View File

@ -1225,18 +1225,28 @@ namespace FFXIVClassic_Map_Server
SELECT
serverItemId,
itemId,
modifierId,
quantity,
itemType,
quality,
durability,
spiritBind,
mainQuality,
subQuality1,
subQuality2,
subQuality3,
param1,
param2,
param3,
spiritbind,
materia1,
materia2,
materia3,
materia4,
materia5
FROM characters_inventory
INNER JOIN server_items ON serverItemId = server_items.id
LEFT JOIN server_items_modifiers ON server_items.modifierId = server_items_modifiers.id
WHERE characterId = @charId AND inventoryType = @type";
MySqlCommand cmd = new MySqlCommand(query, conn);
@ -1252,19 +1262,15 @@ namespace FFXIVClassic_Map_Server
uint itemId = reader.GetUInt32("itemId");
int quantity = reader.GetInt32("quantity");
byte itemType = reader.GetByte("itemType");
byte qualityNumber = reader.GetByte("quality");
int durability = reader.GetInt32("durability");
ushort spiritBind = reader.GetUInt16("spiritBind");
bool hasModifier = !reader.IsDBNull(reader.GetOrdinal("modifierId"));
InventoryItem.ItemModifier modifier = null;
byte materia1 = reader.GetByte("materia1");
byte materia2 = reader.GetByte("materia2");
byte materia3 = reader.GetByte("materia3");
byte materia4 = reader.GetByte("materia4");
byte materia5 = reader.GetByte("materia5");
if (hasModifier)
modifier = new InventoryItem.ItemModifier(reader);
InventoryItem item = new InventoryItem(uniqueId, itemId, quantity, itemType, qualityNumber, durability, spiritBind, materia1, materia2, materia3, materia4, materia5);
InventoryItem item = new InventoryItem(uniqueId, itemId, quantity, new byte[4], new byte[4], qualityNumber, modifier);
item.slot = slot;
slot++;
items.Add(item);
@ -1298,19 +1304,29 @@ namespace FFXIVClassic_Map_Server
SELECT
serverItemId,
itemId,
modifierId,
quantity,
itemType,
quality,
durability,
spiritBind,
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
WHERE retainerId = @retainerId AND inventoryType = @type";
LEFT JOIN server_items_modifiers ON server_items.modifierId = server_items_modifiers.id
WHERE characterId = @charId AND inventoryType = @type";
MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@retainerId", retainer.getRetainerId());
@ -1328,16 +1344,13 @@ namespace FFXIVClassic_Map_Server
byte itemType = reader.GetByte("itemType");
byte qualityNumber = reader.GetByte("quality");
int durability = reader.GetInt32("durability");
ushort spiritBind = reader.GetUInt16("spiritBind");
bool hasModifier = reader.IsDBNull(reader.GetOrdinal("modifierId"));
InventoryItem.ItemModifier modifier = null;
byte materia1 = reader.GetByte("materia1");
byte materia2 = reader.GetByte("materia2");
byte materia3 = reader.GetByte("materia3");
byte materia4 = reader.GetByte("materia4");
byte materia5 = reader.GetByte("materia5");
if (hasModifier)
modifier = new InventoryItem.ItemModifier(reader);
InventoryItem item = new InventoryItem(uniqueId, itemId, quantity, itemType, qualityNumber, durability, spiritBind, materia1, materia2, materia3, materia4, materia5);
InventoryItem item = new InventoryItem(uniqueId, itemId, quantity, new byte[4], new byte[4], qualityNumber, modifier);
item.slot = slot;
slot++;
items.Add(item);
@ -1385,7 +1398,7 @@ namespace FFXIVClassic_Map_Server
cmd.ExecuteNonQuery();
insertedItem = new InventoryItem((uint)cmd.LastInsertedId, itemId, quantity, itemType, quality, durability, 0, 0, 0, 0, 0, 0);
insertedItem = new InventoryItem((uint)cmd.LastInsertedId, itemId, quantity, new byte[4], new byte[4], quality, new InventoryItem.ItemModifier());
}
catch (MySqlException e)
{

View File

@ -46,6 +46,7 @@ namespace FFXIVClassic_Map_Server
public Dictionary<ulong, RelationGroup> mRelationGroups = new Dictionary<ulong, RelationGroup>();
public Dictionary<ulong, TradeGroup> mTradeGroups = new Dictionary<ulong, TradeGroup>();
private Object groupLock = new Object();
private Object tradeLock = new Object();
public ulong groupIndexId = 1;
public WorldManager(Server server)
@ -902,7 +903,7 @@ namespace FFXIVClassic_Map_Server
}
public TradeGroup CreateTradeGroup(Player inviter, Player invitee)
{
{
lock (groupLock)
{
groupIndexId = groupIndexId | 0x0000000000000000;
@ -946,6 +947,11 @@ namespace FFXIVClassic_Map_Server
}
}
public void TradeTEST(Player player)
{
player.KickEventSpecial(Server.GetStaticActors("TradeExecuteCommand"), 0, "commandContent", null, null, null, 16, null, null, null, null, null);
}
public void AcceptTrade(Player invitee)
{
TradeGroup group = GetTradeGroup(invitee.actorId);
@ -958,13 +964,13 @@ namespace FFXIVClassic_Map_Server
Player inviter = (Player)invitee.GetZone().FindActorInArea(group.GetHost());
DeleteTradeGroup(group.groupIndex);
//DeleteTradeGroup(group.groupIndex);
inviter.StartTradeTransaction(invitee);
invitee.StartTradeTransaction(inviter);
inviter.KickEvent(Server.GetStaticActors("TradeExecuteCommand"), "commandContent", null, null, null, 16, null, null, null, null, null);
invitee.KickEvent(Server.GetStaticActors("TradeExecuteCommand"), "commandContent", null, null, null, 16, null, null, null, null, null);
inviter.KickEventSpecial(Server.GetStaticActors("TradeExecuteCommand"), 0, "commandContent", null, null, null, 16, null, null, null, null, null);
invitee.KickEventSpecial(Server.GetStaticActors("TradeExecuteCommand"), 0, "commandContent", null, null, null, 16, null, null, null, null, null);
}
public void CancelTradeTooFar(Player inviter)
@ -1023,6 +1029,20 @@ namespace FFXIVClassic_Map_Server
DeleteTradeGroup(group.groupIndex);
}
public void SwapTradedItems(Player p1, Player p2)
{
lock (tradeLock)
{
if (p1.IsTradeAccepted() && p2.IsTradeAccepted())
{
//move items around
p1.FinishTradeTransaction();
p2.FinishTradeTransaction();
}
}
}
public bool SendGroupInit(Session session, ulong groupId)
{
if (mContentGroups.ContainsKey(groupId))

View File

@ -37,6 +37,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
private bool isTemporary;
private InventoryItem[] list;
private bool[] isDirty;
private bool holdingUpdates = false;
private int endOfListIndex = 0;
@ -135,7 +136,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
if (item.itemId == itemId && item.quality == quality && item.quantity < gItem.maxStack)
{
int oldQuantity = item.quantity;
item.quantity = Math.Min(item.quantity + quantityCount, gItem.maxStack);
item.quantity = Math.Min(item.quantity + quantityCount, gItem.maxStack);
isDirty[i] = true;
quantityCount -= (gItem.maxStack - oldQuantity);
@ -165,6 +166,12 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
SendUpdatePackets();
return INV_ERROR.SUCCESS;
}
public void AddItemSpecial(ushort slot, InventoryItem item)
{
list[slot] = item;
SendUpdatePackets();
}
public void RemoveItem(uint itemId)
@ -306,6 +313,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
SendUpdatePackets();
}
public InventoryItem[] GetRawList()
{
return list;
}
public void ChangeDurability(uint slot, uint durabilityChange)
{
isDirty[slot] = true;
@ -481,11 +493,11 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
{
if (owner is Player)
{
SendUpdatePackets((Player)owner, true);
SendUpdatePackets((Player)owner);
}
}
public void SendUpdatePackets(Player player, bool doneImmediate = false)
public void SendUpdatePackets(Player player)
{
List<InventoryItem> items = new List<InventoryItem>();
List<ushort> slotsToRemove = new List<ushort>();
@ -504,7 +516,7 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
slotsToRemove.Add((ushort)i);
}
if (doneImmediate)
if (!holdingUpdates)
DoneSendUpdate();
player.QueuePacket(InventoryBeginChangePacket.BuildPacket(owner.actorId));
@ -517,8 +529,14 @@ namespace FFXIVClassic_Map_Server.actors.chara.player
player.QueuePacket(InventoryEndChangePacket.BuildPacket(owner.actorId));
}
public void StartSendUpdate()
{
holdingUpdates = true;
}
public void DoneSendUpdate()
{
holdingUpdates = false;
Array.Clear(isDirty, 0, isDirty.Length);
}

View File

@ -111,6 +111,8 @@ namespace FFXIVClassic_Map_Server.Actors
//Trading
private Player otherTrader = null;
private Inventory myOfferings;
private bool isTradeAccepted = false;
private bool isTradeLocked = false;
//GC Related
public byte gcCurrent;
@ -1600,7 +1602,18 @@ namespace FFXIVClassic_Map_Server.Actors
return;
List<LuaParam> lParams = LuaUtils.CreateLuaParamList(parameters);
SubPacket spacket = KickEventPacket.BuildPacket(actorId, actor.actorId, conditionName, lParams);
SubPacket spacket = KickEventPacket.BuildPacket(actorId, actor.actorId, 0x75dc1, conditionName, lParams);
spacket.DebugPrintSubPacket();
QueuePacket(spacket);
}
public void KickEventSpecial(Actor actor, uint unknown, string conditionName, params object[] parameters)
{
if (actor == null)
return;
List<LuaParam> lParams = LuaUtils.CreateLuaParamList(parameters);
SubPacket spacket = KickEventPacket.BuildPacket(actorId, actor.actorId, unknown, conditionName, lParams);
spacket.DebugPrintSubPacket();
QueuePacket(spacket);
}
@ -1786,19 +1799,98 @@ namespace FFXIVClassic_Map_Server.Actors
myOfferings = new Inventory(this, 4, Inventory.TRADE, true);
Inventory otherPlayerOfferings = new Inventory(otherPlayer, 4, Inventory.TRADE, true);
QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId));
QueuePacket(InventorySetBeginPacket.BuildPacket(actorId, 4, Inventory.TRADE));
QueuePacket(EquipmentListX01Packet.BuildPacket(actorId, 1, 1));
QueuePacket(InventorySetEndPacket.BuildPacket(actorId));
QueuePacket(InventoryEndChangePacket.BuildPacket(actorId));
myOfferings.SendFullInventory(this);
myOfferings.StartSendUpdate();
myOfferings.SendUpdatePackets(this);
myOfferings.SendUpdatePackets(otherPlayer);
myOfferings.DoneSendUpdate();
otherTrader = otherPlayer;
isTradeAccepted = false;
}
public Player GetOtherTrader()
{
return otherTrader;
}
public Inventory GetTradeOfferings()
{
return myOfferings;
}
public bool IsTrading()
{
return otherTrader != null;
}
public bool IsTradeAccepted()
{
return isTradeAccepted;
}
public void AddTradeItem(ushort slot, ushort linkedSlot, int subquantity)
{
if (!IsTrading())
return;
InventoryItem mine = inventories[Inventory.NORMAL].GetItemAtSlot(linkedSlot);
InventoryItem tradeItem = new InventoryItem(mine, slot);
myOfferings.StartSendUpdate();
myOfferings.AddItem(mine.itemId, mine.quantity, mine.quality);
myOfferings.SendUpdatePackets(otherTrader);
myOfferings.DoneSendUpdate();
}
public void AddTradeGil(int quantity)
{
if (!IsTrading())
return;
myOfferings.StartSendUpdate();
myOfferings.AddItem(1000001, quantity, 1);
myOfferings.SendUpdatePackets(otherTrader);
myOfferings.DoneSendUpdate();
}
public void RemoveTradeItem(ushort slot)
{
if (!IsTrading())
return;
myOfferings.StartSendUpdate();
myOfferings.RemoveItemAtSlot(slot);
myOfferings.SendUpdatePackets(otherTrader);
myOfferings.DoneSendUpdate();
}
public void ClearTradeItems(ushort slot)
{
if (!IsTrading())
return;
myOfferings.StartSendUpdate();
myOfferings.Clear();
myOfferings.SendUpdatePackets(otherTrader);
myOfferings.DoneSendUpdate();
}
public void AcceptTrade(bool accepted)
{
if (!IsTrading())
return;
isTradeAccepted = accepted;
}
public void FinishTradeTransaction()
{
isTradeAccepted = false;
myOfferings = null;
otherTrader = null;
}
public void Test()
{
QueuePacket(InventoryBeginChangePacket.BuildPacket(actorId));
@ -1820,22 +1912,5 @@ namespace FFXIVClassic_Map_Server.Actors
QueuePacket(InventoryEndChangePacket.BuildPacket(actorId));
}
public Inventory GetTradeOfferings()
{
return myOfferings;
}
public void FinishTradeTransaction()
{
myOfferings = null;
otherTrader = null;
}
public void CancelTradeTransaction()
{
myOfferings = null;
otherTrader = null;
}
}
}

View File

@ -10,17 +10,94 @@ namespace FFXIVClassic_Map_Server.dataobjects
public int quantity = 1;
public ushort slot;
public byte itemType;
public uint dealingAttached1 = 0;
public uint dealingAttached2 = 0;
public uint dealingAttached3 = 0;
public byte[] tags = new byte[4];
public byte[] tagValues = new byte[4];
public byte quality = 1;
public int durability = 0;
public ushort spiritbind = 0;
public ItemModifier modifiers;
public byte materia1 = 0;
public byte materia2 = 0;
public byte materia3 = 0;
public byte materia4 = 0;
public byte materia5 = 0;
public class ItemModifier
{
public uint durability;
public ushort use = 0;
public uint materiaId = 0;
public uint materiaLife = 0;
public byte mainQuality;
public byte[] subQuality = new byte[3];
public uint polish;
public uint param1;
public uint param2;
public uint param3;
public ushort spiritbind;
public byte[] materiaType = new byte[5];
public byte[] materiaGrade = new byte[5];
public ItemModifier()
{
}
public ItemModifier(MySql.Data.MySqlClient.MySqlDataReader reader)
{
durability = reader.GetUInt32("durability");
mainQuality = reader.GetByte("mainQuality");
subQuality[0] = reader.GetByte("subQuality1");
subQuality[1] = reader.GetByte("subQuality2");
subQuality[2] = reader.GetByte("subQuality3");
param1 = reader.GetUInt32("param1");
param2 = reader.GetUInt32("param2");
param3 = reader.GetUInt32("param3");
spiritbind = reader.GetUInt16("spiritbind");
ushort materia1 = reader.GetUInt16("materia1");
ushort materia2 = reader.GetUInt16("materia2");
ushort materia3 = reader.GetUInt16("materia3");
ushort materia4 = reader.GetUInt16("materia4");
ushort materia5 = reader.GetUInt16("materia5");
materiaType[0] = (byte)(materia1 & 0xFF);
materiaGrade[0] = (byte)((materia1 >> 8) & 0xFF);
materiaType[1] = (byte)(materia2 & 0xFF);
materiaGrade[1] = (byte)((materia2 >> 8) & 0xFF);
materiaType[2] = (byte)(materia3 & 0xFF);
materiaGrade[2] = (byte)((materia3 >> 8) & 0xFF);
materiaType[3] = (byte)(materia4 & 0xFF);
materiaGrade[3] = (byte)((materia4 >> 8) & 0xFF);
materiaType[4] = (byte)(materia5 & 0xFF);
materiaGrade[4] = (byte)((materia5 >> 8) & 0xFF);
}
public void WriteBytes(BinaryWriter binWriter)
{
binWriter.Write((UInt32) durability);
binWriter.Write((UInt16) use);
binWriter.Write((UInt32) materiaId);
binWriter.Write((UInt32) materiaLife);
binWriter.Write((Byte) mainQuality);
binWriter.Write((Byte) subQuality[0]);
binWriter.Write((Byte) subQuality[1]);
binWriter.Write((Byte) subQuality[2]);
binWriter.Write((UInt32) polish);
binWriter.Write((UInt32) param1);
binWriter.Write((UInt32) param2);
binWriter.Write((UInt32) param3);
binWriter.Write((UInt16) spiritbind);
binWriter.Write((Byte) materiaType[0]);
binWriter.Write((Byte) materiaType[1]);
binWriter.Write((Byte) materiaType[2]);
binWriter.Write((Byte) materiaType[3]);
binWriter.Write((Byte) materiaType[4]);
binWriter.Write((Byte) materiaGrade[0]);
binWriter.Write((Byte) materiaGrade[1]);
binWriter.Write((Byte) materiaGrade[2]);
binWriter.Write((Byte) materiaGrade[3]);
binWriter.Write((Byte) materiaGrade[4]);
}
}
//Bare Minimum
public InventoryItem(uint id, uint itemId)
@ -30,7 +107,7 @@ namespace FFXIVClassic_Map_Server.dataobjects
this.quantity = 1;
ItemData gItem = Server.GetItemGamedata(itemId);
itemType = gItem.isExclusive ? (byte)0x3 : (byte)0x0;
tags[1] = gItem.isExclusive ? (byte)0x3 : (byte)0x0;
}
//For check command
@ -41,33 +118,27 @@ namespace FFXIVClassic_Map_Server.dataobjects
this.quantity = item.quantity;
this.slot = equipSlot;
this.itemType = item.itemType;
this.tags = item.tags;
this.tagValues = item.tagValues;
this.quality = item.quality;
this.durability = item.durability;
this.spiritbind = item.spiritbind;
this.materia1 = item.materia1;
this.materia2 = item.materia2;
this.materia3 = item.materia3;
this.materia4 = item.materia4;
this.materia5 = item.materia5;
this.modifiers = item.modifiers;
}
public InventoryItem(uint uniqueId, uint itemId, int quantity, byte itemType, byte qualityNumber, int durability, ushort spiritbind, byte materia1, byte materia2, byte materia3, byte materia4, byte materia5)
public InventoryItem(uint uniqueId, uint itemId, int quantity, byte[] tags, byte[] tagValues, byte qualityNumber, ItemModifier modifiers = null)
{
this.uniqueId = uniqueId;
this.itemId = itemId;
this.quantity = quantity;
this.itemType = itemType;
if (tags != null)
this.tags = tags;
if (tagValues != null)
this.tagValues = tagValues;
this.quality = qualityNumber;
this.durability = durability;
this.spiritbind = spiritbind;
this.materia1 = materia1;
this.materia2 = materia2;
this.materia3 = materia3;
this.materia4 = materia4;
this.materia5 = materia5;
this.modifiers = modifiers;
}
public byte[] ToPacketBytes()
@ -83,35 +154,25 @@ namespace FFXIVClassic_Map_Server.dataobjects
binWriter.Write((UInt32)itemId);
binWriter.Write((UInt16)slot);
binWriter.Write((UInt16)0x0001);
binWriter.Write((UInt32)0x00000000);
binWriter.Write((UInt32)0x00000000);
binWriter.Write((UInt32)0x00000000);
binWriter.Write((Byte)0x01);
binWriter.Write((Byte)0x00);
binWriter.Write((UInt32)itemType);
binWriter.Write((UInt32)dealingAttached1);
binWriter.Write((UInt32)dealingAttached2);
binWriter.Write((UInt32)dealingAttached3);
binWriter.Write((UInt32)0x00000000);
for (int i = 0; i < tags.Length; i++)
binWriter.Write((Byte) tags[i]);
for (int i = 0; i < tagValues.Length; i++)
binWriter.Write((Byte) tagValues[i]);
binWriter.Write((byte)quality);
binWriter.Write((byte)0x01);
binWriter.Write((uint)durability);
binWriter.BaseStream.Seek(0x10-0x06, SeekOrigin.Current);
binWriter.Write((byte)0x01);
binWriter.Write((byte)0x01);
binWriter.Write((byte)0x01);
binWriter.Write((byte)0x01);
binWriter.BaseStream.Seek(0x10, SeekOrigin.Current);
binWriter.Write((ushort)spiritbind);
binWriter.Write((byte)materia1);
binWriter.Write((byte)materia2);
binWriter.Write((byte)materia3);
binWriter.Write((byte)materia4);
binWriter.Write((byte)materia5);
binWriter.Write((Byte)quality);
if (modifiers != null)
{
binWriter.Write((Byte)0x01);
modifiers.WriteBytes(binWriter);
}
}
}

View File

@ -13,7 +13,7 @@ namespace FFXIVClassic_Map_Server.packets.send.events
public const ushort OPCODE = 0x012F;
public const uint PACKET_SIZE = 0x90;
public static SubPacket BuildPacket(uint sourcePlayerActorId, uint targetEventActorId, string conditionName, List<LuaParam> luaParams)
public static SubPacket BuildPacket(uint sourcePlayerActorId, uint targetEventActorId, uint unknown, string conditionName, List<LuaParam> luaParams)
{
byte[] data = new byte[PACKET_SIZE - 0x20];
@ -23,10 +23,7 @@ namespace FFXIVClassic_Map_Server.packets.send.events
{
binWriter.Write((UInt32)sourcePlayerActorId);
binWriter.Write((UInt32)targetEventActorId);
int test = 0x75dc1705; //This will crash if set to 0 on pushCommand but not for mining which has to be 0????
binWriter.Write((UInt32)test);
binWriter.Write((UInt32)unknown);
binWriter.Write((UInt32)0x30400000);
binWriter.Write(Encoding.ASCII.GetBytes(conditionName), 0, Encoding.ASCII.GetByteCount(conditionName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(conditionName));