Skip to content

Commit

Permalink
Add support for quests in party
Browse files Browse the repository at this point in the history
- Party list updates with proper progress.
- Track completion of world quests.
- Treat quest accept as a checkpoint for saving progress.
- Fix issue where shallow copy didn't really shallow copy in the quest
  structure.
- Fix issue where changing additional members of quest structure on accident.
  • Loading branch information
pacampbell committed Jun 20, 2024
1 parent c44978c commit 962eb44
Show file tree
Hide file tree
Showing 32 changed files with 741 additions and 142 deletions.
10 changes: 8 additions & 2 deletions Arrowgene.Ddon.Database/Files/Database/Script/schema_sqlite.sql
Original file line number Diff line number Diff line change
Expand Up @@ -499,15 +499,14 @@ CREATE TABLE IF NOT EXISTS "ddon_bazaar_exhibition" (
);

CREATE TABLE IF NOT EXISTS "ddon_reward_box" (
"uniq_reward_id" INTEGER NOT NULL,
"uniq_reward_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"character_common_id" INTEGER NOT NULL,
"quest_id" INTEGER NOT NULL,
"num_random_rewards" INTEGER NOT NULL,
"random_reward0_index" INTEGER NOT NULL,
"random_reward1_index" INTEGER NOT NULL,
"random_reward2_index" INTEGER NOT NULL,
"random_reward3_index" INTEGER NOT NULL,
PRIMARY KEY("uniq_reward_id" AUTOINCREMENT),
CONSTRAINT "fk_ddon_reward_box_character_common_id" FOREIGN KEY("character_common_id") REFERENCES "ddon_character_common"("character_common_id") ON DELETE CASCADE
);

Expand All @@ -523,5 +522,12 @@ CREATE TABLE IF NOT EXISTS "ddon_completed_quests" (
"character_common_id" INTEGER NOT NULL,
"quest_type" INTEGER NOT NULL,
"quest_id" INTEGER NOT NULL,
"clear_count" INTEGER NOT NULL DEFAULT 0,
FOREIGN KEY("character_common_id") REFERENCES "ddon_character_common"("character_common_id") ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS "ddon_priority_quests" (
"character_common_id" INTEGER NOT NULL,
"quest_id" INTEGER NOT NULL,
FOREIGN KEY("character_common_id") REFERENCES "ddon_character_common"("character_common_id") ON DELETE CASCADE
);
9 changes: 8 additions & 1 deletion Arrowgene.Ddon.Database/IDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,13 +187,20 @@ public interface IDatabase
List<QuestBoxRewards> SelectBoxRewardItems(uint commonId);

// Completed Quests
List<QuestId> GetCompletedQuestsByType(uint characterCommonId, QuestType questType);
List<CompletedQuest> GetCompletedQuestsByType(uint characterCommonId, QuestType questType);
CompletedQuest GetCompletedQuestsById(uint characterCommonId, QuestId questId);
bool InsertIfNotExistCompletedQuest(uint characterCommonId, QuestId questId, QuestType questType);

// Quest Progress
bool InsertQuestProgress(uint characterCommonId, QuestId questId, QuestType questType, uint step);
bool UpdateQuestProgress(uint characterCommonId, QuestId questId, QuestType questType, uint step);
bool RemoveQuestProgress(uint characterCommonId, QuestId questId, QuestType questType);
List<QuestProgress> GetQuestProgressByType(uint characterCommonId, QuestType questType);
QuestProgress GetQuestProgressById(uint characterCommonId, QuestId questId);

// Quest Priority
bool InsertPriorityQuest(uint characterCommonId, QuestId questId);
List<QuestId> GetPriorityQuests(uint characterCommonId);
bool DeletePriorityQuest(uint characterCommonId, QuestId questId);
}
}
50 changes: 45 additions & 5 deletions Arrowgene.Ddon.Database/Sql/Core/DdonSqlCompletedQuests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,25 @@ public abstract partial class DdonSqlDb<TCon, TCom, TReader> : SqlDb<TCon, TCom,
/* ddon_completed_quests */
protected static readonly string[] CompletedQuestsFields = new string[]
{
"character_common_id", "quest_type", "quest_id"
"character_common_id", "quest_type", "quest_id", "clear_count"
};

