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: Day/Night support for monster spawns #265

Merged
merged 10 commits into from
Apr 28, 2024
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using Arrowgene.Ddon.Server;
using Arrowgene.Ddon.Server.Network;
using Arrowgene.Ddon.Shared.Crypto;
Expand All @@ -13,7 +14,16 @@ namespace Arrowgene.Ddon.GameServer.Handler
public class InstanceGetEnemySetListHandler : StructurePacketHandler<GameClient, C2SInstanceGetEnemySetListReq>
{
private static readonly ServerLogger Logger = LogProvider.Logger<ServerLogger>(typeof(InstanceGetEnemySetListHandler));

private static readonly long ORIGINAL_REAL_TIME_SEC = 0x55DDD470; // Taken from the pcaps. A few days before DDOn release. Wednesday, 26 August 2015 15:00:00

private long calcGameTimeMSec(DateTimeOffset realTime, long originalRealTimeSec, uint gameTimeOneDayMin, uint gameTimeDayHour)
{
long result = (1440 * (realTime.Millisecond + 1000 * (realTime.ToUnixTimeSeconds() - originalRealTimeSec)) / gameTimeOneDayMin)
% (3600000 * gameTimeDayHour);
return result;
}
const int gameDayLength = 24;
const int gameDayLengthRealTime = 90;
Conner-Schaffer marked this conversation as resolved.
Show resolved Hide resolved
public InstanceGetEnemySetListHandler(DdonGameServer server) : base(server)
{
}
Expand All @@ -24,7 +34,6 @@ public override void Handle(GameClient client, StructurePacket<C2SInstanceGetEne
byte subGroupId = request.Structure.SubGroupId;
client.Character.Stage = stageId;


List<Enemy> spawns = Server.AssetRepository.EnemySpawnAsset.Enemies.GetValueOrDefault((stageId, subGroupId)) ?? new List<Enemy>();

// TODO test
Expand All @@ -43,10 +52,50 @@ public override void Handle(GameClient client, StructurePacket<C2SInstanceGetEne
PositionIndex = i,
EnemyInfo = spawn.asCDataStageLayoutEnemyPresetEnemyInfoClient()
};
response.EnemyList.Add(enemy);
// Get spawn time from the enemy object
string spawnTime = spawn.SpawnTime;
long startMilliseconds, endMilliseconds;
ConvertSpawnTimeToMilliseconds(spawnTime, out startMilliseconds, out endMilliseconds);
Conner-Schaffer marked this conversation as resolved.
Show resolved Hide resolved

// Calculate current game time
long gameTimeMSec = calcGameTimeMSec(DateTimeOffset.Now, ORIGINAL_REAL_TIME_SEC, gameDayLengthRealTime, gameDayLength);

// If end < start, it spans past midnight and needs special range handling
if(endMilliseconds < startMilliseconds)
{
if(gameTimeMSec <= endMilliseconds // Morning range is 0 (midnight) to end time
|| gameTimeMSec >= startMilliseconds) // Evening range is start time and onwards
{
response.EnemyList.Add(enemy);
}
}
else if(gameTimeMSec >= startMilliseconds && gameTimeMSec <= endMilliseconds)
{
response.EnemyList.Add(enemy);
}
}

client.Send(response);
}

