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

feat: Add support for "normal skills" #257

Merged
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
10 changes: 9 additions & 1 deletion Arrowgene.Ddon.Database/IDatabase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Data.Common;
using Arrowgene.Ddon.Database.Model;
Expand Down Expand Up @@ -107,6 +107,14 @@ public interface IDatabase
bool DeleteEquippedAbility(uint commonId, JobId equippedToJob, byte slotNo);
bool DeleteEquippedAbilities(uint commonId, JobId equippedToJob);

// (Learned) Normal Skills / Learned Core Skills
bool InsertIfNotExistsNormalSkillParam(uint commonId, CDataNormalSkillParam normalSkillParam);
bool InsertNormalSkillParam(uint commonId, CDataNormalSkillParam normalSkillParam);
bool ReplaceNormalSkillParam(uint commonId, CDataNormalSkillParam normalSkillParam);
bool UpdateNormalSkillParam(uint commonId, JobId job, uint skillNo, CDataNormalSkillParam normalSkillParam);
bool DeleteNormalSkillParam(uint commonId, JobId job, uint skillNo);
List<CDataNormalSkillParam> SelectNormalSkillParam(uint commonId, JobId job);

// Shortcut
bool InsertShortcut(uint characterId, CDataShortCut shortcut);
bool ReplaceShortcut(uint characterId, CDataShortCut shortcut);
Expand Down
36 changes: 33 additions & 3 deletions Arrowgene.Ddon.Database/Sql/Core/DdonSqlDbNormalSkillParam.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Data.Common;
using Arrowgene.Ddon.Shared.Entity.Structure;
using Arrowgene.Ddon.Shared.Model;
using System.Collections.Generic;

namespace Arrowgene.Ddon.Database.Sql.Core
{
Expand All @@ -18,8 +19,37 @@ public abstract partial class DdonSqlDb<TCon, TCom, TReader> : SqlDb<TCon, TCom,
private readonly string SqlInsertIfNotExistsNormalSkillParam = $"INSERT INTO \"ddon_normal_skill_param\" ({BuildQueryField(CDataNormalSkillParamFields)}) SELECT {BuildQueryInsert(CDataNormalSkillParamFields)} WHERE NOT EXISTS (SELECT 1 FROM \"ddon_normal_skill_param\" WHERE \"character_common_id\" = @character_common_id AND \"job\" = @job AND \"skill_no\"=@skill_no);";
private static readonly string SqlUpdateNormalSkillParam = $"UPDATE \"ddon_normal_skill_param\" SET {BuildQueryUpdate(CDataNormalSkillParamFields)} WHERE \"character_common_id\" = @character_common_id AND \"job\" = @job AND \"skill_no\"=@skill_no;";
private static readonly string SqlSelectNormalSkillParam = $"SELECT {BuildQueryField(CDataNormalSkillParamFields)} FROM \"ddon_normal_skill_param\" WHERE \"character_common_id\" = @character_common_id;";
private static readonly string SqlSelectAllNormalSkillParam = $"SELECT {BuildQueryField(CDataNormalSkillParamFields)} FROM \"ddon_normal_skill_param\" WHERE \"character_common_id\" = @character_common_id and \"job\" = @job;";
private const string SqlDeleteNormalSkillParam = "DELETE FROM \"ddon_normal_skill_param\" WHERE \"character_common_id\"=@character_common_id AND \"job\"=@job AND \"skill_no\"=@skill_no;";

public List<CDataNormalSkillParam> SelectNormalSkillParam(uint commonId, JobId job)
{
using TCon connection = OpenNewConnection();
return SelectNormalSkillParam(connection, commonId, job);
}

public List<CDataNormalSkillParam> SelectNormalSkillParam(TCon conn, uint commonId, JobId job)
{
List<CDataNormalSkillParam> LearnedNormalSkills = new List<CDataNormalSkillParam>();

ExecuteInTransaction(conn =>
{
ExecuteReader(conn, SqlSelectAllNormalSkillParam,
command => {
AddParameter(command, "@character_common_id", commonId);
AddParameter(command, "@job", (byte)job);
}, reader => {
while (reader.Read())
{
CDataNormalSkillParam LearnedNormalSkill = ReadNormalSkillParam(reader);
LearnedNormalSkills.Add(LearnedNormalSkill);
}
});
});

return LearnedNormalSkills;
}

public bool InsertIfNotExistsNormalSkillParam(uint commonId, CDataNormalSkillParam normalSkillParam)
{
using TCon connection = OpenNewConnection();
Expand All @@ -33,7 +63,7 @@ public bool InsertIfNotExistsNormalSkillParam(TCon conn, uint commonId, CDataNor
AddParameter(command, commonId, normalSkillParam);
}) == 1;
}