private readonly string SqlInsertCompletedQuestId = $"INSERT INTO \"ddon_completed_quests\" ({BuildQueryField(CompletedQuestsFields)}) VALUES ({BuildQueryInsert(CompletedQuestsFields)});";
private readonly string SqlInsertIfNotExistCompletedQuestId = $"INSERT INTO \"ddon_completed_quests\" ({BuildQueryField(CompletedQuestsFields)}) SELECT " +
$"{BuildQueryInsert(CompletedQuestsFields)} WHERE NOT EXISTS (SELECT 1 FROM \"ddon_completed_quests\" WHERE " +
$"\"character_common_id\" = @character_common_id AND \"quest_id\" = @quest_id);";
private readonly string SqlSelectCompletedQuestByType = $"SELECT {BuildQueryField(CompletedQuestsFields)} FROM \"ddon_completed_quests\" WHERE \"character_common_id\" = @character_common_id AND \"quest_type\" = @quest_type;";
private readonly string SqlSelectCompletedQuestById = $"SELECT {BuildQueryField(CompletedQuestsFields)} FROM \"ddon_completed_quests\" WHERE \"character_common_id\" = @character_common_id AND \"quest_id\" = @quest_id;";

public List<QuestId> GetCompletedQuestsByType(uint characterCommonId, QuestType questType)
public List<CompletedQuest> GetCompletedQuestsByType(uint characterCommonId, QuestType questType)
{
using TCon connection = OpenNewConnection();
return GetCompletedQuestsByType(connection, characterCommonId, questType);
}

public List<QuestId> GetCompletedQuestsByType(TCon connection, uint characterCommonId, QuestType questType)
public List<CompletedQuest> GetCompletedQuestsByType(TCon connection, uint characterCommonId, QuestType questType)
{
List<QuestId> results = new List<QuestId>();
List<CompletedQuest> results = new List<CompletedQuest>();

ExecuteInTransaction(conn =>
{
Expand All @@ -47,14 +48,52 @@ public List<QuestId> GetCompletedQuestsByType(TCon connection, uint characterCom
}, reader => {
while (reader.Read())
{
results.Add((QuestId)GetUInt32(reader, "quest_id"));
results.Add(new CompletedQuest()
{
QuestId = (QuestId) GetUInt32(reader, "quest_id"),
QuestType = questType,
ClearCount = GetUInt32(reader, "clear_count")
});
}
});
});

return results;
}

public CompletedQuest GetCompletedQuestsById(uint characterCommonId, QuestId questId)
{
using TCon connection = OpenNewConnection();
return GetCompletedQuestsById(connection, characterCommonId, questId);
}

public CompletedQuest GetCompletedQuestsById(TCon connection, uint characterCommonId, QuestId questId)
{
CompletedQuest result = null;

ExecuteInTransaction(conn =>
{
ExecuteReader(conn, SqlSelectCompletedQuestById,
command => {
AddParameter(command, "@character_common_id", characterCommonId);
AddParameter(command, "@quest_id", (uint) questId);
}, reader => {
if (reader.Read())
{
result = new CompletedQuest()
{
QuestId = questId,
QuestType = (QuestType) GetUInt32(reader, "quest_type"),
ClearCount = GetUInt32(reader, "clear_count")
};
}
});
});

return result;
}

public bool InsertIfNotExistCompletedQuest(uint characterCommonId, QuestId questId, QuestType questType)
{
using TCon connection = OpenNewConnection();
Expand All @@ -68,6 +107,7 @@ public bool InsertIfNotExistCompletedQuest(TCon connection, uint characterCommon
AddParameter(command, "character_common_id", characterCommonId);
AddParameter(command, "quest_id", (uint) questId);
AddParameter(command, "quest_type", (uint) questType);
AddParameter(command, "clear_count", 1);
}) == 1;
}
}
Expand Down
86 changes: 86 additions & 0 deletions Arrowgene.Ddon.Database/Sql/Core/DdonSqlPriorityQuests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Data.Common;
using System.Reflection.Metadata.Ecma335;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using Arrowgene.Ddon.Shared.Entity.Structure;
using Arrowgene.Ddon.Shared.Model;
using Arrowgene.Ddon.Shared.Model.Quest;

