diff --git a/.editorconfig b/.editorconfig
index b344e721e..4ee64a6dc 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -9,7 +9,7 @@ root = true
indent_style = space
# Code files
-[*.{cs,sql,json}]
+[*.{cs,sql,json,csx}]
indent_size = 4
insert_final_newline = true
charset = utf-8
diff --git a/Arrowgene.Ddon.Cli/Command/ServerCommand.cs b/Arrowgene.Ddon.Cli/Command/ServerCommand.cs
index d24689333..f5903d0bd 100644
--- a/Arrowgene.Ddon.Cli/Command/ServerCommand.cs
+++ b/Arrowgene.Ddon.Cli/Command/ServerCommand.cs
@@ -1,8 +1,3 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Threading;
using Arrowgene.Ddon.Database;
using Arrowgene.Ddon.GameServer;
using Arrowgene.Ddon.LoginServer;
@@ -10,6 +5,10 @@
using Arrowgene.Ddon.Shared;
using Arrowgene.Ddon.WebServer;
using Arrowgene.Logging;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Threading;
namespace Arrowgene.Ddon.Cli.Command
{
@@ -20,6 +19,7 @@ public class ServerCommand : ICommand
private readonly Setting _setting;
private DdonLoginServer _loginServer;
private DdonGameServer _gameServer;
+ private ScriptedServerSettings _scriptServerSettings;
private DdonWebServer _webServer;
private RpcWebServer _rpcWebServer;
private IDatabase _database;
@@ -110,6 +110,12 @@ public CommandResultType Run(CommandParameter parameter)
_assetRepository.Initialize();
}
+ if (_scriptServerSettings == null)
+ {
+ _scriptServerSettings = new ScriptedServerSettings(_setting.AssetPath);
+ _scriptServerSettings.LoadSettings(_setting.GameServerSetting.GameLogicSetting);
+ }
+
if (_loginServer == null)
{
_loginServer = new DdonLoginServer(_setting.LoginServerSetting, _setting.GameServerSetting.GameLogicSetting, _database, _assetRepository);
diff --git a/Arrowgene.Ddon.Cli/Program.cs b/Arrowgene.Ddon.Cli/Program.cs
index 1a07b2393..042d3a08b 100644
--- a/Arrowgene.Ddon.Cli/Program.cs
+++ b/Arrowgene.Ddon.Cli/Program.cs
@@ -20,15 +20,15 @@
* along with Arrowgene.Ddon.Cli. If not, see .
*/
+using Arrowgene.Ddon.Cli.Command;
+using Arrowgene.Ddon.Shared;
+using Arrowgene.Ddon.Shared.Network;
+using Arrowgene.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
-using Arrowgene.Ddon.Cli.Command;
-using Arrowgene.Ddon.Shared;
-using Arrowgene.Ddon.Shared.Network;
-using Arrowgene.Logging;
namespace Arrowgene.Ddon.Cli
{
diff --git a/Arrowgene.Ddon.GameServer/Arrowgene.Ddon.GameServer.csproj b/Arrowgene.Ddon.GameServer/Arrowgene.Ddon.GameServer.csproj
index c1272072c..620340a1a 100644
--- a/Arrowgene.Ddon.GameServer/Arrowgene.Ddon.GameServer.csproj
+++ b/Arrowgene.Ddon.GameServer/Arrowgene.Ddon.GameServer.csproj
@@ -17,6 +17,6 @@
-
+
diff --git a/Arrowgene.Ddon.GameServer/Characters/EpitaphRoadManager.cs b/Arrowgene.Ddon.GameServer/Characters/EpitaphRoadManager.cs
index 41bce2482..195abe54c 100644
--- a/Arrowgene.Ddon.GameServer/Characters/EpitaphRoadManager.cs
+++ b/Arrowgene.Ddon.GameServer/Characters/EpitaphRoadManager.cs
@@ -1322,6 +1322,22 @@ public List RollGatheringLoot(GameClient client, Charact
return results;
}
+ public bool CheckUnlockConditions(GameClient client, EpitaphBarrier barrier)
+ {
+ foreach (var sectionId in barrier.DependentSectionIds)
+ {
+ var sectionInfo = _Server.EpitaphRoadManager.GetSectionById(sectionId);
+ foreach (var unlockId in sectionInfo.UnlockDependencies)
+ {
+ if (!client.Character.EpitaphRoadState.UnlockedContent.Contains(unlockId))
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
///
/// Called by the task manager. The main task will signal all channels
/// to flush the cached information queried by the player when first
diff --git a/Arrowgene.Ddon.GameServer/Characters/StageManager.cs b/Arrowgene.Ddon.GameServer/Characters/StageManager.cs
index 234d6647c..45aa0ec8a 100644
--- a/Arrowgene.Ddon.GameServer/Characters/StageManager.cs
+++ b/Arrowgene.Ddon.GameServer/Characters/StageManager.cs
@@ -1,15 +1,9 @@
using Arrowgene.Ddon.GameServer.Dump;
-using Arrowgene.Ddon.Shared.Entity.PacketStructure;
using Arrowgene.Ddon.Shared.Entity;
+using Arrowgene.Ddon.Shared.Entity.PacketStructure;
+using Arrowgene.Ddon.Shared.Entity.Structure;
using Arrowgene.Ddon.Shared.Model;
-using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Arrowgene.Ddon.Shared.Entity.Structure;
-using Arrowgene.Ddon.Shared.Network;
-using System.IO;
namespace Arrowgene.Ddon.GameServer.Characters
{
diff --git a/Arrowgene.Ddon.GameServer/DdonGameServer.cs b/Arrowgene.Ddon.GameServer/DdonGameServer.cs
index a1b4bea1e..e2fffaa87 100644
--- a/Arrowgene.Ddon.GameServer/DdonGameServer.cs
+++ b/Arrowgene.Ddon.GameServer/DdonGameServer.cs
@@ -29,6 +29,7 @@
using Arrowgene.Ddon.GameServer.Dump;
using Arrowgene.Ddon.GameServer.Handler;
using Arrowgene.Ddon.GameServer.Party;
+using Arrowgene.Ddon.GameServer.Scripting;
using Arrowgene.Ddon.GameServer.Shop;
using Arrowgene.Ddon.Server;
using Arrowgene.Ddon.Server.Handler;
@@ -53,6 +54,7 @@ public DdonGameServer(GameServerSetting setting, IDatabase database, AssetReposi
: base(ServerType.Game, setting.ServerSetting, database, assetRepository)
{
Setting = new GameServerSetting(setting);
+ ScriptManager = new ScriptManager(this);
ClientLookup = new GameClientLookup();
ChatLogHandler = new ChatLogHandler();
ChatManager = new ChatManager(this);
@@ -91,6 +93,7 @@ public DdonGameServer(GameServerSetting setting, IDatabase database, AssetReposi
public event EventHandler ClientConnectionChangeEvent;
public GameServerSetting Setting { get; }
+ public ScriptManager ScriptManager { get; }
public ChatManager ChatManager { get; }
public ItemManager ItemManager { get; }
public CraftManager CraftManager { get; }
@@ -129,6 +132,8 @@ public DdonGameServer(GameServerSetting setting, IDatabase database, AssetReposi
public override void Start()
{
+ ScriptManager.CompileScripts();
+
QuestManager.LoadQuests(this);
GpCourseManager.EvaluateCourses();
@@ -136,7 +141,7 @@ public override void Start()
{
ScheduleManager.StartServerTasks();
}
-
+
LoadChatHandler();
LoadPacketHandler();
base.Start();
diff --git a/Arrowgene.Ddon.GameServer/GameServerSetting.cs b/Arrowgene.Ddon.GameServer/GameServerSetting.cs
index b1fba56c1..a5ff91c50 100644
--- a/Arrowgene.Ddon.GameServer/GameServerSetting.cs
+++ b/Arrowgene.Ddon.GameServer/GameServerSetting.cs
@@ -7,7 +7,7 @@ namespace Arrowgene.Ddon.GameServer
public class GameServerSetting
{
[DataMember(Order = 1)] public ServerSetting ServerSetting { get; set; }
- [DataMember(Order = 2)] public GameLogicSetting GameLogicSetting { get; set; }
+ public GameLogicSetting GameLogicSetting { get; set; }
public GameServerSetting()
{
diff --git a/Arrowgene.Ddon.GameServer/Handler/NpcGetExtendedFacilityHandler.cs b/Arrowgene.Ddon.GameServer/Handler/NpcGetExtendedFacilityHandler.cs
index 8733982ce..ab29d2b62 100644
--- a/Arrowgene.Ddon.GameServer/Handler/NpcGetExtendedFacilityHandler.cs
+++ b/Arrowgene.Ddon.GameServer/Handler/NpcGetExtendedFacilityHandler.cs
@@ -22,86 +22,16 @@ public NpcGetExtendedFacilityHandler(DdonGameServer server) : base(server)
public override S2CNpcGetNpcExtendedFacilityRes Handle(GameClient client, C2SNpcGetNpcExtendedFacilityReq request)
{
var result = new S2CNpcGetNpcExtendedFacilityRes();
- if (gNpcExtendedBehavior.ContainsKey(request.NpcId))
+
+ if (Server.ScriptManager.NpcExtendedFacilities.ContainsKey(request.NpcId))
{
result.NpcId = request.NpcId;
- gNpcExtendedBehavior[request.NpcId](Server, client, result);
+ Server.ScriptManager.NpcExtendedFacilities[request.NpcId].GetExtendedOptions(Server, client, result);
}
- return result;
- }
- private static bool CheckUnlockConditions(DdonGameServer server, GameClient client, EpitaphBarrier barrier)
- {
- foreach (var sectionId in barrier.DependentSectionIds)
- {
- var sectionInfo = server.EpitaphRoadManager.GetSectionById(sectionId);
- foreach (var unlockId in sectionInfo.UnlockDependencies)
- {
- if (!client.Character.EpitaphRoadState.UnlockedContent.Contains(unlockId))
- {
- return false;
- }
- }
- }
- return true;
+ return result;
}
- private static readonly Dictionary> gNpcExtendedBehavior = new Dictionary>()
- {
- [NpcId.Pehr1] = (DdonGameServer server, GameClient client, S2CNpcGetNpcExtendedFacilityRes result) =>
- {
- if (client.Character.CompletedQuests.ContainsKey((QuestId) 60300020) || (client.QuestState.IsQuestActive(60300020) && client.QuestState.GetQuestState(60300020).Step > 2))
- {
- result.ExtendedMenuItemList.Add(new CDataNpcExtendedFacilityMenuItem() { FunctionClass = NpcFunction.WarMissions, FunctionSelect = NpcFunction.HeroicSpiritSleepingPath, Unk2 = 4452 });
- }
- },
- [NpcId.Anita1] = (DdonGameServer server, GameClient client, S2CNpcGetNpcExtendedFacilityRes result) =>
- {
- var barrier = server.EpitaphRoadManager.GetBarrier(NpcId.Anita1);
- if (!client.Character.EpitaphRoadState.UnlockedContent.Contains(barrier.EpitaphId))
- {
- if (!CheckUnlockConditions(server, client, barrier))
- {
- return;
- }
- result.ExtendedMenuItemList.Add(new CDataNpcExtendedFacilityMenuItem() { FunctionClass = NpcFunction.WarMissions, FunctionSelect = NpcFunction.GiveSpirits });
- }
- },
- [NpcId.Isel1] = (DdonGameServer server, GameClient client, S2CNpcGetNpcExtendedFacilityRes result) =>
- {
- var barrier = server.EpitaphRoadManager.GetBarrier(NpcId.Isel1);
- if (!client.Character.EpitaphRoadState.UnlockedContent.Contains(barrier.EpitaphId))
- {
- if (!CheckUnlockConditions(server, client, barrier))
- {
- return;
- }
- result.ExtendedMenuItemList.Add(new CDataNpcExtendedFacilityMenuItem() { FunctionClass = NpcFunction.WarMissions, FunctionSelect = NpcFunction.GiveSpirits });
- }
- },
- [NpcId.Damad1] = (DdonGameServer server, GameClient client, S2CNpcGetNpcExtendedFacilityRes result) =>
- {
- var barrier = server.EpitaphRoadManager.GetBarrier(NpcId.Damad1);
- if (!client.Character.EpitaphRoadState.UnlockedContent.Contains(barrier.EpitaphId))
- {
- if (!CheckUnlockConditions(server, client, barrier))
- {
- return;
- }
- result.ExtendedMenuItemList.Add(new CDataNpcExtendedFacilityMenuItem() { FunctionClass = NpcFunction.WarMissions, FunctionSelect = NpcFunction.GiveSpirits });
- }
- }
-#if false
- // NPC which controls entrance to Memory of Megadosys
- // Currently commented out since area is not completed and personal quest is missing
- [NpcId.Morgan] = new List()
- {
- // Memory of Megadosys
- new CDataNpcExtendedFacilityMenuItem() { FunctionClass = NpcFunction.WarMissions, FunctionSelect = NpcFunction.HeroicSpiritSleepingPath, Unk2 = 4452}
- },
-#endif
- };
-
private readonly byte[] pcap_data = new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xC2, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x11, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x43, 0x20, 0xFB, 0xE8, 0xC0, 0xA0, 0xEC};
}
}
diff --git a/Arrowgene.Ddon.GameServer/Scripting/DdonLibrary.cs b/Arrowgene.Ddon.GameServer/Scripting/DdonLibrary.cs
new file mode 100644
index 000000000..eb2e74743
--- /dev/null
+++ b/Arrowgene.Ddon.GameServer/Scripting/DdonLibrary.cs
@@ -0,0 +1,14 @@
+namespace Arrowgene.Ddon.GameServer.Scripting
+{
+ public class DdonLibrary
+ {
+ public DdonLibrary()
+ {
+ }
+
+ public static uint GetValue()
+ {
+ return 1;
+ }
+ }
+}
diff --git a/Arrowgene.Ddon.GameServer/Scripting/INpcExtendedFacility.cs b/Arrowgene.Ddon.GameServer/Scripting/INpcExtendedFacility.cs
new file mode 100644
index 000000000..54cfbb244
--- /dev/null
+++ b/Arrowgene.Ddon.GameServer/Scripting/INpcExtendedFacility.cs
@@ -0,0 +1,22 @@
+using Arrowgene.Ddon.GameServer;
+using Arrowgene.Ddon.Shared.Entity.PacketStructure;
+using Arrowgene.Ddon.Shared.Model;
+
+namespace Arrowgene.Ddon.GameServer.Scripting
+{
+ public abstract class INpcExtendedFacility
+ {
+ ///
+ /// NPC ID associated with the extended options.
+ ///
+ public NpcId NpcId { get; protected set; }
+
+ ///
+ /// Gets extended menu options for the NPC.
+ ///
+ ///
+ ///
+ /// The result object for the extended NPC options
+ public abstract void GetExtendedOptions(DdonGameServer server, GameClient client, S2CNpcGetNpcExtendedFacilityRes result);
+ }
+}
diff --git a/Arrowgene.Ddon.GameServer/Scripting/ScriptManager.cs b/Arrowgene.Ddon.GameServer/Scripting/ScriptManager.cs
new file mode 100644
index 000000000..c97e3a0af
--- /dev/null
+++ b/Arrowgene.Ddon.GameServer/Scripting/ScriptManager.cs
@@ -0,0 +1,81 @@
+using Arrowgene.Ddon.Server;
+using Arrowgene.Ddon.Shared;
+using Arrowgene.Ddon.Shared.Model;
+using Arrowgene.Logging;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Scripting;
+using Microsoft.CodeAnalysis.Scripting;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Arrowgene.Ddon.GameServer.Scripting
+{
+ public class ScriptManager
+ {
+ private static readonly ServerLogger Logger = LogProvider.Logger(typeof(ScriptManager));
+ public class Globals
+ {
+ public Globals(DdonGameServer server)
+ {
+ Server = server;
+ }
+
+ public DdonGameServer Server { get; }
+ };
+
+
+ public ScriptManager(DdonGameServer server)
+ {
+ Server = server;
+ ScriptsRoot = $"{server.AssetRepository.AssetsPath}\\scripts";
+ NpcExtendedFacilities = new Dictionary();
+ }
+
+ private DdonGameServer Server { get; }
+ private string ScriptsRoot { get; set; }
+ public Dictionary NpcExtendedFacilities { get; private set; }
+
+ public void CompileScripts()
+ {
+ var ExtendedFacilitiesPath = $"{ScriptsRoot}\\extended_facilities";
+
+ var options = ScriptOptions.Default
+ .AddReferences(MetadataReference.CreateFromFile(typeof(DdonGameServer).Assembly.Location))
+ .AddReferences(MetadataReference.CreateFromFile(typeof(AssetRepository).Assembly.Location))
+ .AddImports("System", "System.Collections", "System.Collections.Generic")
+ .AddImports("Arrowgene.Ddon.Shared")
+ .AddImports("Arrowgene.Ddon.Shared.Model")
+ .AddImports("Arrowgene.Ddon.GameServer")
+ .AddImports("Arrowgene.Ddon.GameServer.Characters")
+ .AddImports("Arrowgene.Ddon.GameServer.Scripting")
+ .AddImports("Arrowgene.Ddon.Shared.Entity.PacketStructure")
+ .AddImports("Arrowgene.Ddon.Shared.Entity.Structure")
+ .AddImports("Arrowgene.Ddon.Shared.Model.Quest");
+
+
+ var globals = new Globals(Server);
+
+ Logger.Info($"Compiling NPC extended facility scripts from {ExtendedFacilitiesPath}");
+ foreach (var file in Directory.EnumerateFiles(ExtendedFacilitiesPath))
+ {
+ Logger.Info($"{file}");
+
+ var script = CSharpScript.Create(
+ code: File.ReadAllText(file),
+ options: options,
+ globalsType: typeof(Globals)
+ );
+
+ var result = script.RunAsync(globals).Result;
+ if (result == null)
+ {
+ Logger.Error($"Failed to execute '{file}' successfully. Skipping.");
+ continue;
+ }
+
+ INpcExtendedFacility extendedFacility = (INpcExtendedFacility)result.ReturnValue;
+ NpcExtendedFacilities[extendedFacility.NpcId] = extendedFacility;
+ }
+ }
+ }
+}
diff --git a/Arrowgene.Ddon.Server/GameLogicSetting.cs b/Arrowgene.Ddon.Server/GameLogicSetting.cs
index 3b67942ab..20f81ed2d 100644
--- a/Arrowgene.Ddon.Server/GameLogicSetting.cs
+++ b/Arrowgene.Ddon.Server/GameLogicSetting.cs
@@ -5,25 +5,21 @@
namespace Arrowgene.Ddon.Server
{
- [DataContract]
public class GameLogicSetting
{
///
/// Additional factor to change how long crafting a recipe will take to finish.
///
- [DataMember(Order = 0)]
public double AdditionalProductionSpeedFactor { get; set; }
///
/// Additional factor to change how much a recipe will cost.
///
- [DataMember(Order = 1)]
public double AdditionalCostPerformanceFactor { get; set; }
///
/// Sets the maximim level that the exp ring will reward a bonus.
///
- [DataMember(Order = 2)]
public uint RookiesRingMaxLevel { get; set; }
///
@@ -31,7 +27,6 @@ public class GameLogicSetting
/// Must be a non-negtive value. If it is less than 0.0, a default of 1.0
/// will be selected.
///
- [DataMember(Order = 3)]
public double RookiesRingBonus { get; set; }
///
@@ -39,328 +34,232 @@ public class GameLogicSetting
/// True = Server entry only. Lower packet load, but also causes invisible people in lobbies.
/// False = On-demand. May cause performance issues due to packet load.
///
- [DataMember(Order = 4)]
public bool NaiveLobbyContextHandling { get; set; }
///
/// Determines the maximum amount of consumable items that can be crafted in one go with a pawn.
/// The default is a value of 10 which is equivalent to the original game's behavior.
///
- [DataMember(Order = 5)] public byte CraftConsumableProductionTimesMax { get; set; }
+ public byte CraftConsumableProductionTimesMax { get; set; }
///
/// Configures if party exp is adjusted based on level differences of members.
///
- [DataMember(Order = 6)] public bool AdjustPartyEnemyExp { get; set; }
+ public bool AdjustPartyEnemyExp { get; set; }
///
/// List of the inclusive ranges of (MinLv, Maxlv, ExpMultiplier). ExpMultiplier is a value
/// from (0.0 - 1.0) which is multipled into the base exp amount to determine the adjusted exp.
/// The minlv and maxlv determine the relative level range that this multiplier should be applied to.
///
- [DataMember(Order = 7)] public List<(uint MinLv, uint MaxLv, double ExpMultiplier)> AdjustPartyEnemyExpTiers { get; set; }
+ public List<(uint MinLv, uint MaxLv, double ExpMultiplier)> AdjustPartyEnemyExpTiers { get; set; }
///
/// Configures if exp is adjusted based on level differences of members vs target level.
///
- [DataMember(Order = 8)] public bool AdjustTargetLvEnemyExp { get; set; }
+ public bool AdjustTargetLvEnemyExp { get; set; }
///
/// List of the inclusive ranges of (MinLv, Maxlv, ExpMultiplier). ExpMultiplier is a value from
/// (0.0 - 1.0) which is multipled into the base exp amount to determine the adjusted exp.
/// The minlv and maxlv determine the relative level range that this multiplier should be applied to.
///
- [DataMember(Order = 9)] public List<(uint MinLv, uint MaxLv, double ExpMultiplier)> AdjustTargetLvEnemyExpTiers { get; set; }
+ public List<(uint MinLv, uint MaxLv, double ExpMultiplier)> AdjustTargetLvEnemyExpTiers { get; set; }
///
/// The number of real world minutes that make up an in-game day.
///
- [DataMember(Order = 10)] public uint GameClockTimescale { get; set; }
+ public uint GameClockTimescale { get; set; }
///
/// Use a poisson process to randomly generate a weather cycle containing this many events, using the statistics in WeatherStatistics.
///
- [DataMember(Order = 11)] public uint WeatherSequenceLength { get; set; }
+ public uint WeatherSequenceLength { get; set; }
///
/// Statistics that drive semirandom weather generation. List is expected to be in (Fair, Cloudy, Rainy) order.
/// meanLength: Average length of the weather, in seconds, when it gets rolled.
/// weight: Relative weight of rolling that weather. Set to 0 to disable.
///
- [DataMember(Order = 12)] public List<(uint MeanLength, uint Weight)> WeatherStatistics { get; set; }
+ public List<(uint MeanLength, uint Weight)> WeatherStatistics { get; set; }
///
/// Configures if the Pawn Exp Catchup mechanic is enabled. This mechanic still rewards the player pawn EXP when the pawn is outside
/// the allowed level range and a lower level than the owner.
///
- [DataMember(Order = 13)] public bool EnablePawnCatchup { get; set; }
+ public bool EnablePawnCatchup { get; set; }
///
/// If the flag EnablePawnCatchup=true, this is the multiplier value used when calculating exp to catch the pawns level back up to the player.
///
- [DataMember(Order = 14)] public double PawnCatchupMultiplier { get; set; }
+ public double PawnCatchupMultiplier { get; set; }
///
/// If the flag EnablePawnCatchup=true, this is the range of level that the pawn falls behind the player before the catchup mechanic kicks in.
///
- [DataMember(Order = 15)] public uint PawnCatchupLvDiff { get; set; }
+ public uint PawnCatchupLvDiff { get; set; }
///
/// Configures the default time in seconds a latern is active after igniting it.
///
- [DataMember(Order = 16)] public uint LaternBurnTimeInSeconds { get; set; }
+ public uint LaternBurnTimeInSeconds { get; set; }
///
/// Maximum amount of play points the client will display in the UI.
/// Play points past this point will also trigger a chat log message saying you've reached the cap.
///
- [DataMember(Order = 17)] public uint PlayPointMax { get; set; }
+ public uint PlayPointMax { get; set; }
///
/// Maximum level for each job.
/// Shared with the login server.
///
- [DataMember(Order = 18)] public uint JobLevelMax { get; set; }
+ public uint JobLevelMax { get; set; }
///
/// Maximum number of members in a single clan.
/// Shared with the login server.
///
- [DataMember(Order = 19)] public uint ClanMemberMax { get; set; }
+ public uint ClanMemberMax { get; set; }
///
/// Maximum number of characters per account.
/// Shared with the login server.
///
- [DataMember(Order = 20)] public byte CharacterNumMax { get; set; }
+ public byte CharacterNumMax { get; set; }
///
/// Toggles the visual equip set for all characters.
/// Shared with the login server.
///
- [DataMember(Order = 21)] public bool EnableVisualEquip { get; set; }
+ public bool EnableVisualEquip { get; set; }
///
/// Maximum entries in the friends list.
/// Shared with the login server.
///
- [DataMember(Order = 22)] public uint FriendListMax { get; set; }
+ public uint FriendListMax { get; set; }
///
/// Limits for each wallet type.
///
- [DataMember(Order = 23)] public Dictionary WalletLimits { get; set; }
+ public Dictionary WalletLimits { get; set; }
///
/// Number of bazaar entries that are given to new characters.
///
- [DataMember(Order = 24)] public uint DefaultMaxBazaarExhibits { get; set; }
+ public uint DefaultMaxBazaarExhibits { get; set; }
///
/// Number of favorite warps that are given to new characters.
///
- [DataMember(Order = 25)] public uint DefaultWarpFavorites { get; set; }
+ public uint DefaultWarpFavorites { get; set; }
///
/// Disables the exp correction if all party members are owned by the same character.
///
- [DataMember(Order = 26)] public bool DisableExpCorrectionForMyPawn { get; set; }
+ public bool DisableExpCorrectionForMyPawn { get; set; }
///
/// Global modifier for enemy exp calculations to scale up or down.
///
- [DataMember(Order = 27)] public double EnemyExpModifier { get; set; }
+ public double EnemyExpModifier { get; set; }
///
/// Global modifier for quest exp calculations to scale up or down.
///
-
- [DataMember(Order = 28)] public double QuestExpModifier { get; set; }
+ public double QuestExpModifier { get; set; }
///
/// Global modifier for pp calculations to scale up or down.
///
- [DataMember(Order = 29)] public double PpModifier { get; set; }
+ public double PpModifier { get; set; }
///
/// Global modifier for Gold calculations to scale up or down.
///
- [DataMember(Order = 30)] public double GoldModifier { get; set; }
+ public double GoldModifier { get; set; }
///
/// Global modifier for Rift calculations to scale up or down.
///
- [DataMember(Order = 31)] public double RiftModifier { get; set; }
+ public double RiftModifier { get; set; }
///
/// Global modifier for BO calculations to scale up or down.
///
- [DataMember(Order = 32)] public double BoModifier { get; set; }
+ public double BoModifier { get; set; }
///
/// Global modifier for HO calculations to scale up or down.
///
- [DataMember(Order = 33)] public double HoModifier { get; set; }
+ public double HoModifier { get; set; }
///
/// Global modifier for JP calculations to scale up or down.
///
- [DataMember(Order = 34)] public double JpModifier { get; set; }
+ public double JpModifier { get; set; }
///
/// Configures the maximum amount of reward box slots.
///
- [DataMember(Order = 35)] public byte RewardBoxMax { get; set; }
+ public byte RewardBoxMax { get; set; }
///
/// Configures the maximum amount of quests that can be ordered at one time.
///
- [DataMember(Order = 36)] public byte QuestOrderMax { get; set; }
+ public byte QuestOrderMax { get; set; }
///
/// Configures if epitaph rewards are limited once per weekly reset.
///
- [DataMember(Order = 37)] public bool EnableEpitaphWeeklyRewards { get; set; }
+ public bool EnableEpitaphWeeklyRewards { get; set; }
///
/// Enables main pawns in party to gain EXP and JP from quests
/// Original game apparantly did not have pawns share quest reward, so will set to false for default,
/// change as needed
///
- [DataMember(Order = 38)] public bool EnableMainPartyPawnsQuestRewards { get; set; }
+ public bool EnableMainPartyPawnsQuestRewards { get; set; }
///
/// Specifies the time in seconds that a bazaar exhibit will last.
/// By default, the equivalent of 3 days
///
- [DataMember(Order = 37)] public ulong BazaarExhibitionTimeSeconds { get; set; }
+ public ulong BazaarExhibitionTimeSeconds { get; set; }
///
/// Specifies the time in seconds that a slot in the bazaar won't be able to be used again.
/// By default, the equivalent of 1 day
///
- [DataMember(Order = 38)] public ulong BazaarCooldownTimeSeconds { get; set; }
+ public ulong BazaarCooldownTimeSeconds { get; set; }
///
/// Various URLs used by the client.
/// Shared with the login server.
///
- [DataMember(Order = 200)] public string UrlManual { get; set; }
- [DataMember(Order = 200)] public string UrlShopDetail { get; set; }
- [DataMember(Order = 200)] public string UrlShopCounterA { get; set; }
- [DataMember(Order = 200)] public string UrlShopAttention { get; set; }
- [DataMember(Order = 200)] public string UrlShopStoneLimit { get; set; }
- [DataMember(Order = 200)] public string UrlShopCounterB { get; set; }
- [DataMember(Order = 200)] public string UrlChargeCallback { get; set; }
- [DataMember(Order = 200)] public string UrlChargeA { get; set; }
- [DataMember(Order = 200)] public string UrlSample9 { get; set; }
- [DataMember(Order = 200)] public string UrlSample10 { get; set; }
- [DataMember(Order = 200)] public string UrlCampaignBanner { get; set; }
- [DataMember(Order = 200)] public string UrlSupportIndex { get; set; }
- [DataMember(Order = 200)] public string UrlPhotoupAuthorize { get; set; }
- [DataMember(Order = 200)] public string UrlApiA { get; set; }
- [DataMember(Order = 200)] public string UrlApiB { get; set; }
- [DataMember(Order = 200)] public string UrlIndex { get; set; }
- [DataMember(Order = 200)] public string UrlCampaign { get; set; }
- [DataMember(Order = 200)] public string UrlChargeB { get; set; }
- [DataMember(Order = 200)] public string UrlCompanionImage { get; set; }
+ public string UrlManual { get; set; }
+ public string UrlShopDetail { get; set; }
+ public string UrlShopCounterA { get; set; }
+ public string UrlShopAttention { get; set; }
+ public string UrlShopStoneLimit { get; set; }
+ public string UrlShopCounterB { get; set; }
+ public string UrlChargeCallback { get; set; }
+ public string UrlChargeA { get; set; }
+ public string UrlSample9 { get; set; }
+ public string UrlSample10 { get; set; }
+ public string UrlCampaignBanner { get; set; }
+ public string UrlSupportIndex { get; set; }
+ public string UrlPhotoupAuthorize { get; set; }
+ public string UrlApiA { get; set; }
+ public string UrlApiB { get; set; }
+ public string UrlIndex { get; set; }
+ public string UrlCampaign { get; set; }
+ public string UrlChargeB { get; set; }
+ public string UrlCompanionImage { get; set; }
public GameLogicSetting()
{
- SetDefaultValues();
- }
-
- void SetDefaultValues()
- {
- LaternBurnTimeInSeconds = 1500;
- AdditionalProductionSpeedFactor = 1.0;
- AdditionalCostPerformanceFactor = 1.0;
- RookiesRingMaxLevel = 89;
- RookiesRingBonus = 1.0;
- NaiveLobbyContextHandling = true;
- CraftConsumableProductionTimesMax = 10;
-
- AdjustPartyEnemyExp = true;
- AdjustPartyEnemyExpTiers = new List<(uint MinLv, uint MaxLv, double ExpMultiplier)>()
- {
- (0, 2, 1.0),
- (3, 4, 0.9),
- (5, 6, 0.8),
- (7, 8, 0.6),
- (9, 10, 0.5),
- };
-
- AdjustTargetLvEnemyExp = false;
- AdjustTargetLvEnemyExpTiers = new List<(uint MinLv, uint MaxLv, double ExpMultiplier)>()
- {
- (0, 2, 1.0),
- (3, 4, 0.9),
- (5, 6, 0.8),
- (7, 8, 0.6),
- (9, 10, 0.5),
- };
-
- EnablePawnCatchup = true;
- PawnCatchupMultiplier = 1.5;
- PawnCatchupLvDiff = 5;
-
- DisableExpCorrectionForMyPawn = true;
-
- GameClockTimescale = 90;
-
- WeatherSequenceLength = 20;
- WeatherStatistics = new List<(uint MeanLength, uint Weight)>
- {
- (60 * 30, 1), //Fair
- (60 * 30, 1), //Cloudy
- (60 * 30, 1), //Rainy
- };
-
- PlayPointMax = 2000;
-
- JobLevelMax = 120;
- ClanMemberMax = 100;
- CharacterNumMax = 4;
- EnableVisualEquip = true;
- FriendListMax = 200;
-
- WalletLimits = DefaultWalletLimits;
-
- DefaultMaxBazaarExhibits = 5;
- DefaultWarpFavorites = 3;
-
- EnableEpitaphWeeklyRewards = false;
- EnableMainPartyPawnsQuestRewards = false;
-
- BazaarExhibitionTimeSeconds = (ulong) TimeSpan.FromDays(3).TotalSeconds;
- BazaarCooldownTimeSeconds = (ulong) TimeSpan.FromDays(1).TotalSeconds;
-
- string urlDomain = $"http://localhost:{52099}";
- UrlManual = $"{urlDomain}/manual_nfb/";
- UrlShopDetail = $"{urlDomain}/shop/ingame/stone/detail";
- UrlShopCounterA = $"{urlDomain}/shop/ingame/counter?";
- UrlShopAttention = $"{urlDomain}/shop/ingame/attention?";
- UrlShopStoneLimit = $"{urlDomain}/shop/ingame/stone/limit";
- UrlShopCounterB = $"{urlDomain}/shop/ingame/counter?";
- UrlChargeCallback = $"{urlDomain}/opening/entry/ddo/cog_callback/charge";
- UrlChargeA = $"{urlDomain}/sp_ingame/charge/";
- UrlSample9 = "http://sample09.html";
- UrlSample10 = "http://sample10.html";
- UrlCampaignBanner = $"{urlDomain}/sp_ingame/campaign/bnr/bnr01.html?";
- UrlSupportIndex = $"{urlDomain}/sp_ingame/support/index.html";
- UrlPhotoupAuthorize = $"{urlDomain}/api/photoup/authorize";
- UrlApiA = $"{urlDomain}/link/api";
- UrlApiB = $"{urlDomain}/link/api";
- UrlIndex = $"{urlDomain}/sp_ingame/link/index.html";
- UrlCampaign = $"{urlDomain}/sp_ingame/campaign/bnr/slide.html";
- UrlChargeB = $"{urlDomain}/sp_ingame/charge/";
- UrlCompanionImage = $"{urlDomain}/";
- }
-
- [OnDeserializing]
- void OnDeserializing(StreamingContext context)
- {
- SetDefaultValues();
}
public GameLogicSetting(GameLogicSetting setting)
@@ -431,9 +330,7 @@ public GameLogicSetting(GameLogicSetting setting)
UrlCompanionImage = setting.UrlCompanionImage;
}
- // Note: method is called after the object is completely deserialized - constructors are skipped.
- [OnDeserialized]
- void OnDeserialized(StreamingContext context)
+ void ValidateSettings()
{
if (RookiesRingBonus < 0)
{
@@ -491,34 +388,6 @@ void OnDeserialized(StreamingContext context)
{
JpModifier = 1.0;
}
-
- foreach (var walletMax in DefaultWalletLimits)
- {
- if (!WalletLimits.ContainsKey(walletMax.Key))
- {
- WalletLimits.Add(walletMax.Key, walletMax.Value);
- }
- }
}
-
- private static readonly Dictionary DefaultWalletLimits = new()
- {
- {WalletType.Gold, 999999999},
- {WalletType.RiftPoints, 999999999},
- {WalletType.BloodOrbs, 500000},
- {WalletType.SilverTickets, 999999999},
- {WalletType.GoldenGemstones, 99999},
- {WalletType.RentalPoints, 99999},
- {WalletType.ResetJobPoints, 99},
- {WalletType.ResetCraftSkills, 99},
- {WalletType.HighOrbs, 5000},
- {WalletType.DominionPoints, 999999999},
- {WalletType.AdventurePassPoints, 80},
- {WalletType.UnknownTickets, 999999999},
- {WalletType.BitterblackMazeResetTicket, 3},
- {WalletType.GoldenDragonMark, 30},
- {WalletType.SilverDragonMark, 150},
- {WalletType.RedDragonMark, 99999},
- };
}
}
diff --git a/Arrowgene.Ddon.Server/ScriptedServerSettings.cs b/Arrowgene.Ddon.Server/ScriptedServerSettings.cs
new file mode 100644
index 000000000..2f4f62be0
--- /dev/null
+++ b/Arrowgene.Ddon.Server/ScriptedServerSettings.cs
@@ -0,0 +1,73 @@
+using Arrowgene.Ddon.Server;
+using Arrowgene.Ddon.Shared.Model;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Scripting;
+using Microsoft.CodeAnalysis.Scripting;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Arrowgene.Ddon.Shared
+{
+ public class ScriptedServerSettings
+ {
+ public class Globals
+ {
+ public GameLogicSetting GameLogicSetting { get; set; }
+ }
+
+ private string ScriptsRoot { get; set; }
+ private Dictionary CompiledScripts;
+
+ public Script GameLogicSettings
+ {
+ get
+ {
+ return CompiledScripts["GameLogicSettings"];
+ }
+ set
+ {
+ CompiledScripts["GameLogicSettings"] = value;
+ }
+ }
+
+ public ScriptedServerSettings(string AssetsPath)
+ {
+ ScriptsRoot = $"{AssetsPath}\\scripts";
+
+ CompiledScripts = new Dictionary();
+
+ var ScriptsDirectory = new DirectoryInfo(ScriptsRoot);
+ if (!ScriptsDirectory.Exists)
+ {
+ return;
+ }
+ }
+
+ public void LoadSettings(GameLogicSetting gameLogicSetting)
+ {
+ string SettingsPath = $"{ScriptsRoot}\\GameLogicSettings.csx";
+
+ var options = ScriptOptions.Default
+ .AddReferences(MetadataReference.CreateFromFile(typeof(GameLogicSetting).Assembly.Location))
+ .AddReferences(MetadataReference.CreateFromFile(typeof(WalletType).Assembly.Location))
+ .AddImports("System", "System.Collections", "System.Collections.Generic")
+ .AddImports("Arrowgene.Ddon.Shared.Model")
+ .AddImports("Arrowgene.Ddon.Shared.Model.Quest");
+
+ Globals globals = new Globals()
+ {
+ GameLogicSetting = gameLogicSetting
+ };
+
+ // Load The Game Settings
+ GameLogicSettings = CSharpScript.Create(
+ code: File.ReadAllText(SettingsPath),
+ options: options,
+ globalsType: typeof(Globals)
+ );
+
+ // Execute the script file to populate the settings
+ GameLogicSettings.RunAsync(globals);
+ }
+ }
+}
diff --git a/Arrowgene.Ddon.Shared/Arrowgene.Ddon.Shared.csproj b/Arrowgene.Ddon.Shared/Arrowgene.Ddon.Shared.csproj
index 94100155d..fb6d683c5 100644
--- a/Arrowgene.Ddon.Shared/Arrowgene.Ddon.Shared.csproj
+++ b/Arrowgene.Ddon.Shared/Arrowgene.Ddon.Shared.csproj
@@ -22,6 +22,7 @@
+
@@ -31,4 +32,38 @@
Files\%(RecursiveDir)%(Filename)%(Extension)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
diff --git a/Arrowgene.Ddon.Shared/AssetRepository.cs b/Arrowgene.Ddon.Shared/AssetRepository.cs
index 2444d1a03..5812e3945 100644
--- a/Arrowgene.Ddon.Shared/AssetRepository.cs
+++ b/Arrowgene.Ddon.Shared/AssetRepository.cs
@@ -16,6 +16,8 @@ namespace Arrowgene.Ddon.Shared
{
public class AssetRepository
{
+ public string AssetsPath { get; private set; }
+
// Client data
public const string ClientErrorCodesKey = "ClientErrorCodes.csv";
public const string ItemListKey = "itemlist.csv";
@@ -70,6 +72,8 @@ public AssetRepository(string folder)
return;
}
+ AssetsPath = folder;
+
_fileSystemWatchers = new Dictionary();
ClientErrorCodes = new List();
diff --git a/Arrowgene.Ddon.Shared/Entity/PacketStructure/S2CNpcGetNpcExtendedFacilityRes.cs b/Arrowgene.Ddon.Shared/Entity/PacketStructure/S2CNpcGetNpcExtendedFacilityRes.cs
index 24c85883c..919758528 100644
--- a/Arrowgene.Ddon.Shared/Entity/PacketStructure/S2CNpcGetNpcExtendedFacilityRes.cs
+++ b/Arrowgene.Ddon.Shared/Entity/PacketStructure/S2CNpcGetNpcExtendedFacilityRes.cs
@@ -3,7 +3,6 @@
using Arrowgene.Ddon.Shared.Model;
using Arrowgene.Ddon.Shared.Network;
using System.Collections.Generic;
-using System.Diagnostics.Contracts;
namespace Arrowgene.Ddon.Shared.Entity.PacketStructure
{
diff --git a/Arrowgene.Ddon.Shared/Files/Assets/scripts/GameLogicSettings.csx b/Arrowgene.Ddon.Shared/Files/Assets/scripts/GameLogicSettings.csx
new file mode 100644
index 000000000..89b09177b
--- /dev/null
+++ b/Arrowgene.Ddon.Shared/Files/Assets/scripts/GameLogicSettings.csx
@@ -0,0 +1,142 @@
+/**
+ * Settings file for Server customization.
+ */
+
+// Generic Server Settings
+GameLogicSetting.NaiveLobbyContextHandling = true;
+
+// Crafting Settings
+GameLogicSetting.AdditionalProductionSpeedFactor = 1.0;
+GameLogicSetting.AdditionalCostPerformanceFactor = 1.0;
+GameLogicSetting.CraftConsumableProductionTimesMax = 10;
+
+// Exp Ring Settings
+GameLogicSetting.RookiesRingMaxLevel = 89;
+GameLogicSetting.RookiesRingBonus = 1.0;
+
+// EXP Penalty Settings
+GameLogicSetting.AdjustPartyEnemyExp = true;
+GameLogicSetting.AdjustPartyEnemyExpTiers = new List<(uint MinLv, uint MaxLv, double ExpMultiplier)>()
+{
+ // 1.0 = 100%, 0 = 0%
+ // If the range is larger than the last entry,
+ // a 0% exp rate is automatically applied if
+ // AdjustPartyEnemyExp = true
+ //
+ // MinLv, MaxLv, ExpMultiplier
+ ( 0, 2, 1.0),
+ ( 3, 4, 0.9),
+ ( 5, 6, 0.8),
+ ( 7, 8, 0.6),
+ ( 9, 10, 0.5),
+};
+
+GameLogicSetting.AdjustTargetLvEnemyExp = false;
+GameLogicSetting.AdjustTargetLvEnemyExpTiers = new List<(uint MinLv, uint MaxLv, double ExpMultiplier)>()
+{
+ // MinLv, MaxLv, ExpMultiplier
+ ( 0, 2, 1.0),
+ ( 3, 4, 0.9),
+ ( 5, 6, 0.8),
+ ( 7, 8, 0.6),
+ ( 9, 10, 0.5),
+};
+
+// Pawn Catchup Settings
+GameLogicSetting.EnablePawnCatchup = true;
+GameLogicSetting.PawnCatchupMultiplier = 1.5;
+GameLogicSetting.PawnCatchupLvDiff = 5;
+
+// Game Time Settings
+GameLogicSetting.GameClockTimescale = 90;
+
+// Weather Settings
+GameLogicSetting.WeatherSequenceLength = 20;
+GameLogicSetting.WeatherStatistics = new List<(uint MeanLength, uint Weight)>()
+{
+ (60 * 30, 1), // Fair
+ (60 * 30, 1), // Cloudy
+ (60 * 30, 1), // Rainy
+};
+
+// Account Settings
+GameLogicSetting.CharacterNumMax = 4;
+GameLogicSetting.FriendListMax = 200;
+
+// Player Settings
+GameLogicSetting.JobLevelMax = 120;
+GameLogicSetting.EnableVisualEquip = true;
+GameLogicSetting.DefaultWarpFavorites = 3;
+GameLogicSetting.LaternBurnTimeInSeconds = 1500;
+
+// Pawn Settings
+GameLogicSetting.EnableMainPartyPawnsQuestRewards = false;
+
+// Bazaar Settings
+GameLogicSetting.DefaultMaxBazaarExhibits = 5;
+GameLogicSetting.BazaarExhibitionTimeSeconds = (ulong) TimeSpan.FromDays(3).TotalSeconds;
+GameLogicSetting.BazaarCooldownTimeSeconds = (ulong) TimeSpan.FromDays(1).TotalSeconds;
+
+// Clan Settings
+GameLogicSetting.ClanMemberMax = 100;
+
+// Epitaph Settings
+GameLogicSetting.EnableEpitaphWeeklyRewards = false;
+
+// Point Settings
+GameLogicSetting.PlayPointMax = 2000;
+
+// Global Point Modifiers
+GameLogicSetting.EnemyExpModifier = 1;
+GameLogicSetting.QuestExpModifier = 1;
+GameLogicSetting.PpModifier = 1;
+GameLogicSetting.GoldModifier = 1;
+GameLogicSetting.RiftModifier = 1;
+GameLogicSetting.BoModifier = 1;
+GameLogicSetting.HoModifier = 1;
+GameLogicSetting.JpModifier = 1;
+GameLogicSetting.RewardBoxMax = 100;
+GameLogicSetting.QuestOrderMax = 20;
+
+// Wallet Settings
+GameLogicSetting.WalletLimits = new Dictionary()
+{
+ {WalletType.Gold, 999999999},
+ {WalletType.RiftPoints, 999999999},
+ {WalletType.BloodOrbs, 500000},
+ {WalletType.SilverTickets, 999999999},
+ {WalletType.GoldenGemstones, 99999},
+ {WalletType.RentalPoints, 99999},
+ {WalletType.ResetJobPoints, 99},
+ {WalletType.ResetCraftSkills, 99},
+ {WalletType.HighOrbs, 5000},
+ {WalletType.DominionPoints, 999999999},
+ {WalletType.AdventurePassPoints, 80},
+ {WalletType.UnknownTickets, 999999999},
+ {WalletType.BitterblackMazeResetTicket, 3},
+ {WalletType.GoldenDragonMark, 30},
+ {WalletType.SilverDragonMark, 150},
+ {WalletType.RedDragonMark, 99999},
+};
+
+// URL Settings
+string urlDomain = $"http://localhost:{52099}";
+GameLogicSetting.UrlManual = $"{urlDomain}/manual_nfb/";
+GameLogicSetting.UrlShopDetail = $"{urlDomain}/shop/ingame/stone/detail";
+GameLogicSetting.UrlShopCounterA = $"{urlDomain}/shop/ingame/counter?";
+GameLogicSetting.UrlShopAttention = $"{urlDomain}/shop/ingame/attention?";
+GameLogicSetting.UrlShopStoneLimit = $"{urlDomain}/shop/ingame/stone/limit";
+GameLogicSetting.UrlShopCounterB = $"{urlDomain}/shop/ingame/counter?";
+GameLogicSetting.UrlChargeCallback = $"{urlDomain}/opening/entry/ddo/cog_callback/charge";
+GameLogicSetting.UrlChargeA = $"{urlDomain}/sp_ingame/charge/";
+GameLogicSetting.UrlSample9 = "http://sample09.html";
+GameLogicSetting.UrlSample10 = "http://sample10.html";
+GameLogicSetting.UrlCampaignBanner = $"{urlDomain}/sp_ingame/campaign/bnr/bnr01.html?";
+GameLogicSetting.UrlSupportIndex = $"{urlDomain}/sp_ingame/support/index.html";
+GameLogicSetting.UrlPhotoupAuthorize = $"{urlDomain}/api/photoup/authorize";
+GameLogicSetting.UrlApiA = $"{urlDomain}/link/api";
+GameLogicSetting.UrlApiB = $"{urlDomain}/link/api";
+GameLogicSetting.UrlIndex = $"{urlDomain}/sp_ingame/link/index.html";
+GameLogicSetting.UrlCampaign = $"{urlDomain}/sp_ingame/campaign/bnr/slide.html";
+GameLogicSetting.UrlChargeB = $"{urlDomain}/sp_ingame/charge/";
+GameLogicSetting.UrlCompanionImage = $"{urlDomain}/";
diff --git a/Arrowgene.Ddon.Shared/Files/Assets/scripts/extended_facilities/Anita1.csx b/Arrowgene.Ddon.Shared/Files/Assets/scripts/extended_facilities/Anita1.csx
new file mode 100644
index 000000000..a85a22c88
--- /dev/null
+++ b/Arrowgene.Ddon.Shared/Files/Assets/scripts/extended_facilities/Anita1.csx
@@ -0,0 +1,22 @@
+public class NpcExtendedFacility : INpcExtendedFacility
+{
+ public NpcExtendedFacility()
+ {
+ NpcId = NpcId.Anita1;
+ }
+
+ public override void GetExtendedOptions(DdonGameServer server, GameClient client, S2CNpcGetNpcExtendedFacilityRes result)
+ {
+ var barrier = server.EpitaphRoadManager.GetBarrier(NpcId);
+ if (!client.Character.EpitaphRoadState.UnlockedContent.Contains(barrier.EpitaphId))
+ {
+ if (!server.EpitaphRoadManager.CheckUnlockConditions(client, barrier))
+ {
+ return;
+ }
+ result.ExtendedMenuItemList.Add(new CDataNpcExtendedFacilityMenuItem() { FunctionClass = NpcFunction.WarMissions, FunctionSelect = NpcFunction.GiveSpirits });
+ }
+ }
+}
+
+return new NpcExtendedFacility();
diff --git a/Arrowgene.Ddon.Shared/Files/Assets/scripts/extended_facilities/Damad1.csx b/Arrowgene.Ddon.Shared/Files/Assets/scripts/extended_facilities/Damad1.csx
new file mode 100644
index 000000000..65af77410
--- /dev/null
+++ b/Arrowgene.Ddon.Shared/Files/Assets/scripts/extended_facilities/Damad1.csx
@@ -0,0 +1,22 @@
+public class NpcExtendedFacility : INpcExtendedFacility
+{
+ public NpcExtendedFacility()
+ {
+ NpcId = NpcId.Damad1;
+ }
+
+ public override void GetExtendedOptions(DdonGameServer server, GameClient client, S2CNpcGetNpcExtendedFacilityRes result)
+ {
+ var barrier = server.EpitaphRoadManager.GetBarrier(NpcId);
+ if (!client.Character.EpitaphRoadState.UnlockedContent.Contains(barrier.EpitaphId))
+ {
+ if (!server.EpitaphRoadManager.CheckUnlockConditions(client, barrier))
+ {
+ return;
+ }
+ result.ExtendedMenuItemList.Add(new CDataNpcExtendedFacilityMenuItem() { FunctionClass = NpcFunction.WarMissions, FunctionSelect = NpcFunction.GiveSpirits });
+ }
+ }
+}
+
+return new NpcExtendedFacility();
diff --git a/Arrowgene.Ddon.Shared/Files/Assets/scripts/extended_facilities/Isel1.csx b/Arrowgene.Ddon.Shared/Files/Assets/scripts/extended_facilities/Isel1.csx
new file mode 100644
index 000000000..11d1cb6d4
--- /dev/null
+++ b/Arrowgene.Ddon.Shared/Files/Assets/scripts/extended_facilities/Isel1.csx
@@ -0,0 +1,22 @@
+public class NpcExtendedFacility : INpcExtendedFacility
+{
+ public NpcExtendedFacility()
+ {
+ NpcId = NpcId.Isel1;
+ }
+
+ public override void GetExtendedOptions(DdonGameServer server, GameClient client, S2CNpcGetNpcExtendedFacilityRes result)
+ {
+ var barrier = server.EpitaphRoadManager.GetBarrier(NpcId);
+ if (!client.Character.EpitaphRoadState.UnlockedContent.Contains(barrier.EpitaphId))
+ {
+ if (!server.EpitaphRoadManager.CheckUnlockConditions(client, barrier))
+ {
+ return;
+ }
+ result.ExtendedMenuItemList.Add(new CDataNpcExtendedFacilityMenuItem() { FunctionClass = NpcFunction.WarMissions, FunctionSelect = NpcFunction.GiveSpirits });
+ }
+ }
+}
+
+return new NpcExtendedFacility();
diff --git a/Arrowgene.Ddon.Shared/Files/Assets/scripts/extended_facilities/Pehr1.csx b/Arrowgene.Ddon.Shared/Files/Assets/scripts/extended_facilities/Pehr1.csx
new file mode 100644
index 000000000..1c311a495
--- /dev/null
+++ b/Arrowgene.Ddon.Shared/Files/Assets/scripts/extended_facilities/Pehr1.csx
@@ -0,0 +1,17 @@
+public class NpcExtendedFacility : INpcExtendedFacility
+{
+ public NpcExtendedFacility()
+ {
+ NpcId = NpcId.Pehr1;
+ }
+
+ public override void GetExtendedOptions(DdonGameServer server, GameClient client, S2CNpcGetNpcExtendedFacilityRes result)
+ {
+ if (client.Character.CompletedQuests.ContainsKey((QuestId) 60300020) || (client.QuestState.IsQuestActive(60300020) && client.QuestState.GetQuestState(60300020).Step > 2))
+ {
+ result.ExtendedMenuItemList.Add(new CDataNpcExtendedFacilityMenuItem() { FunctionClass = NpcFunction.WarMissions, FunctionSelect = NpcFunction.HeroicSpiritSleepingPath, Unk2 = 4452 });
+ }
+ }
+}
+
+return new NpcExtendedFacility();
diff --git a/Arrowgene.Ddon.Test/GameServer/Characters/CraftManagerTest.cs b/Arrowgene.Ddon.Test/GameServer/Characters/CraftManagerTest.cs
index d6d0db9af..b958e0fbf 100644
--- a/Arrowgene.Ddon.Test/GameServer/Characters/CraftManagerTest.cs
+++ b/Arrowgene.Ddon.Test/GameServer/Characters/CraftManagerTest.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using Arrowgene.Ddon.GameServer.Scripting;
using Arrowgene.Ddon.Shared;
using Arrowgene.Ddon.Shared.Entity.Structure;
using Arrowgene.Ddon.Shared.Model;
@@ -14,7 +15,17 @@ public class CraftManagerTest
public CraftManagerTest()
{
- _mockServer = new DdonGameServer(new GameServerSetting(), new MockDatabase(), new AssetRepository("TestFiles"));
+ var settings = new GameServerSetting();
+ settings.GameLogicSetting.GameClockTimescale = 90;
+ settings.GameLogicSetting.WeatherSequenceLength = 20;
+ settings.GameLogicSetting.WeatherStatistics = new List<(uint MeanLength, uint Weight)>()
+ {
+ (60 * 30, 1), // Fair
+ (60 * 30, 1), // Cloudy
+ (60 * 30, 1), // Rainy
+ };
+
+ _mockServer = new DdonGameServer(settings, new MockDatabase(), new AssetRepository("TestFiles"));
_craftManager = new CraftManager(_mockServer);
}
diff --git a/Arrowgene.Ddon.Test/GameServer/SettingTest.cs b/Arrowgene.Ddon.Test/GameServer/SettingTest.cs
index 9f13ea76c..07c58a52c 100644
--- a/Arrowgene.Ddon.Test/GameServer/SettingTest.cs
+++ b/Arrowgene.Ddon.Test/GameServer/SettingTest.cs
@@ -13,9 +13,6 @@ public void Serialize_DefaultSetting_ObjectShouldMatchJson()
string json = Setting.Serialize(setting);
Assert.Contains("\"LogPath\": \"Logs\"", json);
- Assert.Contains("\"GameLogicSetting\":", json);
- Assert.Contains("\"AdditionalProductionSpeedFactor\": 1", json);
- Assert.Contains("\"AdditionalCostPerformanceFactor\": 1", json);
}
[Fact]
@@ -29,10 +26,6 @@ public void Deserialize_ValidJson_ShouldReturnCorrectObject()
""Id"": 10,
""Name"": ""CustomServerName"",
""ServerPort"": 42000
- },
- ""GameLogicSetting"": {
- ""AdditionalProductionSpeedFactor"": 1.5,
- ""AdditionalCostPerformanceFactor"": 1.2
}
}
}";
@@ -43,8 +36,6 @@ public void Deserialize_ValidJson_ShouldReturnCorrectObject()
Assert.Equal("C:\\Assets", setting.AssetPath);
Assert.Equal("CustomServerName", setting.GameServerSetting.ServerSetting.Name);
Assert.Equal(42000, setting.GameServerSetting.ServerSetting.ServerPort);
- Assert.Equal(1.5, setting.GameServerSetting.GameLogicSetting.AdditionalProductionSpeedFactor);
- Assert.Equal(1.2, setting.GameServerSetting.GameLogicSetting.AdditionalCostPerformanceFactor);
}
[Fact]
@@ -58,7 +49,6 @@ public void Deserialize_MissingFields_ShouldAssignDefaultValues()
Assert.NotNull(setting.GameServerSetting);
Assert.Equal("Game", setting.GameServerSetting.ServerSetting.Name);
Assert.Equal(52000, setting.GameServerSetting.ServerSetting.ServerPort);
- Assert.Equal(1.0, setting.GameServerSetting.GameLogicSetting.AdditionalProductionSpeedFactor);
}
[Fact]
@@ -69,8 +59,6 @@ public void RoundTrip_SerializeAndDeserialize_ShouldMaintainObjectState()
string json = Setting.Serialize(originalSetting);
Setting deserializedSetting = Setting.Deserialize(json);
-
- Assert.Equal(2.0, deserializedSetting.GameServerSetting.GameLogicSetting.AdditionalProductionSpeedFactor);
Assert.Equal(originalSetting.LogPath, deserializedSetting.LogPath);
}
}
diff --git a/Arrowgene.DragonsDogmaOnline.sln b/Arrowgene.DragonsDogmaOnline.sln
index d5d35f3bd..95bce9303 100644
--- a/Arrowgene.DragonsDogmaOnline.sln
+++ b/Arrowgene.DragonsDogmaOnline.sln
@@ -1,29 +1,29 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.30204.135
+# Visual Studio Version 17
+VisualStudioVersion = 17.10.35013.160
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arrowgene.Ddon.LoginServer", "Arrowgene.Ddon.LoginServer\Arrowgene.Ddon.LoginServer.csproj", "{5C0F18BB-B735-4284-82A2-27506DFC9E56}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arrowgene.Ddon.LoginServer", "Arrowgene.Ddon.LoginServer\Arrowgene.Ddon.LoginServer.csproj", "{5C0F18BB-B735-4284-82A2-27506DFC9E56}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arrowgene.Ddon.Cli", "Arrowgene.Ddon.Cli\Arrowgene.Ddon.Cli.csproj", "{72B2D640-DEA0-4BA7-A3B5-899954BFBBF5}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arrowgene.Ddon.Cli", "Arrowgene.Ddon.Cli\Arrowgene.Ddon.Cli.csproj", "{72B2D640-DEA0-4BA7-A3B5-899954BFBBF5}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arrowgene.Ddon.WebServer", "Arrowgene.Ddon.WebServer\Arrowgene.Ddon.WebServer.csproj", "{B6813ECD-CF44-4899-838B-94D5F85B39A6}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arrowgene.Ddon.WebServer", "Arrowgene.Ddon.WebServer\Arrowgene.Ddon.WebServer.csproj", "{B6813ECD-CF44-4899-838B-94D5F85B39A6}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arrowgene.Ddon.Database", "Arrowgene.Ddon.Database\Arrowgene.Ddon.Database.csproj", "{E8FD9C06-57D7-4117-97AC-DE7779A73FB1}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arrowgene.Ddon.Database", "Arrowgene.Ddon.Database\Arrowgene.Ddon.Database.csproj", "{E8FD9C06-57D7-4117-97AC-DE7779A73FB1}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arrowgene.Ddon.Shared", "Arrowgene.Ddon.Shared\Arrowgene.Ddon.Shared.csproj", "{840B5617-2B22-461F-96F5-9062303F08E0}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arrowgene.Ddon.Shared", "Arrowgene.Ddon.Shared\Arrowgene.Ddon.Shared.csproj", "{840B5617-2B22-461F-96F5-9062303F08E0}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arrowgene.Ddon.Server", "Arrowgene.Ddon.Server\Arrowgene.Ddon.Server.csproj", "{7D39A3F8-4E2E-4E6F-9136-86EC13D64328}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arrowgene.Ddon.Server", "Arrowgene.Ddon.Server\Arrowgene.Ddon.Server.csproj", "{7D39A3F8-4E2E-4E6F-9136-86EC13D64328}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arrowgene.Ddon.GameServer", "Arrowgene.Ddon.GameServer\Arrowgene.Ddon.GameServer.csproj", "{87B8E9EB-CCCF-481F-8D01-74676ED62AAF}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arrowgene.Ddon.GameServer", "Arrowgene.Ddon.GameServer\Arrowgene.Ddon.GameServer.csproj", "{87B8E9EB-CCCF-481F-8D01-74676ED62AAF}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arrowgene.Ddon.Test", "Arrowgene.Ddon.Test\Arrowgene.Ddon.Test.csproj", "{86D48D8F-AA02-4BB8-9B5C-1313C8310F5F}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arrowgene.Ddon.Test", "Arrowgene.Ddon.Test\Arrowgene.Ddon.Test.csproj", "{86D48D8F-AA02-4BB8-9B5C-1313C8310F5F}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arrowgene.Ddon.Rpc", "Arrowgene.Ddon.Rpc\Arrowgene.Ddon.Rpc.csproj", "{2DE5385B-B8ED-491D-AC6C-895DC154C79E}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arrowgene.Ddon.Rpc", "Arrowgene.Ddon.Rpc\Arrowgene.Ddon.Rpc.csproj", "{2DE5385B-B8ED-491D-AC6C-895DC154C79E}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arrowgene.Ddon.Rpc.Web", "Arrowgene.Ddon.Rpc.Web\Arrowgene.Ddon.Rpc.Web.csproj", "{A98B686D-6C3D-473D-B69D-940ED343D7AF}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arrowgene.Ddon.Rpc.Web", "Arrowgene.Ddon.Rpc.Web\Arrowgene.Ddon.Rpc.Web.csproj", "{A98B686D-6C3D-473D-B69D-940ED343D7AF}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Arrowgene.Ddon.Client", "Arrowgene.Ddon.Client\Arrowgene.Ddon.Client.csproj", "{DAC06C22-BD06-4592-A60A-3990B85EF7A8}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arrowgene.Ddon.Client", "Arrowgene.Ddon.Client\Arrowgene.Ddon.Client.csproj", "{DAC06C22-BD06-4592-A60A-3990B85EF7A8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution