Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Companions - WIP #312

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions sql/updates/update_2023-05-18_2.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
CREATE TABLE IF NOT EXISTS `companions` (
`companionId` bigint(20) NOT NULL AUTO_INCREMENT,
`accountId` bigint(20) NOT NULL,
`characterId` bigint(20) NULL DEFAULT NULL,
`monsterId` int(11) NOT NULL,
`name` varchar(64) NOT NULL,
`slot` tinyint(1) NOT NULL,
`barrackLayer` tinyint(1) NOT NULL DEFAULT '1',
`bx` float NOT NULL,
`by` float NOT NULL,
`bz` float NOT NULL,
`dx` float NOT NULL,
`dy` float NOT NULL,
`exp` int(11) NOT NULL DEFAULT '0',
`stamina` int(11) NOT NULL DEFAULT '60000',
`adoptTime` DATETIME DEFAULT CURRENT_TIMESTAMP,
`active` tinyint(1) DEFAULT '1',
PRIMARY KEY (`companionId`),
KEY `accountId` (`accountId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

ALTER TABLE `companions`
ADD CONSTRAINT `companions_ibfk_1` FOREIGN KEY (`accountId`) REFERENCES `accounts` (`accountId`) ON DELETE CASCADE ON UPDATE CASCADE;

ALTER TABLE `companions`
ADD CONSTRAINT `companions_ibfk_2` FOREIGN KEY (`characterId`) REFERENCES `characters` (`characterId`) ON DELETE SET NULL ON UPDATE CASCADE;
47 changes: 47 additions & 0 deletions src/BarracksServer/Database/Account.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class Account : IAccount
{
private readonly object _moneyLock = new();
private readonly List<Character> _characters = new();
private readonly List<Companion> _companions = new List<Companion>();

/// <summary>
/// Gets or sets account's id.
Expand Down Expand Up @@ -211,6 +212,10 @@ public static Account LoadFromDb(string accountName)
foreach (var character in characters)
account.AddCharacter(character);

var companions = BarracksServer.Instance.Database.GetCompanions(account.Id);
foreach (var companion in companions)
account.AddCompanion(companion);

BarracksServer.Instance.Database.LoadMailbox(account);

return account;
Expand Down Expand Up @@ -330,5 +335,47 @@ public void Save()
BarracksServer.Instance.Database.SaveCharacter(character);
}
}

/// <summary>
/// Returns companion by companion id, or null if it doesn't exist.
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public Companion GetCompanionById(long id)
{
lock (_companions)
return _companions.FirstOrDefault(a => a.ObjectId == id);
}

/// <summary>
/// Returns list of all companions on account.
/// </summary>
/// <returns></returns>
public Companion[] GetCompanions()
{
lock (_companions)
return _companions.ToArray();
}

/// <summary>
/// Adds companion to account object and assigns index.
/// </summary>
/// <param name="companion"></param>
private void AddCompanion(Companion companion)
{
lock (_companions)
{
for (byte i = 1; i <= byte.MaxValue; ++i)
{
if (!_companions.Any(a => a.Index == i))
{
companion.Index = i;
break;
}
}

_companions.Add(companion);
}
}
}
}
82 changes: 82 additions & 0 deletions src/BarracksServer/Database/BarracksDb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
using System.IO;
using System.Linq;
using System.Text;
using Melia.Barracks.Network;
using Melia.Shared.Database;
using Melia.Shared.Game.Const;
using Melia.Shared.Network;
using Melia.Shared.World;
using MySqlConnector;
using Yggdrasil.Logging;
Expand Down Expand Up @@ -571,5 +573,85 @@ public void SaveItem(Character character, long itemId)
trans.Commit();
}
}

/// <summary>
/// Returns all companions on given account.
/// </summary>
/// <param name="accountId"></param>
/// <returns></returns>
public List<Companion> GetCompanions(long accountId)
{
var result = new List<Companion>();

using (var conn = this.GetConnection())
{
using (var mc = new MySqlCommand("SELECT * FROM `companions` WHERE `accountId` = @accountId ORDER BY `slot`", conn))
{
mc.Parameters.AddWithValue("@accountId", accountId);

using (var reader = mc.ExecuteReader())
{
while (reader.Read())
{
var characterId = reader.IsDBNull(2) ? 0 : reader.GetInt64("characterId");
var companion = new Companion(reader.GetInt64("companionId"), reader.GetInt64("accountId"), characterId);
companion.MonsterId = reader.GetInt32("monsterId");
companion.Name = reader.GetStringSafe("name");
companion.Index = (byte)reader.GetInt32("slot");
companion.BarracksLayer = reader.GetInt32("barrackLayer");

var bx = reader.GetFloat("bx");
var by = reader.GetFloat("by");
var bz = reader.GetFloat("bz");
companion.BarracksPosition = new Position(bx, by, bz);

result.Add(companion);
}
}
}
}

return result;
}

/// <summary>
/// Set the current character associated with a companion
/// </summary>
/// <param name="companionId"></param>
/// <param name="characterId"></param>
public void SetCompanionCharacter(long companionId, long characterId)
{
using (var conn = this.GetConnection())
using (var trans = conn.BeginTransaction())
{
using (var cmd = new UpdateCommand("UPDATE `companions` SET {0} WHERE `companionId` = @companionId", conn, trans))
{
cmd.AddParameter("@companionId", companionId);
if (characterId > 0)
cmd.Set("characterId", characterId);
else
cmd.Set("characterId", null);

cmd.Execute();
}
trans.Commit();
}
}

/// <summary>
/// Deletes a companion.
/// </summary>
/// <param name="companionId"></param>
/// <returns></returns>
public bool DeleteCompanion(long companionId)
{
using (var conn = this.GetConnection())
using (var mc = new MySqlCommand("DELETE FROM `companions` WHERE `companionId` = @companionId", conn))
{
mc.Parameters.AddWithValue("@companionId", companionId);

return mc.ExecuteNonQuery() > 0;
}
}
}
}
85 changes: 85 additions & 0 deletions src/BarracksServer/Database/Companion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using Melia.Shared.ObjectProperties;
using Melia.Shared.Game.Const;
using Melia.Shared.World;

namespace Melia.Barracks.Database
{
public class Companion
{
/// <summary>
/// Companion's unique id.
/// </summary>
public long DbId { get; set; }

/// <summary>
/// Companion's globally unique id.
/// </summary>
public long ObjectId => ObjectIdRanges.Companions + this.DbId;

/// <summary>
/// Id of the companion's account.
/// </summary>
public long AccountDbId { get; set; }

/// <summary>
/// Id of the associated character.
/// </summary>
public long CharacterDbId { get; set; } = 0;

/// <summary>
/// Globally unique character id.
/// </summary>
public long CharacterObjectId => (this.CharacterDbId != 0) ? ObjectIdRanges.Characters + this.CharacterDbId : 0;

/// <summary>
/// Visual Id of the companion
/// </summary>
public int MonsterId { get; set; }

/// <summary>
/// Index of companion in companion list.
/// </summary>
public byte Index { get; set; }

/// <summary>
/// Companion's name.
/// </summary>
public string Name { get; set; }

/// <summary>
/// Layer in the barrack that the companion should appear in.
/// </summary>
public int BarracksLayer { get; set; }

/// <summary>
/// Companion's position in barracks.
/// </summary>
public Position BarracksPosition { get; set; }

/// <summary>
/// Companion's direction in barracks.
/// </summary>
public Direction BarracksDirection { get; set; }

/// <summary>
/// Companion's experience point shown as level in barracks.
/// </summary>
public long Exp { get; set; }

/// <summary>
/// Companion ctor
/// </summary>
/// <param name="id"></param>
/// <param name="accountId"></param>
/// <param name="characterId">Set to 0 means no unassigned companion</param>
public Companion(long id, long accountId, long characterId = 0)
{
this.DbId = id;
this.AccountDbId = accountId;
this.CharacterDbId = characterId;
this.BarracksPosition = new Position(30.350805f, 17.948700f, 7.398606f);
this.BarracksDirection = new Direction(45);
this.BarracksLayer = 1;
}
}
}
49 changes: 49 additions & 0 deletions src/BarracksServer/Network/Helpers/BarrackPetHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using Melia.Barracks.Database;
using Melia.Shared.Network;

namespace Melia.Barracks.Network.Helpers
{
/// <summary>
/// Contains extensions for writing barracks character data to packets.
/// </summary>
public static class BarrackPetHelper
{
/// <summary>
/// Writes the character's data to the packet.
/// </summary>
/// <param name="packet"></param>
/// <param name="companion"></param>
/// <exception cref="InvalidOperationException"></exception>
public static void AddCompanion(this Packet packet, Companion companion)
{
packet.PutInt(companion.MonsterId);
packet.PutLong(companion.ObjectId);
packet.PutLong(companion.CharacterObjectId);
packet.PutLong(companion.Exp);
packet.PutLpString(companion.Name);
packet.PutByte(0);
packet.PutFloat(companion.BarracksPosition.X);
packet.PutFloat(companion.BarracksPosition.Y);
packet.PutFloat(companion.BarracksPosition.Z);
packet.PutFloat(companion.BarracksDirection.Cos);
packet.PutFloat(companion.BarracksDirection.Sin);
packet.PutLong(0);
packet.PutByte(companion.Index);
var weaponSlots = (byte)0;
packet.PutInt(weaponSlots);
for (var i = 0; i < weaponSlots; i++)
packet.PutByte(0); // Is Equipped
packet.PutByte(1);
var armorSlots = (byte)0;
packet.PutShort(armorSlots);
packet.PutShort(0); // Property Count
for (var i = 0; i < armorSlots; i++)
packet.PutByte(0);
packet.PutByte(1);
packet.PutInt(1);
packet.PutByte(0);
packet.PutLong(60000);
}
}
}
Loading