namespace Arrowgene.Ddon.Database.Sql.Core
{
public abstract partial class DdonSqlDb<TCon, TCom, TReader> : SqlDb<TCon, TCom, TReader>
where TCon : DbConnection
where TCom : DbCommand
where TReader : DbDataReader
{
/* ddon_completed_quests */
protected static readonly string[] PriorityQuestFields = new string[]
{
"character_common_id", "quest_id"
};

private readonly string SqlInsertIfNotExistPriorityQuestId = $"INSERT INTO \"ddon_priority_quests\" ({BuildQueryField(PriorityQuestFields)}) SELECT " +
$"{BuildQueryInsert(PriorityQuestFields)} WHERE NOT EXISTS (SELECT 1 FROM \"ddon_priority_quests\" WHERE " +
$"\"character_common_id\" = @character_common_id AND \"quest_id\" = @quest_id);";
private readonly string SqlSelectPriorityQuests = $"SELECT {BuildQueryField(PriorityQuestFields)} FROM \"ddon_priority_quests\" WHERE \"character_common_id\" = @character_common_id;";
private readonly string SqlDeletePriorityQuest = $"DELETE FROM \"ddon_priority_quests\" WHERE \"character_common_id\" = @character_common_id AND \"quest_id\" = @quest_id;";

public bool InsertPriorityQuest(uint characterCommonId, QuestId questId)
{
using TCon connection = OpenNewConnection();
return InsertPriorityQuest(connection, characterCommonId, questId);
}

public bool InsertPriorityQuest(TCon connection, uint characterCommonId, QuestId questId)
{
return ExecuteNonQuery(connection, SqlInsertIfNotExistPriorityQuestId, command =>
{
AddParameter(command, "character_common_id", characterCommonId);
AddParameter(command, "quest_id", (uint)questId);
}) == 1;
}

public List<QuestId> GetPriorityQuests(uint characterCommonId)
{
using TCon connection = OpenNewConnection();
return GetPriorityQuests(connection, characterCommonId);
}
public List<QuestId> GetPriorityQuests(TCon connection, uint characterCommonId)
{
List<QuestId> results = new List<QuestId>();
ExecuteInTransaction(conn =>
{
ExecuteReader(conn, SqlSelectPriorityQuests,
command => {
AddParameter(command, "@character_common_id", characterCommonId);
}, reader => {
while (reader.Read())
{
results.Add((QuestId)GetUInt32(reader, "quest_id"));
}
});
});
return results;
}

public bool DeletePriorityQuest(uint characterCommonId, QuestId questId)
{
using TCon connection = OpenNewConnection();
return DeletePriorityQuest(connection, characterCommonId, questId);
}

public bool DeletePriorityQuest(TCon connection, uint characterCommonId, QuestId questId)
{
return ExecuteNonQuery(connection, SqlDeletePriorityQuest, command =>
{
AddParameter(command, "@character_common_id", characterCommonId);
AddParameter(command, "quest_id", (uint)questId);
}) == 1;
}
}
}

67 changes: 64 additions & 3 deletions Arrowgene.Ddon.Database/Sql/Core/DdonSqlQuestProgress.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,22 @@ public abstract partial class DdonSqlDb<TCon, TCom, TReader> : SqlDb<TCon, TCom,

private readonly string SqlSelectQuestProgressByType = $"SELECT {BuildQueryField(QuestProgressFields)} FROM \"ddon_quest_progress\" WHERE +" +
$"\"character_common_id\" = @character_common_id AND \"quest_type\" = @quest_type;";
private readonly string SqlSelectQuestProgressById = $"SELECT {BuildQueryField(QuestProgressFields)} FROM \"ddon_quest_progress\" WHERE +" +
$"\"character_common_id\" = @character_common_id AND \"quest_id\" = @quest_id;";
private readonly string SqlSelectAllQuestProgress = $"SELECT {BuildQueryField(QuestProgressFields)} FROM \"ddon_quest_progress\" WHERE +" +
$"\"character_common_id\" = @character_common_id;";

public List<QuestProgress> GetQuestProgressByType(uint characterCommonId, QuestType questType)
{
using TCon connection = OpenNewConnection();
return GetQuestProgressByType(connection, characterCommonId, questType);
if (questType == QuestType.All)
{
return GetAllQuestProgress(connection, characterCommonId);
}
else
{
return GetQuestProgressByType(connection, characterCommonId, questType);
}
}