public bool InsertNormalSkillParam(uint commonId, CDataNormalSkillParam normalSkillParam)
{
using TCon connection = OpenNewConnection();
Expand Down Expand Up @@ -79,7 +109,7 @@ public bool UpdateNormalSkillParam(TCon connection, uint commonId, JobId job, ui
AddParameter(command, commonId, normalSkillParam);
}) == 1;
}

public bool DeleteNormalSkillParam(uint commonId, JobId job, uint skillNo)
{
return ExecuteNonQuery(SqlDeleteNormalSkillParam, command =>
Expand All @@ -94,8 +124,8 @@ private CDataNormalSkillParam ReadNormalSkillParam(TReader reader)
{
CDataNormalSkillParam normalSkillParam = new CDataNormalSkillParam();
normalSkillParam.Job = (JobId)GetByte(reader, "job");
normalSkillParam.SkillNo = GetUInt32(reader, "skill_no");
normalSkillParam.Index = GetUInt32(reader, "index");
normalSkillParam.SkillNo = GetUInt32(reader, "skill_no");
normalSkillParam.PreSkillNo = GetUInt32(reader, "pre_skill_no");
return normalSkillParam;
}
Expand Down
104 changes: 100 additions & 4 deletions Arrowgene.Ddon.GameServer/Characters/JobManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
using Arrowgene.Ddon.Database;
using Arrowgene.Ddon.GameServer.Handler;
using Arrowgene.Ddon.Server;
using Arrowgene.Ddon.Shared;
using Arrowgene.Ddon.Shared.Entity.PacketStructure;
using Arrowgene.Ddon.Shared.Entity.Structure;
using Arrowgene.Ddon.Shared.Model;
using Arrowgene.Logging;

namespace Arrowgene.Ddon.GameServer.Characters
{
public class JobManager
{
private static readonly ServerLogger Logger = LogProvider.Logger<ServerLogger>(typeof(JobManager));

public void SetJob(DdonServer<GameClient> server, GameClient client, CharacterCommon common, JobId jobId)
{
common.Job = jobId;
Expand Down Expand Up @@ -49,6 +53,7 @@ public void SetJob(DdonServer<GameClient> server, GameClient client, CharacterCo
.Where(x => x != null)
.ToList();
List<CDataLearnNormalSkillParam> normalSkills = common.LearnedNormalSkills
.Where(x => x.Job == common.Job)
.Select(x => new CDataLearnNormalSkillParam(x))
.ToList();
List<CDataEquipJobItem> jobItems = common.Equipment.getJobItemsAsCDataEquipJobItem(common.Job);
Expand All @@ -69,7 +74,7 @@ public void SetJob(DdonServer<GameClient> server, GameClient client, CharacterCo
changeJobNotice.LearnNormalSkillParamList = normalSkills;
changeJobNotice.EquipJobItemList = jobItems;
// TODO: Unk0

foreach(GameClient otherClient in server.ClientLookup.GetAll())
{
otherClient.Send(changeJobNotice);
Expand All @@ -91,7 +96,7 @@ public void SetJob(DdonServer<GameClient> server, GameClient client, CharacterCo
.FirstOrDefault(new CDataPlayPointData());
changeJobResponse.Unk0.Unk0 = (byte) jobId;
changeJobResponse.Unk0.Unk1 = character.Storage.getAllStoragesAsCDataCharacterItemSlotInfoList();

client.Send(changeJobResponse);
}
else if(common is Pawn)
Expand Down Expand Up @@ -286,7 +291,7 @@ public IEnumerable<byte> ChangeExSkill(IDatabase database, GameClient client, Ch
CustomSkill affectedSkill = character.LearnedCustomSkills
.Where(skill => skill.Job == job && skill.SkillId == GetBaseSkillId(skillId))
.Single();

List<byte> affectedSlots = new List<byte>();
for(int i=0; i<character.EquippedCustomSkillsDictionary[job].Count; i++)
{
Expand Down Expand Up @@ -317,6 +322,97 @@ public void RemoveSkill(IDatabase database, CharacterCommon character, JobId job
// From what I tested it doesn't seem to be necessary
}

public void UnlockLearnedNormalSkill(AssetRepository AssetRepo, IDatabase Database, GameClient Client, CharacterCommon Character, JobId Job, uint SkillIndex)
{
CDataCharacterJobData CharacterJobData = Character.CharacterJobDataList.Where(cjd => cjd.Job == Job).Single();

Dictionary<JobId, List<LearnedNormalSkill>> LearnedNormalSkillsMap = AssetRepo.LearnedNormalSkillsAsset.LearnedNormalSkills;

if (!LearnedNormalSkillsMap.ContainsKey(Job) || SkillIndex == 0 || ((SkillIndex - 1) > LearnedNormalSkillsMap[Job].Count()))
{
// Something strange happened, either there is a new job (unlikely)
// or there is a missing skill, or someone tried to craft a custom
// packet to the server. Return back an error packet to the client.
Logger.Error("Illegal request to unlock 'Learned Normal/Core Skill'");

var S2CResult = new S2CSkillLearnNormalSkillRes()
{
Error = 0xabaddeed
};

Client.Send(S2CResult);
return;
}

LearnedNormalSkill Skill = LearnedNormalSkillsMap[Job][(int)(SkillIndex - 1)];
if (CharacterJobData.JobPoint < Skill.JpCost || CharacterJobData.Lv < Skill.RequiredLevel)
{
// This shouldn't happen, but if it does, don't learn the skill and
// return an error packet to the client.
Logger.Error("Illegal request to unlock 'Learned Normal/Core Skill'");

var S2CResult = new S2CSkillLearnNormalSkillRes()
{
Error = 0xabaddeed
};

Client.Send(S2CResult);
return;
}

foreach (uint SkillNo in Skill.SkillNo)
{
List<CDataNormalSkillParam> Matches = Character.LearnedNormalSkills.Where(skill => skill != null && skill.Job == Job && skill.SkillNo == SkillNo).ToList();
if (Matches.Count() == 0)
{

CDataNormalSkillParam NewSkill = new CDataNormalSkillParam()
{
Job = Job,
Index = SkillIndex, // 1, 2, 3 based offset from packet
SkillNo = SkillNo, // Skill ID
PreSkillNo = 0
};

Character.LearnedNormalSkills.Add(NewSkill);
Database.InsertIfNotExistsNormalSkillParam(Character.CommonId, NewSkill);
}
}

// Subtract Job points and update the DB with the new result
CharacterJobData.JobPoint -= Skill.JpCost;
Database.UpdateCharacterJobData(Character.CommonId, CharacterJobData);

if (Character is Character)
{
var Result = new S2CSkillLearnNormalSkillRes()
{
Job = Job,
SkillIndex = SkillIndex,
NewJobPoint = CharacterJobData.JobPoint,
};

Client.Send(Result);
}
else
{
var Result = new S2CSkillLearnPawnNormalSkillRes()
{
PawnId = ((Pawn)Character).PawnId,
Job = Job,
SkillIndex = SkillIndex,
NewJobPoint = CharacterJobData.JobPoint,
};

Client.Send(Result);
}

// TODO: Send data to rest of party
// TODO: S2C_NORMAL_SKILL_LEARN_NTC currently not defined
// TODO: Need to investigate ID and layout
// Client.Party.SendToAll(S2C_NORMAL_SKILL_LEARN_NTC)
}

public void UnlockAbility(IDatabase database, GameClient client, CharacterCommon character, JobId job, uint abilityId, byte abilityLv)
{
// Check if there is a learned ability of the same ID (This unlock is a level upgrade)
Expand Down Expand Up @@ -447,4 +543,4 @@ public void RemoveAbility(IDatabase database, CharacterCommon character, byte sl
// Same as skills, i haven't found an Ability off NTC. It may not be required
}
}
}
}
2 changes: 1 addition & 1 deletion Arrowgene.Ddon.GameServer/GameStructure.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using System.Collections.Generic;
using Arrowgene.Ddon.GameServer.Party;
using Arrowgene.Ddon.Shared.Entity.Structure;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ public override void Handle(GameClient client, StructurePacket<C2SSkillGetCurren
{
// TODO: Check if its necessary to filter so only the current job skills are sent
S2CSkillGetCurrentSetSkillListRes res = new S2CSkillGetCurrentSetSkillListRes();
res.NormalSkillList = client.Character.LearnedNormalSkills;
res.NormalSkillList = client.Character.LearnedNormalSkills
.Where(x => x.Job == client.Character.Job)
.ToList();
res.SetCustomSkillList = client.Character.EquippedCustomSkillsDictionary[client.Character.Job]
.Select((x, index) => x?.AsCDataSetAcquirementParam((byte)(index+1)))
.Where(x => x != null)
.ToList();
.ToList();
res.SetAbilityList = client.Character.EquippedAbilitiesDictionary[client.Character.Job]
.Select((x, index) => x?.AsCDataSetAcquirementParam((byte)(index+1)))
.Where(x => x != null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
using System.Linq;
using Arrowgene.Ddon.Server;
using Arrowgene.Ddon.Server.Network;
using Arrowgene.Ddon.Shared;
using Arrowgene.Ddon.Shared.Entity.PacketStructure;
using Arrowgene.Ddon.Shared.Entity.Structure;
using Arrowgene.Ddon.Shared.Network;
using Arrowgene.Logging;
using System.Collections.Generic;

namespace Arrowgene.Ddon.GameServer.Handler
{
public class SkillGetLearnedNormalSkillListHandler : StructurePacketHandler<GameClient, C2SSkillGetLearnedNormalSkillListReq>
public class SkillGetLearnedNormalSkillListHandler : GameStructurePacketHandler<C2SSkillGetLearnedNormalSkillListReq>
{
private static readonly ServerLogger Logger = LogProvider.Logger<ServerLogger>(typeof(SkillGetLearnedNormalSkillListHandler));

Expand All @@ -19,9 +19,13 @@ public SkillGetLearnedNormalSkillListHandler(DdonGameServer server) : base(serve
// Learned Core Skills
public override void Handle(GameClient client, StructurePacket<C2SSkillGetLearnedNormalSkillListReq> packet)
{
client.Send(new S2CSkillGetLearnedNormalSkillListRes() {
var Result = new S2CSkillGetLearnedNormalSkillListRes()
{
NormalSkillParamList = client.Character.LearnedNormalSkills
});
};

client.Send(Result);
}

}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using Arrowgene.Ddon.Server;
using Arrowgene.Ddon.Server.Network;
Expand All @@ -20,10 +21,11 @@ public SkillGetPawnLearnedNormalSkillListHandler(DdonGameServer server) : base(s
public override void Handle(GameClient client, StructurePacket<C2SSkillGetPawnLearnedNormalSkillListReq> packet)
{
Pawn pawn = client.Character.Pawns.Where(pawn => pawn.PawnId == packet.Structure.PawnId).Single();

client.Send(new S2CSkillGetPawnLearnedNormalSkillListRes() {
PawnId = pawn.PawnId,
NormalSkillParamList = pawn.LearnedNormalSkills
});
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ public override void Handle(GameClient client, StructurePacket<C2SSkillGetPawnSe
client.Send(res);
}
}
}
}
28 changes: 9 additions & 19 deletions Arrowgene.Ddon.GameServer/Handler/SkillLearnNormalSkillHandler.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Linq;
using Arrowgene.Ddon.GameServer.Characters;
using Arrowgene.Ddon.Server;
using Arrowgene.Ddon.Shared;
using Arrowgene.Ddon.Shared.Entity.PacketStructure;
using Arrowgene.Ddon.Shared.Entity.Structure;
using Arrowgene.Ddon.Shared.Network;
using Arrowgene.Logging;

Expand All @@ -10,28 +10,18 @@ namespace Arrowgene.Ddon.GameServer.Handler
public class SkillLearnNormalSkillHandler : GameStructurePacketHandler<C2SSkillLearnNormalSkillReq>
{
private static readonly ServerLogger Logger = LogProvider.Logger<ServerLogger>(typeof(SkillLearnNormalSkillHandler));


private readonly JobManager _jobManager;

public SkillLearnNormalSkillHandler(DdonGameServer server) : base(server)
{
this._jobManager = server.JobManager;
}

public override void Handle(GameClient client, StructurePacket<C2SSkillLearnNormalSkillReq> packet)
{
CDataCharacterJobData characterJobData = client.Character.CharacterJobDataList.Where(cjd => cjd.Job == packet.Structure.Job).Single();

client.Character.LearnedNormalSkills.Add(new CDataNormalSkillParam()
{
Job = packet.Structure.Job,
SkillNo = packet.Structure.SkillId,
Index = 4 // wtf
});
// TODO: DB and substract JP
client.Send(new S2CSkillLearnNormalSkillRes()
{
Job = packet.Structure.Job,
SkillId = packet.Structure.SkillId,
NewJobPoint = characterJobData.JobPoint
});
_jobManager.UnlockLearnedNormalSkill(Server.AssetRepository, Server.Database, client, client.Character,
packet.Structure.Job, packet.Structure.SkillId);
}
}
}
}
Loading
Loading