private void ConvertSpawnTimeToMilliseconds(string spawnTime, out long startMilliseconds, out long endMilliseconds)
{
// Split the spawnTime string at the comma to get start and end times
string[] spawnTimes = spawnTime.Split(',');

// Split the start time at the colon to get hours and minutes
string[] startTimeComponents = spawnTimes[0].Split(':');
int startHours = int.Parse(startTimeComponents[0]);
int startMinutes = int.Parse(startTimeComponents[1]);

// Split the end time at the colon to get hours and minutes
string[] endTimeComponents = spawnTimes[1].Split(':');
int endHours = int.Parse(endTimeComponents[0]);
int endMinutes = int.Parse(endTimeComponents[1]);

// Convert hours and minutes into milliseconds
startMilliseconds = (startHours * 3600000) + (startMinutes * 60000);
endMilliseconds = (endHours * 3600000) + (endMinutes * 60000);
}
}
}
35 changes: 33 additions & 2 deletions Arrowgene.Ddon.Shared/AssetReader/EnemySpawnAssetDeserializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class EnemySpawnAssetDeserializer : IAssetDeserializer<EnemySpawnAsset>
{
private static readonly ILogger Logger = LogProvider.Logger(typeof(EnemySpawnAssetDeserializer));

private static readonly string[] ENEMY_HEADERS = new string[]{"StageId", "LayerNo", "GroupId", "SubGroupId", "EnemyId", "NamedEnemyParamsId", "RaidBossId", "Scale", "Lv", "HmPresetNo", "StartThinkTblNo", "RepopNum", "RepopCount", "EnemyTargetTypesId", "MontageFixNo", "SetType", "InfectionType", "IsBossGauge", "IsBossBGM", "IsManualSet", "IsAreaBoss", "BloodOrbs", "HighOrbs", "Experience", "DropsTableId"};
private static readonly string[] ENEMY_HEADERS = new string[]{"StageId", "LayerNo", "GroupId", "SubGroupId", "EnemyId", "NamedEnemyParamsId", "RaidBossId", "Scale", "Lv", "HmPresetNo", "StartThinkTblNo", "RepopNum", "RepopCount", "EnemyTargetTypesId", "MontageFixNo", "SetType", "InfectionType", "IsBossGauge", "IsBossBGM", "IsManualSet", "IsAreaBoss", "BloodOrbs", "HighOrbs", "Experience", "DropsTableId", "SpawnTime"};
private static readonly string[] DROPS_TABLE_HEADERS = new string[]{"ItemId", "ItemNum", "MaxItemNum", "Quality", "IsHidden", "DropChance"};

public EnemySpawnAsset ReadPath(string path)
Expand Down Expand Up @@ -99,6 +99,17 @@ public EnemySpawnAsset ReadPath(string path)
HighOrbs = row[enemySchemaIndexes["HighOrbs"]].GetUInt32(),
Experience = row[enemySchemaIndexes["Experience"]].GetUInt32(),
};
if(enemySchemaIndexes.ContainsKey("SpawnTime"))
{
enemy.SpawnTime = row[enemySchemaIndexes["SpawnTime"]].GetString();
}
else
{
enemy.SpawnTime = "00:00,23:59";
}



int dropsTableId = row[enemySchemaIndexes["DropsTableId"]].GetInt32();
if(dropsTableId >= 0)
{
Expand All @@ -111,6 +122,26 @@ public EnemySpawnAsset ReadPath(string path)
return asset;
}

// private void ConvertSpawnTimeToMilliseconds(string spawnTime, out long startMilliseconds, out long endMilliseconds)
// {
// // Split the spawnTime string at the comma to get start and end times
// string[] spawnTimes = spawnTime.Split(',');

// // Split the start time at the colon to get hours and minutes
// string[] startTimeComponents = spawnTimes[0].Split(':');
// int startHours = int.Parse(startTimeComponents[0]);
// int startMinutes = int.Parse(startTimeComponents[1]);

// // Split the end time at the colon to get hours and minutes
// string[] endTimeComponents = spawnTimes[1].Split(':');
// int endHours = int.Parse(endTimeComponents[0]);
// int endMinutes = int.Parse(endTimeComponents[1]);

// // Convert hours and minutes into milliseconds
// startMilliseconds = (startHours * 3600000) + (startMinutes * 60000);
// endMilliseconds = (endHours * 3600000) + (endMinutes * 60000);
// }

protected uint ParseHexUInt(string str)
{
str = str.TrimStart('0', 'x');
Expand All @@ -131,4 +162,4 @@ private Dictionary<string, int> findSchemaIndexes(string[] reference, List<strin
return schemaIndexes;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public CDataStageLayoutEnemyPresetEnemyInfoClient()
public bool IsAreaBoss { get; set; }
public bool IsBloodEnemy { get; set; }
public bool IsHighOrbEnemy { get; set; }
public string SpawnTime { get; set; }
Conner-Schaffer marked this conversation as resolved.
Show resolved Hide resolved

public class Serializer : EntitySerializer<CDataStageLayoutEnemyPresetEnemyInfoClient>
{
Expand Down
Loading
Loading