public List<QuestProgress> GetQuestProgressByType(TCon connection, uint characterCommonId, QuestType questType)
Expand All @@ -44,7 +55,28 @@ public List<QuestProgress> GetQuestProgressByType(TCon connection, uint characte
}, reader => {
while (reader.Read())
{
var result = ReadQuestProgressByType(reader);
var result = ReadQuestProgress(reader);
results.Add(result);
}
});
});

return results;
}

private List<QuestProgress> GetAllQuestProgress(TCon connection, uint characterCommonId)
{
List<QuestProgress> results = new List<QuestProgress>();

ExecuteInTransaction(conn =>
{
ExecuteReader(conn, SqlSelectAllQuestProgress,
command => {
AddParameter(command, "@character_common_id", characterCommonId);
}, reader => {
while (reader.Read())
{
var result = ReadQuestProgress(reader);
results.Add(result);
}
});
Expand All @@ -53,6 +85,35 @@ public List<QuestProgress> GetQuestProgressByType(TCon connection, uint characte
return results;
}


public QuestProgress GetQuestProgressById(uint characterCommonId, QuestId questId)
{
using TCon connection = OpenNewConnection();
return GetQuestProgressById(connection, characterCommonId, questId);
}

public QuestProgress GetQuestProgressById(TCon connection, uint characterCommonId, QuestId questId)
{
QuestProgress result = null;
ExecuteInTransaction(connection =>
{
ExecuteReader(connection, SqlSelectQuestProgressById,
command =>
{
AddParameter(command, "@character_common_id", characterCommonId);
AddParameter(command, "@quest_id", (uint)questId);
},
reader =>
{
if (reader.Read())
{
result = ReadQuestProgress(reader);
}
});
});
return result;
}

public bool RemoveQuestProgress(uint characterCommonId, QuestId questId, QuestType questType)
{
using TCon connection = OpenNewConnection();
Expand Down Expand Up @@ -103,7 +164,7 @@ public bool UpdateQuestProgress(TCon connection, uint characterCommonId, QuestId
}) == 1; ;
}

private QuestProgress ReadQuestProgressByType(TReader reader)
private QuestProgress ReadQuestProgress(TReader reader)
{
QuestProgress obj = new QuestProgress();
obj.CharacterCommonId = GetUInt32(reader, "character_common_id");
Expand Down
1 change: 1 addition & 0 deletions Arrowgene.Ddon.GameServer/DdonGameServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ private void LoadPacketHandler()
AddHandler(new ProfileGetCharacterProfileHandler(this));
AddHandler(new ProfileGetMyCharacterProfileHandler(this));

AddHandler(new QuestCancelPriorityQuestHandler(this));
AddHandler(new QuestEndDistributionQuestCancelHandler(this));
AddHandler(new QuestGetAdventureGuideQuestListHandler(this));
AddHandler(new QuestGetAdventureGuideQuestNoticeHandler(this));
Expand Down
17 changes: 13 additions & 4 deletions Arrowgene.Ddon.GameServer/Handler/PartyPartyCreateHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Arrowgene.Ddon.Shared.Network;
using Arrowgene.Logging;
using System.ComponentModel;
using System.Linq;

namespace Arrowgene.Ddon.GameServer.Handler
{
Expand Down Expand Up @@ -50,11 +51,19 @@ public override void Handle(GameClient client, StructurePacket<C2SPartyPartyCrea
return;
}

// TODO: Fetch all quests for the party, not just MSQ
var mainQuests = Server.Database.GetQuestProgressByType(client.Character.CommonId, QuestType.Main);
foreach (var mainQuest in mainQuests)
var quests = Server.Database.GetQuestProgressByType(client.Character.CommonId, QuestType.All);
foreach (var quest in quests)
{
party.QuestState.AddNewQuest(mainQuest.QuestId, mainQuest.Step);
party.QuestState.AddNewQuest(quest.QuestId, quest.Step);
}

var worldQuests = Server.Database.GetQuestProgressByType(client.Character.CommonId, QuestType.World).Select(x => x.QuestId).ToList();
foreach (var quest in QuestManager.GetQuestsByType(QuestType.World))
{
if (!worldQuests.Contains(quest.Key))
{
party.QuestState.AddNewQuest(quest.Key, 0);
}
}

S2CPartyPartyJoinNtc ntc = new S2CPartyPartyJoinNtc();
Expand Down
Loading

0 comments on commit 962eb44

Please sign in to comment.