Add LongExtensions.Truncate32 and refactor tick handling - #614

Merged
AngeloTadeucci merged 5 commits into
masterfrom
field-tick
Oct 15, 2025
Merged

Add LongExtensions.Truncate32 and refactor tick handling#614
AngeloTadeucci merged 5 commits into
masterfrom
field-tick

Conversation

@AngeloTadeucci

@AngeloTadeucciAngeloTadeucci commented Oct 13, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes

    • Expired buffs and skill cooldowns are no longer saved or restored.
    • Timing calculations for portals, fishing, instruments, breakables, and region skills made more consistent to reduce desync and overflow issues.
  • Refactor

    • Standardized conversion of 64-bit ticks to 32-bit client timers for improved timing reliability.
  • Tests

    • Added comprehensive tests validating 32-bit tick truncation behavior.

@coderabbitai

coderabbitaiBot commented Oct 13, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a 32-bit truncation helper (Truncate32) and applies it across tick serialization and packet writes, exposes a 32-bit FieldTickInt on IField/FieldManager, filters expired buffs/cooldowns when saving cache, and renames a BuffManager parameter.

Changes

Cohort / File(s)Summary
Tick truncation utility & tests
Maple2.Tools/Extensions/LongExtensions.cs, Maple2.Server.Tests/Tools/LongExtensionsTests.cs
Add Truncate32(this long) extension to truncate 64-bit ticks to 32-bit ints; add comprehensive unit tests covering boundaries, wraparound, and TickCount-like behavior.
Field tick API & usage
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs, Maple2.Server.Game/Manager/Field/FieldManager/IField.cs, Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs, Maple2.Server.Game/Manager/DungeonManager.cs, Maple2.Server.Game/Manager/FishingManager.cs, Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
Introduce FieldTickInt (derived via Truncate32) on FieldManager/IField; replace direct 64→32 casts with .Truncate32() or use FieldTickInt where 32-bit ticks are required; update tick initializations (e.g., use Lobby.FieldTick).
Serialization & packets
Maple2.Model/Game/User/SkillCooldown.cs, Maple2.Server.Game/Model/Field/Buff.cs, Maple2.Server.Game/Packets/BreakablePacket.cs, Maple2.Server.Game/Packets/InstrumentPacket.cs, Maple2.Server.Game/Packets/RegionSkillPacket.cs
Replace direct (int) casts of tick values with .Truncate32() when writing to buffers/packets; add using Maple2.Tools.Extensions.
Cache save filtering
Maple2.Server.Game/Session/GameSession.cs
Filter out expired buffs and skill cooldowns (Where(EndTick - fieldTick > 0)) before projecting and saving cache entries; compute MsRemaining via .Truncate32().
BuffManager signature change
Maple2.Server.Game/Manager/BuffManager.cs
Rename public method parameter from buffscacheBuffs in SetCacheBuffs(IList<BuffInfo> cacheBuffs, long currentTick) and update internal iteration/usage.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Player
participant GameSession
participant Field as FieldManager
participant BuffManager
participant Persistence as PlayerConfigStorage
Player->>GameSession: Request SaveCacheConfig
GameSession->>Field: Read FieldTick (64-bit)
Field-->>GameSession: FieldTickInt (FieldTick.Truncate32())
GameSession->>GameSession: Filter Buffs/Cooldowns (EndTick - FieldTick > 0)
GameSession->>Persistence: Save filtered BuffInfo & SkillCooldownInfo (MsRemaining via Truncate32)
Persistence-->>GameSession: Ack
GameSession-->>Player: Done
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Zintixx

Poem

I hop through ticks from long to small,
Snip 64-bits till they answer the call.
Packets line up, portals chime,
Buffs saved neat and right on time.
A rabbit trims each ticking line — 🐇⌛

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title Check✅ PassedThe title succinctly captures the core changes introduced in this pull request by mentioning both the addition of the Truncate32 extension method and the overarching refactoring of tick handling throughout the codebase. It is concise, specific, and directly reflects the main developer intent without extraneous detail.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch field-tick

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between deed140 and d5aff14.

📒 Files selected for processing (1)
  • Maple2.Server.Game/Session/GameSession.cs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Maple2.Server.Game/Session/GameSession.cs (3)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-44)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (3)
Maple2.Server.Game/Session/GameSession.cs (3)

30-30: LGTM!

The import enables the use of Truncate32() for standardized 32-bit tick conversions throughout this file.


818-827: Good filtering of expired buffs.

The filtering logic correctly excludes buffs where EndTick - fieldTick <= 0, ensuring only active buffs are cached. The use of Truncate32() for the remaining duration calculation aligns with the broader refactoring effort.


830-839: Good filtering of expired cooldowns.

The filtering and projection logic mirrors the buff handling above, maintaining consistency across cache persistence.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
Maple2.Tools/Extensions/LongExtensions.cs (1)

10-12: LGTM! Clean truncation logic.

The implementation correctly truncates 64-bit values to 32-bit by masking the lower 32 bits and casting to int, which properly handles wraparound (values > int.MaxValue become negative, matching Environment.TickCount behavior).

Optional performance optimization:

Consider marking this method with [MethodImpl(MethodImplOptions.AggressiveInlining)] to ensure it's inlined at call sites, as it's a simple operation called frequently in serialization paths:

+using System.Runtime.CompilerServices;+
namespace Maple2.Tools.Extensions;
public static class LongExtensions {
/// <summary>
/// Truncates a long value to a 32-bit int, handling overflow properly.
/// This is useful for converting Environment.TickCount64 to match Environment.TickCount behavior.
/// </summary>
/// <param name="value">The long value to truncate</param>
/// <returns>The truncated int value</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Truncate32(this long value) {
return (int) (0xFFFFFFFF & value);
}
}
Maple2.Server.Game/Packets/BreakablePacket.cs (1)

26-29: Correct 32‑bit tick truncation; minor consistency refactor

Using Truncate32() here is correct and safer than direct casts. For consistency and tiny perf, also cache Environment.TickCount64 in the single‑update overload.

Apply this diff to the single-update method:

- public static ByteWriter Update(FieldBreakable breakable) {+ public static ByteWriter Update(FieldBreakable breakable) {
var pWriter = Packet.Of(SendOp.Breakable);
pWriter.Write<Command>(Command.Update);
pWriter.WriteString(breakable.EntityId);
pWriter.Write<BreakableState>(breakable.State);
pWriter.WriteBool(breakable.Visible);
- if (breakable.BaseTick > 0) {- pWriter.WriteInt((Environment.TickCount64 - breakable.BaseTick).Truncate32());+ long currentTick = Environment.TickCount64;+ if (breakable.BaseTick > 0) {+ pWriter.WriteInt((currentTick - breakable.BaseTick).Truncate32());
pWriter.WriteInt(breakable.BaseTick.Truncate32());
} else {
pWriter.WriteInt();
pWriter.WriteInt();
}

Additionally, to guarantee behavior even inside checked contexts, consider making the extension use an unchecked cast:

publicstaticintTruncate32(thislongvalue)=>unchecked((int)value);

Based on learnings

Also applies to: 45-47

Maple2.Server.Game/Session/GameSession.cs (1)

813-839: Clamp MsRemaining to int range to avoid overflow

Current cast may overflow if remaining ms > int.MaxValue. Clamp before casting.

Apply this diff:

- .Where(buff => buff.EndTick - fieldTick > 0)+ .Where(buff => buff.EndTick - fieldTick > 0)
.Select(buff => new BuffInfo {
Id = buff.Id,
Level = buff.Level,
- MsRemaining = (int) (buff.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(buff.EndTick - fieldTick, int.MaxValue),
Stacks = buff.Stacks,
Enabled = buff.Enabled,
StopTime = stopTime,
}),
- .Where(cooldown => cooldown.EndTick - fieldTick > 0)+ .Where(cooldown => cooldown.EndTick - fieldTick > 0)
.Select(cooldown => new SkillCooldownInfo {
SkillId = cooldown.SkillId,
SkillLevel = cooldown.SkillLevel,
GroupId = cooldown.GroupId,
- MsRemaining = (int) (cooldown.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(cooldown.EndTick - fieldTick, int.MaxValue),
StopTime = stopTime,
Charges = cooldown.Charges,
}),

Optional: also clamp DeathInfo.MsRemaining to non-negative to avoid sending negative values when already expired.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c45ccca and 72b5e0f.

📒 Files selected for processing (14)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (1)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/FishingManager.cs (1)
Maple2.Server.Game/Packets/FishingPacket.cs (1)
  • FishingPacket (12-156)
Maple2.Server.Game/Session/GameSession.cs (2)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-62)
Maple2.Server.Game/Packets/BreakablePacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (11)
Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: Approve stack restoration in SetCacheBuffs Passing info.Stacks to AddBuff restores buff stacks correctly; BuffInfo.Stacks is initialized in PlayerConfigResponse.

Maple2.Model/Game/User/SkillCooldown.cs (1)

24-24: LGTM! Consistent use of Truncate32 for serialization.

The change from direct cast to Truncate32() makes the 32-bit truncation intent explicit and aligns with the refactoring pattern.

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: LGTM! Improved timing consistency.

The change from Environment.TickCount to Lobby.FieldTick centralizes timing through the field manager, ensuring consistent field-relative timing for dungeon room records.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM! Consistent packet serialization.

The change to Truncate32() makes the 32-bit truncation explicit for packet serialization, aligning with the refactoring pattern.

Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)

21-21: LGTM! Consistent packet serialization.

The change to Truncate32() for NextTick serialization aligns with the refactoring pattern and makes truncation intent explicit.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-323: LGTM! Consistent buff serialization.

The changes to use Truncate32() for both StartTick and EndTick align with the refactoring pattern and make the 32-bit truncation explicit for byte serialization.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM! Consistent use of FieldTickInt for portal timing.

The change to use FieldTickInt directly for quest portal timing is cleaner than casting FieldTick and aligns with the 32-bit tick representation pattern.


628-628: LGTM! Consistent portal timing.

Using FieldTickInt for the bonus map portal's EndTick aligns with the other portal timing changes and the 32-bit tick pattern.

Maple2.Server.Game/Manager/FishingManager.cs (1)

257-257: LGTM! Cleaner fishing timer calculation.

Using session.Field.FieldTickInt directly is cleaner than casting FieldTick and aligns with the refactoring to use the 32-bit tick property.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)

264-270: Good addition: 32‑bit tick accessor mirrors TickCount semantics

The Truncate32-based property is appropriate for client-facing 32-bit tick usage and avoids unsafe casts. Nice doc and placement.

Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1)

59-59: IField implementers updated FieldManager defines FieldTickInt; no other IField implementers exist.

Comment threadMaple2.Server.Tests/Tools/LongExtensionsTests.cs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)

1-2: Restore missing NUnit using and replace C# 12 collection expression

[Test], [TestCase], and Assert won’t resolve without using NUnit.Framework;, so the test project doesn’t compile. The long[] testValues = [...] literal also requires C# 12; the repo still targets earlier language versions, so that syntax fails to build. Please add the NUnit using and fall back to a classic array initializer so the tests compile again.

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;
- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };

Also applies to: 121-135

🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1)

4-4: Verify the import is intentional.

The added import appears unused in this file.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • Maple2.Server.Game/Manager/BuffManager.cs
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/DungeonManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
  • Maple2.Server.Game/Packets/BreakablePacket.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
🧰 Additional context used
🧬 Code graph analysis (5)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (2)
Maple2.Model/Game/User/SkillCooldown.cs (2)

3-3: LGTM: Import required for extension method.

The import is necessary for using the Truncate32() extension method and is correctly placed.


24-24: LGTM: Improved clarity with explicit truncation.

The change from (int) EndTick to EndTick.Truncate32() is functionally equivalent but significantly improves code clarity by making the truncation intent explicit. This aligns with the broader refactoring pattern applied across the codebase for tick handling.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (2)

1-3: Fix missing NUnit import to compile tests

Add NUnit using so [Test]/Assert resolve.

Apply:

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;

121-136: Replace C# 12 collection expression with classic array initializer

Ensures compatibility with older language versions.

Apply:

- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
- 0xFFFFFFFF,+ 0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };
🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/DungeonManager.cs (1)

352-352: Avoid potential overflow: cast after dividing

Divide on long first, then cast to int.

Apply:

- UserRecord.TotalSeconds = (int) (Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000;+ UserRecord.TotalSeconds = (int) ((Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
🚧 Files skipped from review as they are similar to previous changes (7)
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Model/Game/User/SkillCooldown.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
🧰 Additional context used
🧬 Code graph analysis (7)
Maple2.Server.Game/Packets/BreakablePacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (7)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM: Safe 32-bit truncation for quest portal ticks.

The changes correctly use Truncate32() for EndTick and FieldTickInt for StartTick. The explicit cast to long before adding milliseconds prevents double-precision arithmetic, and Truncate32() safely masks the lower 32 bits without sign extension issues.


628-628: LGTM: Consistent tick truncation pattern.

The EndTick calculation correctly applies the same safe truncation pattern used for quest portals, ensuring consistent tick handling across portal types.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-324: Consistent 32-bit tick serialization

Using Truncate32() here is correct and consistent with packet expectations.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM: Use Truncate32 for StartTick

Correctly avoids checked-cast overflow and preserves lower 32 bits.

Maple2.Server.Game/Packets/BreakablePacket.cs (1)

27-29: LGTM: Safe 32-bit truncation for tick diff and base tick

Truncate32() matches TickCount wrap semantics and avoids overflow on casts.

Also applies to: 45-47

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: EndTick assignment already uses FieldTick—time bases match

Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: LGTM! Good refactor and bug fix.

The changes improve code clarity and correctness:

  1. Parameter rename (buffscacheBuffs): Avoids shadowing the class-level buffs field, making the code easier to read and maintain.

  2. Stack preservation (line 513): Now passes info.Stacks to AddBuff, correctly preserving stack counts when loading cached buffs. Previously, stacks would default to 0, losing this information.

The validation logic and filtering (lines 507-512) appropriately handle invalid buffs and skip expired buffs that don't use in-game time.

@AngeloTadeucci
AngeloTadeucci merged commit c3067a2 into masterOct 15, 2025
4 of 5 checks passed
@AngeloTadeucci
AngeloTadeucci deleted the field-tick branch October 15, 2025 02:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AngeloTadeucci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Add LongExtensions.Truncate32 and refactor tick handling - #614

Merged
AngeloTadeucci merged 5 commits into
masterfrom
field-tick
Oct 15, 2025
Merged

Add LongExtensions.Truncate32 and refactor tick handling#614
AngeloTadeucci merged 5 commits into
masterfrom
field-tick

Conversation

@AngeloTadeucci

@AngeloTadeucciAngeloTadeucci commented Oct 13, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes

    • Expired buffs and skill cooldowns are no longer saved or restored.
    • Timing calculations for portals, fishing, instruments, breakables, and region skills made more consistent to reduce desync and overflow issues.
  • Refactor

    • Standardized conversion of 64-bit ticks to 32-bit client timers for improved timing reliability.
  • Tests

    • Added comprehensive tests validating 32-bit tick truncation behavior.

@coderabbitai

coderabbitaiBot commented Oct 13, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a 32-bit truncation helper (Truncate32) and applies it across tick serialization and packet writes, exposes a 32-bit FieldTickInt on IField/FieldManager, filters expired buffs/cooldowns when saving cache, and renames a BuffManager parameter.

Changes

Cohort / File(s)Summary
Tick truncation utility & tests
Maple2.Tools/Extensions/LongExtensions.cs, Maple2.Server.Tests/Tools/LongExtensionsTests.cs
Add Truncate32(this long) extension to truncate 64-bit ticks to 32-bit ints; add comprehensive unit tests covering boundaries, wraparound, and TickCount-like behavior.
Field tick API & usage
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs, Maple2.Server.Game/Manager/Field/FieldManager/IField.cs, Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs, Maple2.Server.Game/Manager/DungeonManager.cs, Maple2.Server.Game/Manager/FishingManager.cs, Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
Introduce FieldTickInt (derived via Truncate32) on FieldManager/IField; replace direct 64→32 casts with .Truncate32() or use FieldTickInt where 32-bit ticks are required; update tick initializations (e.g., use Lobby.FieldTick).
Serialization & packets
Maple2.Model/Game/User/SkillCooldown.cs, Maple2.Server.Game/Model/Field/Buff.cs, Maple2.Server.Game/Packets/BreakablePacket.cs, Maple2.Server.Game/Packets/InstrumentPacket.cs, Maple2.Server.Game/Packets/RegionSkillPacket.cs
Replace direct (int) casts of tick values with .Truncate32() when writing to buffers/packets; add using Maple2.Tools.Extensions.
Cache save filtering
Maple2.Server.Game/Session/GameSession.cs
Filter out expired buffs and skill cooldowns (Where(EndTick - fieldTick > 0)) before projecting and saving cache entries; compute MsRemaining via .Truncate32().
BuffManager signature change
Maple2.Server.Game/Manager/BuffManager.cs
Rename public method parameter from buffscacheBuffs in SetCacheBuffs(IList<BuffInfo> cacheBuffs, long currentTick) and update internal iteration/usage.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Player
participant GameSession
participant Field as FieldManager
participant BuffManager
participant Persistence as PlayerConfigStorage
Player->>GameSession: Request SaveCacheConfig
GameSession->>Field: Read FieldTick (64-bit)
Field-->>GameSession: FieldTickInt (FieldTick.Truncate32())
GameSession->>GameSession: Filter Buffs/Cooldowns (EndTick - FieldTick > 0)
GameSession->>Persistence: Save filtered BuffInfo & SkillCooldownInfo (MsRemaining via Truncate32)
Persistence-->>GameSession: Ack
GameSession-->>Player: Done
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Zintixx

Poem

I hop through ticks from long to small,
Snip 64-bits till they answer the call.
Packets line up, portals chime,
Buffs saved neat and right on time.
A rabbit trims each ticking line — 🐇⌛

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title Check✅ PassedThe title succinctly captures the core changes introduced in this pull request by mentioning both the addition of the Truncate32 extension method and the overarching refactoring of tick handling throughout the codebase. It is concise, specific, and directly reflects the main developer intent without extraneous detail.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch field-tick

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between deed140 and d5aff14.

📒 Files selected for processing (1)
  • Maple2.Server.Game/Session/GameSession.cs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Maple2.Server.Game/Session/GameSession.cs (3)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-44)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (3)
Maple2.Server.Game/Session/GameSession.cs (3)

30-30: LGTM!

The import enables the use of Truncate32() for standardized 32-bit tick conversions throughout this file.


818-827: Good filtering of expired buffs.

The filtering logic correctly excludes buffs where EndTick - fieldTick <= 0, ensuring only active buffs are cached. The use of Truncate32() for the remaining duration calculation aligns with the broader refactoring effort.


830-839: Good filtering of expired cooldowns.

The filtering and projection logic mirrors the buff handling above, maintaining consistency across cache persistence.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
Maple2.Tools/Extensions/LongExtensions.cs (1)

10-12: LGTM! Clean truncation logic.

The implementation correctly truncates 64-bit values to 32-bit by masking the lower 32 bits and casting to int, which properly handles wraparound (values > int.MaxValue become negative, matching Environment.TickCount behavior).

Optional performance optimization:

Consider marking this method with [MethodImpl(MethodImplOptions.AggressiveInlining)] to ensure it's inlined at call sites, as it's a simple operation called frequently in serialization paths:

+using System.Runtime.CompilerServices;+
namespace Maple2.Tools.Extensions;
public static class LongExtensions {
/// <summary>
/// Truncates a long value to a 32-bit int, handling overflow properly.
/// This is useful for converting Environment.TickCount64 to match Environment.TickCount behavior.
/// </summary>
/// <param name="value">The long value to truncate</param>
/// <returns>The truncated int value</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Truncate32(this long value) {
return (int) (0xFFFFFFFF & value);
}
}
Maple2.Server.Game/Packets/BreakablePacket.cs (1)

26-29: Correct 32‑bit tick truncation; minor consistency refactor

Using Truncate32() here is correct and safer than direct casts. For consistency and tiny perf, also cache Environment.TickCount64 in the single‑update overload.

Apply this diff to the single-update method:

- public static ByteWriter Update(FieldBreakable breakable) {+ public static ByteWriter Update(FieldBreakable breakable) {
var pWriter = Packet.Of(SendOp.Breakable);
pWriter.Write<Command>(Command.Update);
pWriter.WriteString(breakable.EntityId);
pWriter.Write<BreakableState>(breakable.State);
pWriter.WriteBool(breakable.Visible);
- if (breakable.BaseTick > 0) {- pWriter.WriteInt((Environment.TickCount64 - breakable.BaseTick).Truncate32());+ long currentTick = Environment.TickCount64;+ if (breakable.BaseTick > 0) {+ pWriter.WriteInt((currentTick - breakable.BaseTick).Truncate32());
pWriter.WriteInt(breakable.BaseTick.Truncate32());
} else {
pWriter.WriteInt();
pWriter.WriteInt();
}

Additionally, to guarantee behavior even inside checked contexts, consider making the extension use an unchecked cast:

publicstaticintTruncate32(thislongvalue)=>unchecked((int)value);

Based on learnings

Also applies to: 45-47

Maple2.Server.Game/Session/GameSession.cs (1)

813-839: Clamp MsRemaining to int range to avoid overflow

Current cast may overflow if remaining ms > int.MaxValue. Clamp before casting.

Apply this diff:

- .Where(buff => buff.EndTick - fieldTick > 0)+ .Where(buff => buff.EndTick - fieldTick > 0)
.Select(buff => new BuffInfo {
Id = buff.Id,
Level = buff.Level,
- MsRemaining = (int) (buff.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(buff.EndTick - fieldTick, int.MaxValue),
Stacks = buff.Stacks,
Enabled = buff.Enabled,
StopTime = stopTime,
}),
- .Where(cooldown => cooldown.EndTick - fieldTick > 0)+ .Where(cooldown => cooldown.EndTick - fieldTick > 0)
.Select(cooldown => new SkillCooldownInfo {
SkillId = cooldown.SkillId,
SkillLevel = cooldown.SkillLevel,
GroupId = cooldown.GroupId,
- MsRemaining = (int) (cooldown.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(cooldown.EndTick - fieldTick, int.MaxValue),
StopTime = stopTime,
Charges = cooldown.Charges,
}),

Optional: also clamp DeathInfo.MsRemaining to non-negative to avoid sending negative values when already expired.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c45ccca and 72b5e0f.

📒 Files selected for processing (14)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (1)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/FishingManager.cs (1)
Maple2.Server.Game/Packets/FishingPacket.cs (1)
  • FishingPacket (12-156)
Maple2.Server.Game/Session/GameSession.cs (2)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-62)
Maple2.Server.Game/Packets/BreakablePacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (11)
Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: Approve stack restoration in SetCacheBuffs Passing info.Stacks to AddBuff restores buff stacks correctly; BuffInfo.Stacks is initialized in PlayerConfigResponse.

Maple2.Model/Game/User/SkillCooldown.cs (1)

24-24: LGTM! Consistent use of Truncate32 for serialization.

The change from direct cast to Truncate32() makes the 32-bit truncation intent explicit and aligns with the refactoring pattern.

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: LGTM! Improved timing consistency.

The change from Environment.TickCount to Lobby.FieldTick centralizes timing through the field manager, ensuring consistent field-relative timing for dungeon room records.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM! Consistent packet serialization.

The change to Truncate32() makes the 32-bit truncation explicit for packet serialization, aligning with the refactoring pattern.

Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)

21-21: LGTM! Consistent packet serialization.

The change to Truncate32() for NextTick serialization aligns with the refactoring pattern and makes truncation intent explicit.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-323: LGTM! Consistent buff serialization.

The changes to use Truncate32() for both StartTick and EndTick align with the refactoring pattern and make the 32-bit truncation explicit for byte serialization.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM! Consistent use of FieldTickInt for portal timing.

The change to use FieldTickInt directly for quest portal timing is cleaner than casting FieldTick and aligns with the 32-bit tick representation pattern.


628-628: LGTM! Consistent portal timing.

Using FieldTickInt for the bonus map portal's EndTick aligns with the other portal timing changes and the 32-bit tick pattern.

Maple2.Server.Game/Manager/FishingManager.cs (1)

257-257: LGTM! Cleaner fishing timer calculation.

Using session.Field.FieldTickInt directly is cleaner than casting FieldTick and aligns with the refactoring to use the 32-bit tick property.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)

264-270: Good addition: 32‑bit tick accessor mirrors TickCount semantics

The Truncate32-based property is appropriate for client-facing 32-bit tick usage and avoids unsafe casts. Nice doc and placement.

Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1)

59-59: IField implementers updated FieldManager defines FieldTickInt; no other IField implementers exist.

Comment threadMaple2.Server.Tests/Tools/LongExtensionsTests.cs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)

1-2: Restore missing NUnit using and replace C# 12 collection expression

[Test], [TestCase], and Assert won’t resolve without using NUnit.Framework;, so the test project doesn’t compile. The long[] testValues = [...] literal also requires C# 12; the repo still targets earlier language versions, so that syntax fails to build. Please add the NUnit using and fall back to a classic array initializer so the tests compile again.

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;
- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };

Also applies to: 121-135

🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1)

4-4: Verify the import is intentional.

The added import appears unused in this file.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • Maple2.Server.Game/Manager/BuffManager.cs
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/DungeonManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
  • Maple2.Server.Game/Packets/BreakablePacket.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
🧰 Additional context used
🧬 Code graph analysis (5)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (2)
Maple2.Model/Game/User/SkillCooldown.cs (2)

3-3: LGTM: Import required for extension method.

The import is necessary for using the Truncate32() extension method and is correctly placed.


24-24: LGTM: Improved clarity with explicit truncation.

The change from (int) EndTick to EndTick.Truncate32() is functionally equivalent but significantly improves code clarity by making the truncation intent explicit. This aligns with the broader refactoring pattern applied across the codebase for tick handling.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (2)

1-3: Fix missing NUnit import to compile tests

Add NUnit using so [Test]/Assert resolve.

Apply:

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;

121-136: Replace C# 12 collection expression with classic array initializer

Ensures compatibility with older language versions.

Apply:

- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
- 0xFFFFFFFF,+ 0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };
🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/DungeonManager.cs (1)

352-352: Avoid potential overflow: cast after dividing

Divide on long first, then cast to int.

Apply:

- UserRecord.TotalSeconds = (int) (Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000;+ UserRecord.TotalSeconds = (int) ((Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
🚧 Files skipped from review as they are similar to previous changes (7)
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Model/Game/User/SkillCooldown.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
🧰 Additional context used
🧬 Code graph analysis (7)
Maple2.Server.Game/Packets/BreakablePacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (7)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM: Safe 32-bit truncation for quest portal ticks.

The changes correctly use Truncate32() for EndTick and FieldTickInt for StartTick. The explicit cast to long before adding milliseconds prevents double-precision arithmetic, and Truncate32() safely masks the lower 32 bits without sign extension issues.


628-628: LGTM: Consistent tick truncation pattern.

The EndTick calculation correctly applies the same safe truncation pattern used for quest portals, ensuring consistent tick handling across portal types.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-324: Consistent 32-bit tick serialization

Using Truncate32() here is correct and consistent with packet expectations.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM: Use Truncate32 for StartTick

Correctly avoids checked-cast overflow and preserves lower 32 bits.

Maple2.Server.Game/Packets/BreakablePacket.cs (1)

27-29: LGTM: Safe 32-bit truncation for tick diff and base tick

Truncate32() matches TickCount wrap semantics and avoids overflow on casts.

Also applies to: 45-47

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: EndTick assignment already uses FieldTick—time bases match

Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: LGTM! Good refactor and bug fix.

The changes improve code clarity and correctness:

  1. Parameter rename (buffscacheBuffs): Avoids shadowing the class-level buffs field, making the code easier to read and maintain.

  2. Stack preservation (line 513): Now passes info.Stacks to AddBuff, correctly preserving stack counts when loading cached buffs. Previously, stacks would default to 0, losing this information.

The validation logic and filtering (lines 507-512) appropriately handle invalid buffs and skip expired buffs that don't use in-game time.

@AngeloTadeucci
AngeloTadeucci merged commit c3067a2 into masterOct 15, 2025
4 of 5 checks passed
@AngeloTadeucci
AngeloTadeucci deleted the field-tick branch October 15, 2025 02:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AngeloTadeucci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add LongExtensions.Truncate32 and refactor tick handling - #614

Merged
AngeloTadeucci merged 5 commits into
masterfrom
field-tick
Oct 15, 2025
Merged

Add LongExtensions.Truncate32 and refactor tick handling#614
AngeloTadeucci merged 5 commits into
masterfrom
field-tick

Conversation

@AngeloTadeucci

@AngeloTadeucciAngeloTadeucci commented Oct 13, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes

    • Expired buffs and skill cooldowns are no longer saved or restored.
    • Timing calculations for portals, fishing, instruments, breakables, and region skills made more consistent to reduce desync and overflow issues.
  • Refactor

    • Standardized conversion of 64-bit ticks to 32-bit client timers for improved timing reliability.
  • Tests

    • Added comprehensive tests validating 32-bit tick truncation behavior.

@coderabbitai

coderabbitaiBot commented Oct 13, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a 32-bit truncation helper (Truncate32) and applies it across tick serialization and packet writes, exposes a 32-bit FieldTickInt on IField/FieldManager, filters expired buffs/cooldowns when saving cache, and renames a BuffManager parameter.

Changes

Cohort / File(s)Summary
Tick truncation utility & tests
Maple2.Tools/Extensions/LongExtensions.cs, Maple2.Server.Tests/Tools/LongExtensionsTests.cs
Add Truncate32(this long) extension to truncate 64-bit ticks to 32-bit ints; add comprehensive unit tests covering boundaries, wraparound, and TickCount-like behavior.
Field tick API & usage
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs, Maple2.Server.Game/Manager/Field/FieldManager/IField.cs, Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs, Maple2.Server.Game/Manager/DungeonManager.cs, Maple2.Server.Game/Manager/FishingManager.cs, Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
Introduce FieldTickInt (derived via Truncate32) on FieldManager/IField; replace direct 64→32 casts with .Truncate32() or use FieldTickInt where 32-bit ticks are required; update tick initializations (e.g., use Lobby.FieldTick).
Serialization & packets
Maple2.Model/Game/User/SkillCooldown.cs, Maple2.Server.Game/Model/Field/Buff.cs, Maple2.Server.Game/Packets/BreakablePacket.cs, Maple2.Server.Game/Packets/InstrumentPacket.cs, Maple2.Server.Game/Packets/RegionSkillPacket.cs
Replace direct (int) casts of tick values with .Truncate32() when writing to buffers/packets; add using Maple2.Tools.Extensions.
Cache save filtering
Maple2.Server.Game/Session/GameSession.cs
Filter out expired buffs and skill cooldowns (Where(EndTick - fieldTick > 0)) before projecting and saving cache entries; compute MsRemaining via .Truncate32().
BuffManager signature change
Maple2.Server.Game/Manager/BuffManager.cs
Rename public method parameter from buffscacheBuffs in SetCacheBuffs(IList<BuffInfo> cacheBuffs, long currentTick) and update internal iteration/usage.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Player
participant GameSession
participant Field as FieldManager
participant BuffManager
participant Persistence as PlayerConfigStorage
Player->>GameSession: Request SaveCacheConfig
GameSession->>Field: Read FieldTick (64-bit)
Field-->>GameSession: FieldTickInt (FieldTick.Truncate32())
GameSession->>GameSession: Filter Buffs/Cooldowns (EndTick - FieldTick > 0)
GameSession->>Persistence: Save filtered BuffInfo & SkillCooldownInfo (MsRemaining via Truncate32)
Persistence-->>GameSession: Ack
GameSession-->>Player: Done
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Zintixx

Poem

I hop through ticks from long to small,
Snip 64-bits till they answer the call.
Packets line up, portals chime,
Buffs saved neat and right on time.
A rabbit trims each ticking line — 🐇⌛

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title Check✅ PassedThe title succinctly captures the core changes introduced in this pull request by mentioning both the addition of the Truncate32 extension method and the overarching refactoring of tick handling throughout the codebase. It is concise, specific, and directly reflects the main developer intent without extraneous detail.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch field-tick

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between deed140 and d5aff14.

📒 Files selected for processing (1)
  • Maple2.Server.Game/Session/GameSession.cs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Maple2.Server.Game/Session/GameSession.cs (3)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-44)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (3)
Maple2.Server.Game/Session/GameSession.cs (3)

30-30: LGTM!

The import enables the use of Truncate32() for standardized 32-bit tick conversions throughout this file.


818-827: Good filtering of expired buffs.

The filtering logic correctly excludes buffs where EndTick - fieldTick <= 0, ensuring only active buffs are cached. The use of Truncate32() for the remaining duration calculation aligns with the broader refactoring effort.


830-839: Good filtering of expired cooldowns.

The filtering and projection logic mirrors the buff handling above, maintaining consistency across cache persistence.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
Maple2.Tools/Extensions/LongExtensions.cs (1)

10-12: LGTM! Clean truncation logic.

The implementation correctly truncates 64-bit values to 32-bit by masking the lower 32 bits and casting to int, which properly handles wraparound (values > int.MaxValue become negative, matching Environment.TickCount behavior).

Optional performance optimization:

Consider marking this method with [MethodImpl(MethodImplOptions.AggressiveInlining)] to ensure it's inlined at call sites, as it's a simple operation called frequently in serialization paths:

+using System.Runtime.CompilerServices;+
namespace Maple2.Tools.Extensions;
public static class LongExtensions {
/// <summary>
/// Truncates a long value to a 32-bit int, handling overflow properly.
/// This is useful for converting Environment.TickCount64 to match Environment.TickCount behavior.
/// </summary>
/// <param name="value">The long value to truncate</param>
/// <returns>The truncated int value</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Truncate32(this long value) {
return (int) (0xFFFFFFFF & value);
}
}
Maple2.Server.Game/Packets/BreakablePacket.cs (1)

26-29: Correct 32‑bit tick truncation; minor consistency refactor

Using Truncate32() here is correct and safer than direct casts. For consistency and tiny perf, also cache Environment.TickCount64 in the single‑update overload.

Apply this diff to the single-update method:

- public static ByteWriter Update(FieldBreakable breakable) {+ public static ByteWriter Update(FieldBreakable breakable) {
var pWriter = Packet.Of(SendOp.Breakable);
pWriter.Write<Command>(Command.Update);
pWriter.WriteString(breakable.EntityId);
pWriter.Write<BreakableState>(breakable.State);
pWriter.WriteBool(breakable.Visible);
- if (breakable.BaseTick > 0) {- pWriter.WriteInt((Environment.TickCount64 - breakable.BaseTick).Truncate32());+ long currentTick = Environment.TickCount64;+ if (breakable.BaseTick > 0) {+ pWriter.WriteInt((currentTick - breakable.BaseTick).Truncate32());
pWriter.WriteInt(breakable.BaseTick.Truncate32());
} else {
pWriter.WriteInt();
pWriter.WriteInt();
}

Additionally, to guarantee behavior even inside checked contexts, consider making the extension use an unchecked cast:

publicstaticintTruncate32(thislongvalue)=>unchecked((int)value);

Based on learnings

Also applies to: 45-47

Maple2.Server.Game/Session/GameSession.cs (1)

813-839: Clamp MsRemaining to int range to avoid overflow

Current cast may overflow if remaining ms > int.MaxValue. Clamp before casting.

Apply this diff:

- .Where(buff => buff.EndTick - fieldTick > 0)+ .Where(buff => buff.EndTick - fieldTick > 0)
.Select(buff => new BuffInfo {
Id = buff.Id,
Level = buff.Level,
- MsRemaining = (int) (buff.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(buff.EndTick - fieldTick, int.MaxValue),
Stacks = buff.Stacks,
Enabled = buff.Enabled,
StopTime = stopTime,
}),
- .Where(cooldown => cooldown.EndTick - fieldTick > 0)+ .Where(cooldown => cooldown.EndTick - fieldTick > 0)
.Select(cooldown => new SkillCooldownInfo {
SkillId = cooldown.SkillId,
SkillLevel = cooldown.SkillLevel,
GroupId = cooldown.GroupId,
- MsRemaining = (int) (cooldown.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(cooldown.EndTick - fieldTick, int.MaxValue),
StopTime = stopTime,
Charges = cooldown.Charges,
}),

Optional: also clamp DeathInfo.MsRemaining to non-negative to avoid sending negative values when already expired.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c45ccca and 72b5e0f.

📒 Files selected for processing (14)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (1)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/FishingManager.cs (1)
Maple2.Server.Game/Packets/FishingPacket.cs (1)
  • FishingPacket (12-156)
Maple2.Server.Game/Session/GameSession.cs (2)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-62)
Maple2.Server.Game/Packets/BreakablePacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (11)
Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: Approve stack restoration in SetCacheBuffs Passing info.Stacks to AddBuff restores buff stacks correctly; BuffInfo.Stacks is initialized in PlayerConfigResponse.

Maple2.Model/Game/User/SkillCooldown.cs (1)

24-24: LGTM! Consistent use of Truncate32 for serialization.

The change from direct cast to Truncate32() makes the 32-bit truncation intent explicit and aligns with the refactoring pattern.

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: LGTM! Improved timing consistency.

The change from Environment.TickCount to Lobby.FieldTick centralizes timing through the field manager, ensuring consistent field-relative timing for dungeon room records.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM! Consistent packet serialization.

The change to Truncate32() makes the 32-bit truncation explicit for packet serialization, aligning with the refactoring pattern.

Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)

21-21: LGTM! Consistent packet serialization.

The change to Truncate32() for NextTick serialization aligns with the refactoring pattern and makes truncation intent explicit.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-323: LGTM! Consistent buff serialization.

The changes to use Truncate32() for both StartTick and EndTick align with the refactoring pattern and make the 32-bit truncation explicit for byte serialization.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM! Consistent use of FieldTickInt for portal timing.

The change to use FieldTickInt directly for quest portal timing is cleaner than casting FieldTick and aligns with the 32-bit tick representation pattern.


628-628: LGTM! Consistent portal timing.

Using FieldTickInt for the bonus map portal's EndTick aligns with the other portal timing changes and the 32-bit tick pattern.

Maple2.Server.Game/Manager/FishingManager.cs (1)

257-257: LGTM! Cleaner fishing timer calculation.

Using session.Field.FieldTickInt directly is cleaner than casting FieldTick and aligns with the refactoring to use the 32-bit tick property.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)

264-270: Good addition: 32‑bit tick accessor mirrors TickCount semantics

The Truncate32-based property is appropriate for client-facing 32-bit tick usage and avoids unsafe casts. Nice doc and placement.

Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1)

59-59: IField implementers updated FieldManager defines FieldTickInt; no other IField implementers exist.

Comment threadMaple2.Server.Tests/Tools/LongExtensionsTests.cs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)

1-2: Restore missing NUnit using and replace C# 12 collection expression

[Test], [TestCase], and Assert won’t resolve without using NUnit.Framework;, so the test project doesn’t compile. The long[] testValues = [...] literal also requires C# 12; the repo still targets earlier language versions, so that syntax fails to build. Please add the NUnit using and fall back to a classic array initializer so the tests compile again.

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;
- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };

Also applies to: 121-135

🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1)

4-4: Verify the import is intentional.

The added import appears unused in this file.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • Maple2.Server.Game/Manager/BuffManager.cs
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/DungeonManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
  • Maple2.Server.Game/Packets/BreakablePacket.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
🧰 Additional context used
🧬 Code graph analysis (5)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (2)
Maple2.Model/Game/User/SkillCooldown.cs (2)

3-3: LGTM: Import required for extension method.

The import is necessary for using the Truncate32() extension method and is correctly placed.


24-24: LGTM: Improved clarity with explicit truncation.

The change from (int) EndTick to EndTick.Truncate32() is functionally equivalent but significantly improves code clarity by making the truncation intent explicit. This aligns with the broader refactoring pattern applied across the codebase for tick handling.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (2)

1-3: Fix missing NUnit import to compile tests

Add NUnit using so [Test]/Assert resolve.

Apply:

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;

121-136: Replace C# 12 collection expression with classic array initializer

Ensures compatibility with older language versions.

Apply:

- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
- 0xFFFFFFFF,+ 0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };
🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/DungeonManager.cs (1)

352-352: Avoid potential overflow: cast after dividing

Divide on long first, then cast to int.

Apply:

- UserRecord.TotalSeconds = (int) (Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000;+ UserRecord.TotalSeconds = (int) ((Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
🚧 Files skipped from review as they are similar to previous changes (7)
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Model/Game/User/SkillCooldown.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
🧰 Additional context used
🧬 Code graph analysis (7)
Maple2.Server.Game/Packets/BreakablePacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (7)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM: Safe 32-bit truncation for quest portal ticks.

The changes correctly use Truncate32() for EndTick and FieldTickInt for StartTick. The explicit cast to long before adding milliseconds prevents double-precision arithmetic, and Truncate32() safely masks the lower 32 bits without sign extension issues.


628-628: LGTM: Consistent tick truncation pattern.

The EndTick calculation correctly applies the same safe truncation pattern used for quest portals, ensuring consistent tick handling across portal types.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-324: Consistent 32-bit tick serialization

Using Truncate32() here is correct and consistent with packet expectations.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM: Use Truncate32 for StartTick

Correctly avoids checked-cast overflow and preserves lower 32 bits.

Maple2.Server.Game/Packets/BreakablePacket.cs (1)

27-29: LGTM: Safe 32-bit truncation for tick diff and base tick

Truncate32() matches TickCount wrap semantics and avoids overflow on casts.

Also applies to: 45-47

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: EndTick assignment already uses FieldTick—time bases match

Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: LGTM! Good refactor and bug fix.

The changes improve code clarity and correctness:

  1. Parameter rename (buffscacheBuffs): Avoids shadowing the class-level buffs field, making the code easier to read and maintain.

  2. Stack preservation (line 513): Now passes info.Stacks to AddBuff, correctly preserving stack counts when loading cached buffs. Previously, stacks would default to 0, losing this information.

The validation logic and filtering (lines 507-512) appropriately handle invalid buffs and skip expired buffs that don't use in-game time.

@AngeloTadeucci
AngeloTadeucci merged commit c3067a2 into masterOct 15, 2025
4 of 5 checks passed
@AngeloTadeucci
AngeloTadeucci deleted the field-tick branch October 15, 2025 02:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AngeloTadeucci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add LongExtensions.Truncate32 and refactor tick handling - #614

Merged
AngeloTadeucci merged 5 commits into
masterfrom
field-tick
Oct 15, 2025
Merged

Add LongExtensions.Truncate32 and refactor tick handling#614
AngeloTadeucci merged 5 commits into
masterfrom
field-tick

Conversation

@AngeloTadeucci

@AngeloTadeucciAngeloTadeucci commented Oct 13, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes

    • Expired buffs and skill cooldowns are no longer saved or restored.
    • Timing calculations for portals, fishing, instruments, breakables, and region skills made more consistent to reduce desync and overflow issues.
  • Refactor

    • Standardized conversion of 64-bit ticks to 32-bit client timers for improved timing reliability.
  • Tests

    • Added comprehensive tests validating 32-bit tick truncation behavior.

@coderabbitai

coderabbitaiBot commented Oct 13, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a 32-bit truncation helper (Truncate32) and applies it across tick serialization and packet writes, exposes a 32-bit FieldTickInt on IField/FieldManager, filters expired buffs/cooldowns when saving cache, and renames a BuffManager parameter.

Changes

Cohort / File(s)Summary
Tick truncation utility & tests
Maple2.Tools/Extensions/LongExtensions.cs, Maple2.Server.Tests/Tools/LongExtensionsTests.cs
Add Truncate32(this long) extension to truncate 64-bit ticks to 32-bit ints; add comprehensive unit tests covering boundaries, wraparound, and TickCount-like behavior.
Field tick API & usage
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs, Maple2.Server.Game/Manager/Field/FieldManager/IField.cs, Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs, Maple2.Server.Game/Manager/DungeonManager.cs, Maple2.Server.Game/Manager/FishingManager.cs, Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
Introduce FieldTickInt (derived via Truncate32) on FieldManager/IField; replace direct 64→32 casts with .Truncate32() or use FieldTickInt where 32-bit ticks are required; update tick initializations (e.g., use Lobby.FieldTick).
Serialization & packets
Maple2.Model/Game/User/SkillCooldown.cs, Maple2.Server.Game/Model/Field/Buff.cs, Maple2.Server.Game/Packets/BreakablePacket.cs, Maple2.Server.Game/Packets/InstrumentPacket.cs, Maple2.Server.Game/Packets/RegionSkillPacket.cs
Replace direct (int) casts of tick values with .Truncate32() when writing to buffers/packets; add using Maple2.Tools.Extensions.
Cache save filtering
Maple2.Server.Game/Session/GameSession.cs
Filter out expired buffs and skill cooldowns (Where(EndTick - fieldTick > 0)) before projecting and saving cache entries; compute MsRemaining via .Truncate32().
BuffManager signature change
Maple2.Server.Game/Manager/BuffManager.cs
Rename public method parameter from buffscacheBuffs in SetCacheBuffs(IList<BuffInfo> cacheBuffs, long currentTick) and update internal iteration/usage.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Player
participant GameSession
participant Field as FieldManager
participant BuffManager
participant Persistence as PlayerConfigStorage
Player->>GameSession: Request SaveCacheConfig
GameSession->>Field: Read FieldTick (64-bit)
Field-->>GameSession: FieldTickInt (FieldTick.Truncate32())
GameSession->>GameSession: Filter Buffs/Cooldowns (EndTick - FieldTick > 0)
GameSession->>Persistence: Save filtered BuffInfo & SkillCooldownInfo (MsRemaining via Truncate32)
Persistence-->>GameSession: Ack
GameSession-->>Player: Done
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Zintixx

Poem

I hop through ticks from long to small,
Snip 64-bits till they answer the call.
Packets line up, portals chime,
Buffs saved neat and right on time.
A rabbit trims each ticking line — 🐇⌛

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title Check✅ PassedThe title succinctly captures the core changes introduced in this pull request by mentioning both the addition of the Truncate32 extension method and the overarching refactoring of tick handling throughout the codebase. It is concise, specific, and directly reflects the main developer intent without extraneous detail.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch field-tick

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between deed140 and d5aff14.

📒 Files selected for processing (1)
  • Maple2.Server.Game/Session/GameSession.cs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Maple2.Server.Game/Session/GameSession.cs (3)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-44)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (3)
Maple2.Server.Game/Session/GameSession.cs (3)

30-30: LGTM!

The import enables the use of Truncate32() for standardized 32-bit tick conversions throughout this file.


818-827: Good filtering of expired buffs.

The filtering logic correctly excludes buffs where EndTick - fieldTick <= 0, ensuring only active buffs are cached. The use of Truncate32() for the remaining duration calculation aligns with the broader refactoring effort.


830-839: Good filtering of expired cooldowns.

The filtering and projection logic mirrors the buff handling above, maintaining consistency across cache persistence.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
Maple2.Tools/Extensions/LongExtensions.cs (1)

10-12: LGTM! Clean truncation logic.

The implementation correctly truncates 64-bit values to 32-bit by masking the lower 32 bits and casting to int, which properly handles wraparound (values > int.MaxValue become negative, matching Environment.TickCount behavior).

Optional performance optimization:

Consider marking this method with [MethodImpl(MethodImplOptions.AggressiveInlining)] to ensure it's inlined at call sites, as it's a simple operation called frequently in serialization paths:

+using System.Runtime.CompilerServices;+
namespace Maple2.Tools.Extensions;
public static class LongExtensions {
/// <summary>
/// Truncates a long value to a 32-bit int, handling overflow properly.
/// This is useful for converting Environment.TickCount64 to match Environment.TickCount behavior.
/// </summary>
/// <param name="value">The long value to truncate</param>
/// <returns>The truncated int value</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Truncate32(this long value) {
return (int) (0xFFFFFFFF & value);
}
}
Maple2.Server.Game/Packets/BreakablePacket.cs (1)

26-29: Correct 32‑bit tick truncation; minor consistency refactor

Using Truncate32() here is correct and safer than direct casts. For consistency and tiny perf, also cache Environment.TickCount64 in the single‑update overload.

Apply this diff to the single-update method:

- public static ByteWriter Update(FieldBreakable breakable) {+ public static ByteWriter Update(FieldBreakable breakable) {
var pWriter = Packet.Of(SendOp.Breakable);
pWriter.Write<Command>(Command.Update);
pWriter.WriteString(breakable.EntityId);
pWriter.Write<BreakableState>(breakable.State);
pWriter.WriteBool(breakable.Visible);
- if (breakable.BaseTick > 0) {- pWriter.WriteInt((Environment.TickCount64 - breakable.BaseTick).Truncate32());+ long currentTick = Environment.TickCount64;+ if (breakable.BaseTick > 0) {+ pWriter.WriteInt((currentTick - breakable.BaseTick).Truncate32());
pWriter.WriteInt(breakable.BaseTick.Truncate32());
} else {
pWriter.WriteInt();
pWriter.WriteInt();
}

Additionally, to guarantee behavior even inside checked contexts, consider making the extension use an unchecked cast:

publicstaticintTruncate32(thislongvalue)=>unchecked((int)value);

Based on learnings

Also applies to: 45-47

Maple2.Server.Game/Session/GameSession.cs (1)

813-839: Clamp MsRemaining to int range to avoid overflow

Current cast may overflow if remaining ms > int.MaxValue. Clamp before casting.

Apply this diff:

- .Where(buff => buff.EndTick - fieldTick > 0)+ .Where(buff => buff.EndTick - fieldTick > 0)
.Select(buff => new BuffInfo {
Id = buff.Id,
Level = buff.Level,
- MsRemaining = (int) (buff.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(buff.EndTick - fieldTick, int.MaxValue),
Stacks = buff.Stacks,
Enabled = buff.Enabled,
StopTime = stopTime,
}),
- .Where(cooldown => cooldown.EndTick - fieldTick > 0)+ .Where(cooldown => cooldown.EndTick - fieldTick > 0)
.Select(cooldown => new SkillCooldownInfo {
SkillId = cooldown.SkillId,
SkillLevel = cooldown.SkillLevel,
GroupId = cooldown.GroupId,
- MsRemaining = (int) (cooldown.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(cooldown.EndTick - fieldTick, int.MaxValue),
StopTime = stopTime,
Charges = cooldown.Charges,
}),

Optional: also clamp DeathInfo.MsRemaining to non-negative to avoid sending negative values when already expired.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c45ccca and 72b5e0f.

📒 Files selected for processing (14)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (1)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/FishingManager.cs (1)
Maple2.Server.Game/Packets/FishingPacket.cs (1)
  • FishingPacket (12-156)
Maple2.Server.Game/Session/GameSession.cs (2)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-62)
Maple2.Server.Game/Packets/BreakablePacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (11)
Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: Approve stack restoration in SetCacheBuffs Passing info.Stacks to AddBuff restores buff stacks correctly; BuffInfo.Stacks is initialized in PlayerConfigResponse.

Maple2.Model/Game/User/SkillCooldown.cs (1)

24-24: LGTM! Consistent use of Truncate32 for serialization.

The change from direct cast to Truncate32() makes the 32-bit truncation intent explicit and aligns with the refactoring pattern.

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: LGTM! Improved timing consistency.

The change from Environment.TickCount to Lobby.FieldTick centralizes timing through the field manager, ensuring consistent field-relative timing for dungeon room records.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM! Consistent packet serialization.

The change to Truncate32() makes the 32-bit truncation explicit for packet serialization, aligning with the refactoring pattern.

Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)

21-21: LGTM! Consistent packet serialization.

The change to Truncate32() for NextTick serialization aligns with the refactoring pattern and makes truncation intent explicit.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-323: LGTM! Consistent buff serialization.

The changes to use Truncate32() for both StartTick and EndTick align with the refactoring pattern and make the 32-bit truncation explicit for byte serialization.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM! Consistent use of FieldTickInt for portal timing.

The change to use FieldTickInt directly for quest portal timing is cleaner than casting FieldTick and aligns with the 32-bit tick representation pattern.


628-628: LGTM! Consistent portal timing.

Using FieldTickInt for the bonus map portal's EndTick aligns with the other portal timing changes and the 32-bit tick pattern.

Maple2.Server.Game/Manager/FishingManager.cs (1)

257-257: LGTM! Cleaner fishing timer calculation.

Using session.Field.FieldTickInt directly is cleaner than casting FieldTick and aligns with the refactoring to use the 32-bit tick property.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)

264-270: Good addition: 32‑bit tick accessor mirrors TickCount semantics

The Truncate32-based property is appropriate for client-facing 32-bit tick usage and avoids unsafe casts. Nice doc and placement.

Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1)

59-59: IField implementers updated FieldManager defines FieldTickInt; no other IField implementers exist.

Comment threadMaple2.Server.Tests/Tools/LongExtensionsTests.cs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)

1-2: Restore missing NUnit using and replace C# 12 collection expression

[Test], [TestCase], and Assert won’t resolve without using NUnit.Framework;, so the test project doesn’t compile. The long[] testValues = [...] literal also requires C# 12; the repo still targets earlier language versions, so that syntax fails to build. Please add the NUnit using and fall back to a classic array initializer so the tests compile again.

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;
- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };

Also applies to: 121-135

🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1)

4-4: Verify the import is intentional.

The added import appears unused in this file.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • Maple2.Server.Game/Manager/BuffManager.cs
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/DungeonManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
  • Maple2.Server.Game/Packets/BreakablePacket.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
🧰 Additional context used
🧬 Code graph analysis (5)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (2)
Maple2.Model/Game/User/SkillCooldown.cs (2)

3-3: LGTM: Import required for extension method.

The import is necessary for using the Truncate32() extension method and is correctly placed.


24-24: LGTM: Improved clarity with explicit truncation.

The change from (int) EndTick to EndTick.Truncate32() is functionally equivalent but significantly improves code clarity by making the truncation intent explicit. This aligns with the broader refactoring pattern applied across the codebase for tick handling.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (2)

1-3: Fix missing NUnit import to compile tests

Add NUnit using so [Test]/Assert resolve.

Apply:

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;

121-136: Replace C# 12 collection expression with classic array initializer

Ensures compatibility with older language versions.

Apply:

- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
- 0xFFFFFFFF,+ 0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };
🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/DungeonManager.cs (1)

352-352: Avoid potential overflow: cast after dividing

Divide on long first, then cast to int.

Apply:

- UserRecord.TotalSeconds = (int) (Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000;+ UserRecord.TotalSeconds = (int) ((Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
🚧 Files skipped from review as they are similar to previous changes (7)
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Model/Game/User/SkillCooldown.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
🧰 Additional context used
🧬 Code graph analysis (7)
Maple2.Server.Game/Packets/BreakablePacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (7)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM: Safe 32-bit truncation for quest portal ticks.

The changes correctly use Truncate32() for EndTick and FieldTickInt for StartTick. The explicit cast to long before adding milliseconds prevents double-precision arithmetic, and Truncate32() safely masks the lower 32 bits without sign extension issues.


628-628: LGTM: Consistent tick truncation pattern.

The EndTick calculation correctly applies the same safe truncation pattern used for quest portals, ensuring consistent tick handling across portal types.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-324: Consistent 32-bit tick serialization

Using Truncate32() here is correct and consistent with packet expectations.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM: Use Truncate32 for StartTick

Correctly avoids checked-cast overflow and preserves lower 32 bits.

Maple2.Server.Game/Packets/BreakablePacket.cs (1)

27-29: LGTM: Safe 32-bit truncation for tick diff and base tick

Truncate32() matches TickCount wrap semantics and avoids overflow on casts.

Also applies to: 45-47

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: EndTick assignment already uses FieldTick—time bases match

Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: LGTM! Good refactor and bug fix.

The changes improve code clarity and correctness:

  1. Parameter rename (buffscacheBuffs): Avoids shadowing the class-level buffs field, making the code easier to read and maintain.

  2. Stack preservation (line 513): Now passes info.Stacks to AddBuff, correctly preserving stack counts when loading cached buffs. Previously, stacks would default to 0, losing this information.

The validation logic and filtering (lines 507-512) appropriately handle invalid buffs and skip expired buffs that don't use in-game time.

@AngeloTadeucci
AngeloTadeucci merged commit c3067a2 into masterOct 15, 2025
4 of 5 checks passed
@AngeloTadeucci
AngeloTadeucci deleted the field-tick branch October 15, 2025 02:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AngeloTadeucci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Add LongExtensions.Truncate32 and refactor tick handling - #614

Merged
AngeloTadeucci merged 5 commits into
masterfrom
field-tick
Oct 15, 2025
Merged

Add LongExtensions.Truncate32 and refactor tick handling#614
AngeloTadeucci merged 5 commits into
masterfrom
field-tick

Conversation

@AngeloTadeucci

@AngeloTadeucciAngeloTadeucci commented Oct 13, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes

    • Expired buffs and skill cooldowns are no longer saved or restored.
    • Timing calculations for portals, fishing, instruments, breakables, and region skills made more consistent to reduce desync and overflow issues.
  • Refactor

    • Standardized conversion of 64-bit ticks to 32-bit client timers for improved timing reliability.
  • Tests

    • Added comprehensive tests validating 32-bit tick truncation behavior.

@coderabbitai

coderabbitaiBot commented Oct 13, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a 32-bit truncation helper (Truncate32) and applies it across tick serialization and packet writes, exposes a 32-bit FieldTickInt on IField/FieldManager, filters expired buffs/cooldowns when saving cache, and renames a BuffManager parameter.

Changes

Cohort / File(s)Summary
Tick truncation utility & tests
Maple2.Tools/Extensions/LongExtensions.cs, Maple2.Server.Tests/Tools/LongExtensionsTests.cs
Add Truncate32(this long) extension to truncate 64-bit ticks to 32-bit ints; add comprehensive unit tests covering boundaries, wraparound, and TickCount-like behavior.
Field tick API & usage
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs, Maple2.Server.Game/Manager/Field/FieldManager/IField.cs, Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs, Maple2.Server.Game/Manager/DungeonManager.cs, Maple2.Server.Game/Manager/FishingManager.cs, Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
Introduce FieldTickInt (derived via Truncate32) on FieldManager/IField; replace direct 64→32 casts with .Truncate32() or use FieldTickInt where 32-bit ticks are required; update tick initializations (e.g., use Lobby.FieldTick).
Serialization & packets
Maple2.Model/Game/User/SkillCooldown.cs, Maple2.Server.Game/Model/Field/Buff.cs, Maple2.Server.Game/Packets/BreakablePacket.cs, Maple2.Server.Game/Packets/InstrumentPacket.cs, Maple2.Server.Game/Packets/RegionSkillPacket.cs
Replace direct (int) casts of tick values with .Truncate32() when writing to buffers/packets; add using Maple2.Tools.Extensions.
Cache save filtering
Maple2.Server.Game/Session/GameSession.cs
Filter out expired buffs and skill cooldowns (Where(EndTick - fieldTick > 0)) before projecting and saving cache entries; compute MsRemaining via .Truncate32().
BuffManager signature change
Maple2.Server.Game/Manager/BuffManager.cs
Rename public method parameter from buffscacheBuffs in SetCacheBuffs(IList<BuffInfo> cacheBuffs, long currentTick) and update internal iteration/usage.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Player
participant GameSession
participant Field as FieldManager
participant BuffManager
participant Persistence as PlayerConfigStorage
Player->>GameSession: Request SaveCacheConfig
GameSession->>Field: Read FieldTick (64-bit)
Field-->>GameSession: FieldTickInt (FieldTick.Truncate32())
GameSession->>GameSession: Filter Buffs/Cooldowns (EndTick - FieldTick > 0)
GameSession->>Persistence: Save filtered BuffInfo & SkillCooldownInfo (MsRemaining via Truncate32)
Persistence-->>GameSession: Ack
GameSession-->>Player: Done
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Zintixx

Poem

I hop through ticks from long to small,
Snip 64-bits till they answer the call.
Packets line up, portals chime,
Buffs saved neat and right on time.
A rabbit trims each ticking line — 🐇⌛

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title Check✅ PassedThe title succinctly captures the core changes introduced in this pull request by mentioning both the addition of the Truncate32 extension method and the overarching refactoring of tick handling throughout the codebase. It is concise, specific, and directly reflects the main developer intent without extraneous detail.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch field-tick

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between deed140 and d5aff14.

📒 Files selected for processing (1)
  • Maple2.Server.Game/Session/GameSession.cs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Maple2.Server.Game/Session/GameSession.cs (3)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-44)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (3)
Maple2.Server.Game/Session/GameSession.cs (3)

30-30: LGTM!

The import enables the use of Truncate32() for standardized 32-bit tick conversions throughout this file.


818-827: Good filtering of expired buffs.

The filtering logic correctly excludes buffs where EndTick - fieldTick <= 0, ensuring only active buffs are cached. The use of Truncate32() for the remaining duration calculation aligns with the broader refactoring effort.


830-839: Good filtering of expired cooldowns.

The filtering and projection logic mirrors the buff handling above, maintaining consistency across cache persistence.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
Maple2.Tools/Extensions/LongExtensions.cs (1)

10-12: LGTM! Clean truncation logic.

The implementation correctly truncates 64-bit values to 32-bit by masking the lower 32 bits and casting to int, which properly handles wraparound (values > int.MaxValue become negative, matching Environment.TickCount behavior).

Optional performance optimization:

Consider marking this method with [MethodImpl(MethodImplOptions.AggressiveInlining)] to ensure it's inlined at call sites, as it's a simple operation called frequently in serialization paths:

+using System.Runtime.CompilerServices;+
namespace Maple2.Tools.Extensions;
public static class LongExtensions {
/// <summary>
/// Truncates a long value to a 32-bit int, handling overflow properly.
/// This is useful for converting Environment.TickCount64 to match Environment.TickCount behavior.
/// </summary>
/// <param name="value">The long value to truncate</param>
/// <returns>The truncated int value</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Truncate32(this long value) {
return (int) (0xFFFFFFFF & value);
}
}
Maple2.Server.Game/Packets/BreakablePacket.cs (1)

26-29: Correct 32‑bit tick truncation; minor consistency refactor

Using Truncate32() here is correct and safer than direct casts. For consistency and tiny perf, also cache Environment.TickCount64 in the single‑update overload.

Apply this diff to the single-update method:

- public static ByteWriter Update(FieldBreakable breakable) {+ public static ByteWriter Update(FieldBreakable breakable) {
var pWriter = Packet.Of(SendOp.Breakable);
pWriter.Write<Command>(Command.Update);
pWriter.WriteString(breakable.EntityId);
pWriter.Write<BreakableState>(breakable.State);
pWriter.WriteBool(breakable.Visible);
- if (breakable.BaseTick > 0) {- pWriter.WriteInt((Environment.TickCount64 - breakable.BaseTick).Truncate32());+ long currentTick = Environment.TickCount64;+ if (breakable.BaseTick > 0) {+ pWriter.WriteInt((currentTick - breakable.BaseTick).Truncate32());
pWriter.WriteInt(breakable.BaseTick.Truncate32());
} else {
pWriter.WriteInt();
pWriter.WriteInt();
}

Additionally, to guarantee behavior even inside checked contexts, consider making the extension use an unchecked cast:

publicstaticintTruncate32(thislongvalue)=>unchecked((int)value);

Based on learnings

Also applies to: 45-47

Maple2.Server.Game/Session/GameSession.cs (1)

813-839: Clamp MsRemaining to int range to avoid overflow

Current cast may overflow if remaining ms > int.MaxValue. Clamp before casting.

Apply this diff:

- .Where(buff => buff.EndTick - fieldTick > 0)+ .Where(buff => buff.EndTick - fieldTick > 0)
.Select(buff => new BuffInfo {
Id = buff.Id,
Level = buff.Level,
- MsRemaining = (int) (buff.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(buff.EndTick - fieldTick, int.MaxValue),
Stacks = buff.Stacks,
Enabled = buff.Enabled,
StopTime = stopTime,
}),
- .Where(cooldown => cooldown.EndTick - fieldTick > 0)+ .Where(cooldown => cooldown.EndTick - fieldTick > 0)
.Select(cooldown => new SkillCooldownInfo {
SkillId = cooldown.SkillId,
SkillLevel = cooldown.SkillLevel,
GroupId = cooldown.GroupId,
- MsRemaining = (int) (cooldown.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(cooldown.EndTick - fieldTick, int.MaxValue),
StopTime = stopTime,
Charges = cooldown.Charges,
}),

Optional: also clamp DeathInfo.MsRemaining to non-negative to avoid sending negative values when already expired.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c45ccca and 72b5e0f.

📒 Files selected for processing (14)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (1)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/FishingManager.cs (1)
Maple2.Server.Game/Packets/FishingPacket.cs (1)
  • FishingPacket (12-156)
Maple2.Server.Game/Session/GameSession.cs (2)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-62)
Maple2.Server.Game/Packets/BreakablePacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (11)
Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: Approve stack restoration in SetCacheBuffs Passing info.Stacks to AddBuff restores buff stacks correctly; BuffInfo.Stacks is initialized in PlayerConfigResponse.

Maple2.Model/Game/User/SkillCooldown.cs (1)

24-24: LGTM! Consistent use of Truncate32 for serialization.

The change from direct cast to Truncate32() makes the 32-bit truncation intent explicit and aligns with the refactoring pattern.

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: LGTM! Improved timing consistency.

The change from Environment.TickCount to Lobby.FieldTick centralizes timing through the field manager, ensuring consistent field-relative timing for dungeon room records.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM! Consistent packet serialization.

The change to Truncate32() makes the 32-bit truncation explicit for packet serialization, aligning with the refactoring pattern.

Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)

21-21: LGTM! Consistent packet serialization.

The change to Truncate32() for NextTick serialization aligns with the refactoring pattern and makes truncation intent explicit.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-323: LGTM! Consistent buff serialization.

The changes to use Truncate32() for both StartTick and EndTick align with the refactoring pattern and make the 32-bit truncation explicit for byte serialization.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM! Consistent use of FieldTickInt for portal timing.

The change to use FieldTickInt directly for quest portal timing is cleaner than casting FieldTick and aligns with the 32-bit tick representation pattern.


628-628: LGTM! Consistent portal timing.

Using FieldTickInt for the bonus map portal's EndTick aligns with the other portal timing changes and the 32-bit tick pattern.

Maple2.Server.Game/Manager/FishingManager.cs (1)

257-257: LGTM! Cleaner fishing timer calculation.

Using session.Field.FieldTickInt directly is cleaner than casting FieldTick and aligns with the refactoring to use the 32-bit tick property.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)

264-270: Good addition: 32‑bit tick accessor mirrors TickCount semantics

The Truncate32-based property is appropriate for client-facing 32-bit tick usage and avoids unsafe casts. Nice doc and placement.

Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1)

59-59: IField implementers updated FieldManager defines FieldTickInt; no other IField implementers exist.

Comment threadMaple2.Server.Tests/Tools/LongExtensionsTests.cs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)

1-2: Restore missing NUnit using and replace C# 12 collection expression

[Test], [TestCase], and Assert won’t resolve without using NUnit.Framework;, so the test project doesn’t compile. The long[] testValues = [...] literal also requires C# 12; the repo still targets earlier language versions, so that syntax fails to build. Please add the NUnit using and fall back to a classic array initializer so the tests compile again.

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;
- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };

Also applies to: 121-135

🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1)

4-4: Verify the import is intentional.

The added import appears unused in this file.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • Maple2.Server.Game/Manager/BuffManager.cs
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/DungeonManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
  • Maple2.Server.Game/Packets/BreakablePacket.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
🧰 Additional context used
🧬 Code graph analysis (5)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (2)
Maple2.Model/Game/User/SkillCooldown.cs (2)

3-3: LGTM: Import required for extension method.

The import is necessary for using the Truncate32() extension method and is correctly placed.


24-24: LGTM: Improved clarity with explicit truncation.

The change from (int) EndTick to EndTick.Truncate32() is functionally equivalent but significantly improves code clarity by making the truncation intent explicit. This aligns with the broader refactoring pattern applied across the codebase for tick handling.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (2)

1-3: Fix missing NUnit import to compile tests

Add NUnit using so [Test]/Assert resolve.

Apply:

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;

121-136: Replace C# 12 collection expression with classic array initializer

Ensures compatibility with older language versions.

Apply:

- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
- 0xFFFFFFFF,+ 0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };
🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/DungeonManager.cs (1)

352-352: Avoid potential overflow: cast after dividing

Divide on long first, then cast to int.

Apply:

- UserRecord.TotalSeconds = (int) (Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000;+ UserRecord.TotalSeconds = (int) ((Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
🚧 Files skipped from review as they are similar to previous changes (7)
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Model/Game/User/SkillCooldown.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
🧰 Additional context used
🧬 Code graph analysis (7)
Maple2.Server.Game/Packets/BreakablePacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (7)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM: Safe 32-bit truncation for quest portal ticks.

The changes correctly use Truncate32() for EndTick and FieldTickInt for StartTick. The explicit cast to long before adding milliseconds prevents double-precision arithmetic, and Truncate32() safely masks the lower 32 bits without sign extension issues.


628-628: LGTM: Consistent tick truncation pattern.

The EndTick calculation correctly applies the same safe truncation pattern used for quest portals, ensuring consistent tick handling across portal types.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-324: Consistent 32-bit tick serialization

Using Truncate32() here is correct and consistent with packet expectations.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM: Use Truncate32 for StartTick

Correctly avoids checked-cast overflow and preserves lower 32 bits.

Maple2.Server.Game/Packets/BreakablePacket.cs (1)

27-29: LGTM: Safe 32-bit truncation for tick diff and base tick

Truncate32() matches TickCount wrap semantics and avoids overflow on casts.

Also applies to: 45-47

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: EndTick assignment already uses FieldTick—time bases match

Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: LGTM! Good refactor and bug fix.

The changes improve code clarity and correctness:

  1. Parameter rename (buffscacheBuffs): Avoids shadowing the class-level buffs field, making the code easier to read and maintain.

  2. Stack preservation (line 513): Now passes info.Stacks to AddBuff, correctly preserving stack counts when loading cached buffs. Previously, stacks would default to 0, losing this information.

The validation logic and filtering (lines 507-512) appropriately handle invalid buffs and skip expired buffs that don't use in-game time.

@AngeloTadeucci
AngeloTadeucci merged commit c3067a2 into masterOct 15, 2025
4 of 5 checks passed
@AngeloTadeucci
AngeloTadeucci deleted the field-tick branch October 15, 2025 02:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AngeloTadeucci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add LongExtensions.Truncate32 and refactor tick handling - #614

Merged
AngeloTadeucci merged 5 commits into
masterfrom
field-tick
Oct 15, 2025
Merged

Add LongExtensions.Truncate32 and refactor tick handling#614
AngeloTadeucci merged 5 commits into
masterfrom
field-tick

Conversation

@AngeloTadeucci

@AngeloTadeucciAngeloTadeucci commented Oct 13, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes

    • Expired buffs and skill cooldowns are no longer saved or restored.
    • Timing calculations for portals, fishing, instruments, breakables, and region skills made more consistent to reduce desync and overflow issues.
  • Refactor

    • Standardized conversion of 64-bit ticks to 32-bit client timers for improved timing reliability.
  • Tests

    • Added comprehensive tests validating 32-bit tick truncation behavior.

@coderabbitai

coderabbitaiBot commented Oct 13, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a 32-bit truncation helper (Truncate32) and applies it across tick serialization and packet writes, exposes a 32-bit FieldTickInt on IField/FieldManager, filters expired buffs/cooldowns when saving cache, and renames a BuffManager parameter.

Changes

Cohort / File(s)Summary
Tick truncation utility & tests
Maple2.Tools/Extensions/LongExtensions.cs, Maple2.Server.Tests/Tools/LongExtensionsTests.cs
Add Truncate32(this long) extension to truncate 64-bit ticks to 32-bit ints; add comprehensive unit tests covering boundaries, wraparound, and TickCount-like behavior.
Field tick API & usage
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs, Maple2.Server.Game/Manager/Field/FieldManager/IField.cs, Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs, Maple2.Server.Game/Manager/DungeonManager.cs, Maple2.Server.Game/Manager/FishingManager.cs, Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
Introduce FieldTickInt (derived via Truncate32) on FieldManager/IField; replace direct 64→32 casts with .Truncate32() or use FieldTickInt where 32-bit ticks are required; update tick initializations (e.g., use Lobby.FieldTick).
Serialization & packets
Maple2.Model/Game/User/SkillCooldown.cs, Maple2.Server.Game/Model/Field/Buff.cs, Maple2.Server.Game/Packets/BreakablePacket.cs, Maple2.Server.Game/Packets/InstrumentPacket.cs, Maple2.Server.Game/Packets/RegionSkillPacket.cs
Replace direct (int) casts of tick values with .Truncate32() when writing to buffers/packets; add using Maple2.Tools.Extensions.
Cache save filtering
Maple2.Server.Game/Session/GameSession.cs
Filter out expired buffs and skill cooldowns (Where(EndTick - fieldTick > 0)) before projecting and saving cache entries; compute MsRemaining via .Truncate32().
BuffManager signature change
Maple2.Server.Game/Manager/BuffManager.cs
Rename public method parameter from buffscacheBuffs in SetCacheBuffs(IList<BuffInfo> cacheBuffs, long currentTick) and update internal iteration/usage.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Player
participant GameSession
participant Field as FieldManager
participant BuffManager
participant Persistence as PlayerConfigStorage
Player->>GameSession: Request SaveCacheConfig
GameSession->>Field: Read FieldTick (64-bit)
Field-->>GameSession: FieldTickInt (FieldTick.Truncate32())
GameSession->>GameSession: Filter Buffs/Cooldowns (EndTick - FieldTick > 0)
GameSession->>Persistence: Save filtered BuffInfo & SkillCooldownInfo (MsRemaining via Truncate32)
Persistence-->>GameSession: Ack
GameSession-->>Player: Done
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Zintixx

Poem

I hop through ticks from long to small,
Snip 64-bits till they answer the call.
Packets line up, portals chime,
Buffs saved neat and right on time.
A rabbit trims each ticking line — 🐇⌛

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title Check✅ PassedThe title succinctly captures the core changes introduced in this pull request by mentioning both the addition of the Truncate32 extension method and the overarching refactoring of tick handling throughout the codebase. It is concise, specific, and directly reflects the main developer intent without extraneous detail.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch field-tick

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between deed140 and d5aff14.

📒 Files selected for processing (1)
  • Maple2.Server.Game/Session/GameSession.cs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Maple2.Server.Game/Session/GameSession.cs (3)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-44)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (3)
Maple2.Server.Game/Session/GameSession.cs (3)

30-30: LGTM!

The import enables the use of Truncate32() for standardized 32-bit tick conversions throughout this file.


818-827: Good filtering of expired buffs.

The filtering logic correctly excludes buffs where EndTick - fieldTick <= 0, ensuring only active buffs are cached. The use of Truncate32() for the remaining duration calculation aligns with the broader refactoring effort.


830-839: Good filtering of expired cooldowns.

The filtering and projection logic mirrors the buff handling above, maintaining consistency across cache persistence.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
Maple2.Tools/Extensions/LongExtensions.cs (1)

10-12: LGTM! Clean truncation logic.

The implementation correctly truncates 64-bit values to 32-bit by masking the lower 32 bits and casting to int, which properly handles wraparound (values > int.MaxValue become negative, matching Environment.TickCount behavior).

Optional performance optimization:

Consider marking this method with [MethodImpl(MethodImplOptions.AggressiveInlining)] to ensure it's inlined at call sites, as it's a simple operation called frequently in serialization paths:

+using System.Runtime.CompilerServices;+
namespace Maple2.Tools.Extensions;
public static class LongExtensions {
/// <summary>
/// Truncates a long value to a 32-bit int, handling overflow properly.
/// This is useful for converting Environment.TickCount64 to match Environment.TickCount behavior.
/// </summary>
/// <param name="value">The long value to truncate</param>
/// <returns>The truncated int value</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Truncate32(this long value) {
return (int) (0xFFFFFFFF & value);
}
}
Maple2.Server.Game/Packets/BreakablePacket.cs (1)

26-29: Correct 32‑bit tick truncation; minor consistency refactor

Using Truncate32() here is correct and safer than direct casts. For consistency and tiny perf, also cache Environment.TickCount64 in the single‑update overload.

Apply this diff to the single-update method:

- public static ByteWriter Update(FieldBreakable breakable) {+ public static ByteWriter Update(FieldBreakable breakable) {
var pWriter = Packet.Of(SendOp.Breakable);
pWriter.Write<Command>(Command.Update);
pWriter.WriteString(breakable.EntityId);
pWriter.Write<BreakableState>(breakable.State);
pWriter.WriteBool(breakable.Visible);
- if (breakable.BaseTick > 0) {- pWriter.WriteInt((Environment.TickCount64 - breakable.BaseTick).Truncate32());+ long currentTick = Environment.TickCount64;+ if (breakable.BaseTick > 0) {+ pWriter.WriteInt((currentTick - breakable.BaseTick).Truncate32());
pWriter.WriteInt(breakable.BaseTick.Truncate32());
} else {
pWriter.WriteInt();
pWriter.WriteInt();
}

Additionally, to guarantee behavior even inside checked contexts, consider making the extension use an unchecked cast:

publicstaticintTruncate32(thislongvalue)=>unchecked((int)value);

Based on learnings

Also applies to: 45-47

Maple2.Server.Game/Session/GameSession.cs (1)

813-839: Clamp MsRemaining to int range to avoid overflow

Current cast may overflow if remaining ms > int.MaxValue. Clamp before casting.

Apply this diff:

- .Where(buff => buff.EndTick - fieldTick > 0)+ .Where(buff => buff.EndTick - fieldTick > 0)
.Select(buff => new BuffInfo {
Id = buff.Id,
Level = buff.Level,
- MsRemaining = (int) (buff.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(buff.EndTick - fieldTick, int.MaxValue),
Stacks = buff.Stacks,
Enabled = buff.Enabled,
StopTime = stopTime,
}),
- .Where(cooldown => cooldown.EndTick - fieldTick > 0)+ .Where(cooldown => cooldown.EndTick - fieldTick > 0)
.Select(cooldown => new SkillCooldownInfo {
SkillId = cooldown.SkillId,
SkillLevel = cooldown.SkillLevel,
GroupId = cooldown.GroupId,
- MsRemaining = (int) (cooldown.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(cooldown.EndTick - fieldTick, int.MaxValue),
StopTime = stopTime,
Charges = cooldown.Charges,
}),

Optional: also clamp DeathInfo.MsRemaining to non-negative to avoid sending negative values when already expired.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c45ccca and 72b5e0f.

📒 Files selected for processing (14)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (1)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/FishingManager.cs (1)
Maple2.Server.Game/Packets/FishingPacket.cs (1)
  • FishingPacket (12-156)
Maple2.Server.Game/Session/GameSession.cs (2)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-62)
Maple2.Server.Game/Packets/BreakablePacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (11)
Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: Approve stack restoration in SetCacheBuffs Passing info.Stacks to AddBuff restores buff stacks correctly; BuffInfo.Stacks is initialized in PlayerConfigResponse.

Maple2.Model/Game/User/SkillCooldown.cs (1)

24-24: LGTM! Consistent use of Truncate32 for serialization.

The change from direct cast to Truncate32() makes the 32-bit truncation intent explicit and aligns with the refactoring pattern.

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: LGTM! Improved timing consistency.

The change from Environment.TickCount to Lobby.FieldTick centralizes timing through the field manager, ensuring consistent field-relative timing for dungeon room records.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM! Consistent packet serialization.

The change to Truncate32() makes the 32-bit truncation explicit for packet serialization, aligning with the refactoring pattern.

Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)

21-21: LGTM! Consistent packet serialization.

The change to Truncate32() for NextTick serialization aligns with the refactoring pattern and makes truncation intent explicit.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-323: LGTM! Consistent buff serialization.

The changes to use Truncate32() for both StartTick and EndTick align with the refactoring pattern and make the 32-bit truncation explicit for byte serialization.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM! Consistent use of FieldTickInt for portal timing.

The change to use FieldTickInt directly for quest portal timing is cleaner than casting FieldTick and aligns with the 32-bit tick representation pattern.


628-628: LGTM! Consistent portal timing.

Using FieldTickInt for the bonus map portal's EndTick aligns with the other portal timing changes and the 32-bit tick pattern.

Maple2.Server.Game/Manager/FishingManager.cs (1)

257-257: LGTM! Cleaner fishing timer calculation.

Using session.Field.FieldTickInt directly is cleaner than casting FieldTick and aligns with the refactoring to use the 32-bit tick property.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)

264-270: Good addition: 32‑bit tick accessor mirrors TickCount semantics

The Truncate32-based property is appropriate for client-facing 32-bit tick usage and avoids unsafe casts. Nice doc and placement.

Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1)

59-59: IField implementers updated FieldManager defines FieldTickInt; no other IField implementers exist.

Comment threadMaple2.Server.Tests/Tools/LongExtensionsTests.cs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)

1-2: Restore missing NUnit using and replace C# 12 collection expression

[Test], [TestCase], and Assert won’t resolve without using NUnit.Framework;, so the test project doesn’t compile. The long[] testValues = [...] literal also requires C# 12; the repo still targets earlier language versions, so that syntax fails to build. Please add the NUnit using and fall back to a classic array initializer so the tests compile again.

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;
- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };

Also applies to: 121-135

🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1)

4-4: Verify the import is intentional.

The added import appears unused in this file.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • Maple2.Server.Game/Manager/BuffManager.cs
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/DungeonManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
  • Maple2.Server.Game/Packets/BreakablePacket.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
🧰 Additional context used
🧬 Code graph analysis (5)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (2)
Maple2.Model/Game/User/SkillCooldown.cs (2)

3-3: LGTM: Import required for extension method.

The import is necessary for using the Truncate32() extension method and is correctly placed.


24-24: LGTM: Improved clarity with explicit truncation.

The change from (int) EndTick to EndTick.Truncate32() is functionally equivalent but significantly improves code clarity by making the truncation intent explicit. This aligns with the broader refactoring pattern applied across the codebase for tick handling.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (2)

1-3: Fix missing NUnit import to compile tests

Add NUnit using so [Test]/Assert resolve.

Apply:

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;

121-136: Replace C# 12 collection expression with classic array initializer

Ensures compatibility with older language versions.

Apply:

- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
- 0xFFFFFFFF,+ 0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };
🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/DungeonManager.cs (1)

352-352: Avoid potential overflow: cast after dividing

Divide on long first, then cast to int.

Apply:

- UserRecord.TotalSeconds = (int) (Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000;+ UserRecord.TotalSeconds = (int) ((Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
🚧 Files skipped from review as they are similar to previous changes (7)
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Model/Game/User/SkillCooldown.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
🧰 Additional context used
🧬 Code graph analysis (7)
Maple2.Server.Game/Packets/BreakablePacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (7)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM: Safe 32-bit truncation for quest portal ticks.

The changes correctly use Truncate32() for EndTick and FieldTickInt for StartTick. The explicit cast to long before adding milliseconds prevents double-precision arithmetic, and Truncate32() safely masks the lower 32 bits without sign extension issues.


628-628: LGTM: Consistent tick truncation pattern.

The EndTick calculation correctly applies the same safe truncation pattern used for quest portals, ensuring consistent tick handling across portal types.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-324: Consistent 32-bit tick serialization

Using Truncate32() here is correct and consistent with packet expectations.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM: Use Truncate32 for StartTick

Correctly avoids checked-cast overflow and preserves lower 32 bits.

Maple2.Server.Game/Packets/BreakablePacket.cs (1)

27-29: LGTM: Safe 32-bit truncation for tick diff and base tick

Truncate32() matches TickCount wrap semantics and avoids overflow on casts.

Also applies to: 45-47

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: EndTick assignment already uses FieldTick—time bases match

Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: LGTM! Good refactor and bug fix.

The changes improve code clarity and correctness:

  1. Parameter rename (buffscacheBuffs): Avoids shadowing the class-level buffs field, making the code easier to read and maintain.

  2. Stack preservation (line 513): Now passes info.Stacks to AddBuff, correctly preserving stack counts when loading cached buffs. Previously, stacks would default to 0, losing this information.

The validation logic and filtering (lines 507-512) appropriately handle invalid buffs and skip expired buffs that don't use in-game time.

@AngeloTadeucci
AngeloTadeucci merged commit c3067a2 into masterOct 15, 2025
4 of 5 checks passed
@AngeloTadeucci
AngeloTadeucci deleted the field-tick branch October 15, 2025 02:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AngeloTadeucci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Add LongExtensions.Truncate32 and refactor tick handling - #614

Merged
AngeloTadeucci merged 5 commits into
masterfrom
field-tick
Oct 15, 2025
Merged

Add LongExtensions.Truncate32 and refactor tick handling#614
AngeloTadeucci merged 5 commits into
masterfrom
field-tick

Conversation

@AngeloTadeucci

@AngeloTadeucciAngeloTadeucci commented Oct 13, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes

    • Expired buffs and skill cooldowns are no longer saved or restored.
    • Timing calculations for portals, fishing, instruments, breakables, and region skills made more consistent to reduce desync and overflow issues.
  • Refactor

    • Standardized conversion of 64-bit ticks to 32-bit client timers for improved timing reliability.
  • Tests

    • Added comprehensive tests validating 32-bit tick truncation behavior.

@coderabbitai

coderabbitaiBot commented Oct 13, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a 32-bit truncation helper (Truncate32) and applies it across tick serialization and packet writes, exposes a 32-bit FieldTickInt on IField/FieldManager, filters expired buffs/cooldowns when saving cache, and renames a BuffManager parameter.

Changes

Cohort / File(s)Summary
Tick truncation utility & tests
Maple2.Tools/Extensions/LongExtensions.cs, Maple2.Server.Tests/Tools/LongExtensionsTests.cs
Add Truncate32(this long) extension to truncate 64-bit ticks to 32-bit ints; add comprehensive unit tests covering boundaries, wraparound, and TickCount-like behavior.
Field tick API & usage
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs, Maple2.Server.Game/Manager/Field/FieldManager/IField.cs, Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs, Maple2.Server.Game/Manager/DungeonManager.cs, Maple2.Server.Game/Manager/FishingManager.cs, Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
Introduce FieldTickInt (derived via Truncate32) on FieldManager/IField; replace direct 64→32 casts with .Truncate32() or use FieldTickInt where 32-bit ticks are required; update tick initializations (e.g., use Lobby.FieldTick).
Serialization & packets
Maple2.Model/Game/User/SkillCooldown.cs, Maple2.Server.Game/Model/Field/Buff.cs, Maple2.Server.Game/Packets/BreakablePacket.cs, Maple2.Server.Game/Packets/InstrumentPacket.cs, Maple2.Server.Game/Packets/RegionSkillPacket.cs
Replace direct (int) casts of tick values with .Truncate32() when writing to buffers/packets; add using Maple2.Tools.Extensions.
Cache save filtering
Maple2.Server.Game/Session/GameSession.cs
Filter out expired buffs and skill cooldowns (Where(EndTick - fieldTick > 0)) before projecting and saving cache entries; compute MsRemaining via .Truncate32().
BuffManager signature change
Maple2.Server.Game/Manager/BuffManager.cs
Rename public method parameter from buffscacheBuffs in SetCacheBuffs(IList<BuffInfo> cacheBuffs, long currentTick) and update internal iteration/usage.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Player
participant GameSession
participant Field as FieldManager
participant BuffManager
participant Persistence as PlayerConfigStorage
Player->>GameSession: Request SaveCacheConfig
GameSession->>Field: Read FieldTick (64-bit)
Field-->>GameSession: FieldTickInt (FieldTick.Truncate32())
GameSession->>GameSession: Filter Buffs/Cooldowns (EndTick - FieldTick > 0)
GameSession->>Persistence: Save filtered BuffInfo & SkillCooldownInfo (MsRemaining via Truncate32)
Persistence-->>GameSession: Ack
GameSession-->>Player: Done
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Zintixx

Poem

I hop through ticks from long to small,
Snip 64-bits till they answer the call.
Packets line up, portals chime,
Buffs saved neat and right on time.
A rabbit trims each ticking line — 🐇⌛

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title Check✅ PassedThe title succinctly captures the core changes introduced in this pull request by mentioning both the addition of the Truncate32 extension method and the overarching refactoring of tick handling throughout the codebase. It is concise, specific, and directly reflects the main developer intent without extraneous detail.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch field-tick

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between deed140 and d5aff14.

📒 Files selected for processing (1)
  • Maple2.Server.Game/Session/GameSession.cs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Maple2.Server.Game/Session/GameSession.cs (3)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-44)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (3)
Maple2.Server.Game/Session/GameSession.cs (3)

30-30: LGTM!

The import enables the use of Truncate32() for standardized 32-bit tick conversions throughout this file.


818-827: Good filtering of expired buffs.

The filtering logic correctly excludes buffs where EndTick - fieldTick <= 0, ensuring only active buffs are cached. The use of Truncate32() for the remaining duration calculation aligns with the broader refactoring effort.


830-839: Good filtering of expired cooldowns.

The filtering and projection logic mirrors the buff handling above, maintaining consistency across cache persistence.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
Maple2.Tools/Extensions/LongExtensions.cs (1)

10-12: LGTM! Clean truncation logic.

The implementation correctly truncates 64-bit values to 32-bit by masking the lower 32 bits and casting to int, which properly handles wraparound (values > int.MaxValue become negative, matching Environment.TickCount behavior).

Optional performance optimization:

Consider marking this method with [MethodImpl(MethodImplOptions.AggressiveInlining)] to ensure it's inlined at call sites, as it's a simple operation called frequently in serialization paths:

+using System.Runtime.CompilerServices;+
namespace Maple2.Tools.Extensions;
public static class LongExtensions {
/// <summary>
/// Truncates a long value to a 32-bit int, handling overflow properly.
/// This is useful for converting Environment.TickCount64 to match Environment.TickCount behavior.
/// </summary>
/// <param name="value">The long value to truncate</param>
/// <returns>The truncated int value</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Truncate32(this long value) {
return (int) (0xFFFFFFFF & value);
}
}
Maple2.Server.Game/Packets/BreakablePacket.cs (1)

26-29: Correct 32‑bit tick truncation; minor consistency refactor

Using Truncate32() here is correct and safer than direct casts. For consistency and tiny perf, also cache Environment.TickCount64 in the single‑update overload.

Apply this diff to the single-update method:

- public static ByteWriter Update(FieldBreakable breakable) {+ public static ByteWriter Update(FieldBreakable breakable) {
var pWriter = Packet.Of(SendOp.Breakable);
pWriter.Write<Command>(Command.Update);
pWriter.WriteString(breakable.EntityId);
pWriter.Write<BreakableState>(breakable.State);
pWriter.WriteBool(breakable.Visible);
- if (breakable.BaseTick > 0) {- pWriter.WriteInt((Environment.TickCount64 - breakable.BaseTick).Truncate32());+ long currentTick = Environment.TickCount64;+ if (breakable.BaseTick > 0) {+ pWriter.WriteInt((currentTick - breakable.BaseTick).Truncate32());
pWriter.WriteInt(breakable.BaseTick.Truncate32());
} else {
pWriter.WriteInt();
pWriter.WriteInt();
}

Additionally, to guarantee behavior even inside checked contexts, consider making the extension use an unchecked cast:

publicstaticintTruncate32(thislongvalue)=>unchecked((int)value);

Based on learnings

Also applies to: 45-47

Maple2.Server.Game/Session/GameSession.cs (1)

813-839: Clamp MsRemaining to int range to avoid overflow

Current cast may overflow if remaining ms > int.MaxValue. Clamp before casting.

Apply this diff:

- .Where(buff => buff.EndTick - fieldTick > 0)+ .Where(buff => buff.EndTick - fieldTick > 0)
.Select(buff => new BuffInfo {
Id = buff.Id,
Level = buff.Level,
- MsRemaining = (int) (buff.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(buff.EndTick - fieldTick, int.MaxValue),
Stacks = buff.Stacks,
Enabled = buff.Enabled,
StopTime = stopTime,
}),
- .Where(cooldown => cooldown.EndTick - fieldTick > 0)+ .Where(cooldown => cooldown.EndTick - fieldTick > 0)
.Select(cooldown => new SkillCooldownInfo {
SkillId = cooldown.SkillId,
SkillLevel = cooldown.SkillLevel,
GroupId = cooldown.GroupId,
- MsRemaining = (int) (cooldown.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(cooldown.EndTick - fieldTick, int.MaxValue),
StopTime = stopTime,
Charges = cooldown.Charges,
}),

Optional: also clamp DeathInfo.MsRemaining to non-negative to avoid sending negative values when already expired.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c45ccca and 72b5e0f.

📒 Files selected for processing (14)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (1)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/FishingManager.cs (1)
Maple2.Server.Game/Packets/FishingPacket.cs (1)
  • FishingPacket (12-156)
Maple2.Server.Game/Session/GameSession.cs (2)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-62)
Maple2.Server.Game/Packets/BreakablePacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (11)
Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: Approve stack restoration in SetCacheBuffs Passing info.Stacks to AddBuff restores buff stacks correctly; BuffInfo.Stacks is initialized in PlayerConfigResponse.

Maple2.Model/Game/User/SkillCooldown.cs (1)

24-24: LGTM! Consistent use of Truncate32 for serialization.

The change from direct cast to Truncate32() makes the 32-bit truncation intent explicit and aligns with the refactoring pattern.

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: LGTM! Improved timing consistency.

The change from Environment.TickCount to Lobby.FieldTick centralizes timing through the field manager, ensuring consistent field-relative timing for dungeon room records.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM! Consistent packet serialization.

The change to Truncate32() makes the 32-bit truncation explicit for packet serialization, aligning with the refactoring pattern.

Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)

21-21: LGTM! Consistent packet serialization.

The change to Truncate32() for NextTick serialization aligns with the refactoring pattern and makes truncation intent explicit.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-323: LGTM! Consistent buff serialization.

The changes to use Truncate32() for both StartTick and EndTick align with the refactoring pattern and make the 32-bit truncation explicit for byte serialization.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM! Consistent use of FieldTickInt for portal timing.

The change to use FieldTickInt directly for quest portal timing is cleaner than casting FieldTick and aligns with the 32-bit tick representation pattern.


628-628: LGTM! Consistent portal timing.

Using FieldTickInt for the bonus map portal's EndTick aligns with the other portal timing changes and the 32-bit tick pattern.

Maple2.Server.Game/Manager/FishingManager.cs (1)

257-257: LGTM! Cleaner fishing timer calculation.

Using session.Field.FieldTickInt directly is cleaner than casting FieldTick and aligns with the refactoring to use the 32-bit tick property.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)

264-270: Good addition: 32‑bit tick accessor mirrors TickCount semantics

The Truncate32-based property is appropriate for client-facing 32-bit tick usage and avoids unsafe casts. Nice doc and placement.

Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1)

59-59: IField implementers updated FieldManager defines FieldTickInt; no other IField implementers exist.

Comment threadMaple2.Server.Tests/Tools/LongExtensionsTests.cs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)

1-2: Restore missing NUnit using and replace C# 12 collection expression

[Test], [TestCase], and Assert won’t resolve without using NUnit.Framework;, so the test project doesn’t compile. The long[] testValues = [...] literal also requires C# 12; the repo still targets earlier language versions, so that syntax fails to build. Please add the NUnit using and fall back to a classic array initializer so the tests compile again.

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;
- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };

Also applies to: 121-135

🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1)

4-4: Verify the import is intentional.

The added import appears unused in this file.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • Maple2.Server.Game/Manager/BuffManager.cs
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/DungeonManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
  • Maple2.Server.Game/Packets/BreakablePacket.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
🧰 Additional context used
🧬 Code graph analysis (5)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (2)
Maple2.Model/Game/User/SkillCooldown.cs (2)

3-3: LGTM: Import required for extension method.

The import is necessary for using the Truncate32() extension method and is correctly placed.


24-24: LGTM: Improved clarity with explicit truncation.

The change from (int) EndTick to EndTick.Truncate32() is functionally equivalent but significantly improves code clarity by making the truncation intent explicit. This aligns with the broader refactoring pattern applied across the codebase for tick handling.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (2)

1-3: Fix missing NUnit import to compile tests

Add NUnit using so [Test]/Assert resolve.

Apply:

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;

121-136: Replace C# 12 collection expression with classic array initializer

Ensures compatibility with older language versions.

Apply:

- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
- 0xFFFFFFFF,+ 0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };
🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/DungeonManager.cs (1)

352-352: Avoid potential overflow: cast after dividing

Divide on long first, then cast to int.

Apply:

- UserRecord.TotalSeconds = (int) (Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000;+ UserRecord.TotalSeconds = (int) ((Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
🚧 Files skipped from review as they are similar to previous changes (7)
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Model/Game/User/SkillCooldown.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
🧰 Additional context used
🧬 Code graph analysis (7)
Maple2.Server.Game/Packets/BreakablePacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (7)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM: Safe 32-bit truncation for quest portal ticks.

The changes correctly use Truncate32() for EndTick and FieldTickInt for StartTick. The explicit cast to long before adding milliseconds prevents double-precision arithmetic, and Truncate32() safely masks the lower 32 bits without sign extension issues.


628-628: LGTM: Consistent tick truncation pattern.

The EndTick calculation correctly applies the same safe truncation pattern used for quest portals, ensuring consistent tick handling across portal types.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-324: Consistent 32-bit tick serialization

Using Truncate32() here is correct and consistent with packet expectations.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM: Use Truncate32 for StartTick

Correctly avoids checked-cast overflow and preserves lower 32 bits.

Maple2.Server.Game/Packets/BreakablePacket.cs (1)

27-29: LGTM: Safe 32-bit truncation for tick diff and base tick

Truncate32() matches TickCount wrap semantics and avoids overflow on casts.

Also applies to: 45-47

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: EndTick assignment already uses FieldTick—time bases match

Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: LGTM! Good refactor and bug fix.

The changes improve code clarity and correctness:

  1. Parameter rename (buffscacheBuffs): Avoids shadowing the class-level buffs field, making the code easier to read and maintain.

  2. Stack preservation (line 513): Now passes info.Stacks to AddBuff, correctly preserving stack counts when loading cached buffs. Previously, stacks would default to 0, losing this information.

The validation logic and filtering (lines 507-512) appropriately handle invalid buffs and skip expired buffs that don't use in-game time.

@AngeloTadeucci
AngeloTadeucci merged commit c3067a2 into masterOct 15, 2025
4 of 5 checks passed
@AngeloTadeucci
AngeloTadeucci deleted the field-tick branch October 15, 2025 02:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AngeloTadeucci
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Add LongExtensions.Truncate32 and refactor tick handling - #614

Merged
AngeloTadeucci merged 5 commits into
masterfrom
field-tick
Oct 15, 2025
Merged

Add LongExtensions.Truncate32 and refactor tick handling#614
AngeloTadeucci merged 5 commits into
masterfrom
field-tick

Conversation

@AngeloTadeucci

@AngeloTadeucciAngeloTadeucci commented Oct 13, 2025

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • Bug Fixes

    • Expired buffs and skill cooldowns are no longer saved or restored.
    • Timing calculations for portals, fishing, instruments, breakables, and region skills made more consistent to reduce desync and overflow issues.
  • Refactor

    • Standardized conversion of 64-bit ticks to 32-bit client timers for improved timing reliability.
  • Tests

    • Added comprehensive tests validating 32-bit tick truncation behavior.

@coderabbitai

coderabbitaiBot commented Oct 13, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Adds a 32-bit truncation helper (Truncate32) and applies it across tick serialization and packet writes, exposes a 32-bit FieldTickInt on IField/FieldManager, filters expired buffs/cooldowns when saving cache, and renames a BuffManager parameter.

Changes

Cohort / File(s)Summary
Tick truncation utility & tests
Maple2.Tools/Extensions/LongExtensions.cs, Maple2.Server.Tests/Tools/LongExtensionsTests.cs
Add Truncate32(this long) extension to truncate 64-bit ticks to 32-bit ints; add comprehensive unit tests covering boundaries, wraparound, and TickCount-like behavior.
Field tick API & usage
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs, Maple2.Server.Game/Manager/Field/FieldManager/IField.cs, Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs, Maple2.Server.Game/Manager/DungeonManager.cs, Maple2.Server.Game/Manager/FishingManager.cs, Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
Introduce FieldTickInt (derived via Truncate32) on FieldManager/IField; replace direct 64→32 casts with .Truncate32() or use FieldTickInt where 32-bit ticks are required; update tick initializations (e.g., use Lobby.FieldTick).
Serialization & packets
Maple2.Model/Game/User/SkillCooldown.cs, Maple2.Server.Game/Model/Field/Buff.cs, Maple2.Server.Game/Packets/BreakablePacket.cs, Maple2.Server.Game/Packets/InstrumentPacket.cs, Maple2.Server.Game/Packets/RegionSkillPacket.cs
Replace direct (int) casts of tick values with .Truncate32() when writing to buffers/packets; add using Maple2.Tools.Extensions.
Cache save filtering
Maple2.Server.Game/Session/GameSession.cs
Filter out expired buffs and skill cooldowns (Where(EndTick - fieldTick > 0)) before projecting and saving cache entries; compute MsRemaining via .Truncate32().
BuffManager signature change
Maple2.Server.Game/Manager/BuffManager.cs
Rename public method parameter from buffscacheBuffs in SetCacheBuffs(IList<BuffInfo> cacheBuffs, long currentTick) and update internal iteration/usage.

Sequence Diagram(s)

sequenceDiagram
autonumber
actor Player
participant GameSession
participant Field as FieldManager
participant BuffManager
participant Persistence as PlayerConfigStorage
Player->>GameSession: Request SaveCacheConfig
GameSession->>Field: Read FieldTick (64-bit)
Field-->>GameSession: FieldTickInt (FieldTick.Truncate32())
GameSession->>GameSession: Filter Buffs/Cooldowns (EndTick - FieldTick > 0)
GameSession->>Persistence: Save filtered BuffInfo & SkillCooldownInfo (MsRemaining via Truncate32)
Persistence-->>GameSession: Ack
GameSession-->>Player: Done
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Zintixx

Poem

I hop through ticks from long to small,
Snip 64-bits till they answer the call.
Packets line up, portals chime,
Buffs saved neat and right on time.
A rabbit trims each ticking line — 🐇⌛

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title Check✅ PassedThe title succinctly captures the core changes introduced in this pull request by mentioning both the addition of the Truncate32 extension method and the overarching refactoring of tick handling throughout the codebase. It is concise, specific, and directly reflects the main developer intent without extraneous detail.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch field-tick

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between deed140 and d5aff14.

📒 Files selected for processing (1)
  • Maple2.Server.Game/Session/GameSession.cs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
Maple2.Server.Game/Session/GameSession.cs (3)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-44)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (3)
Maple2.Server.Game/Session/GameSession.cs (3)

30-30: LGTM!

The import enables the use of Truncate32() for standardized 32-bit tick conversions throughout this file.


818-827: Good filtering of expired buffs.

The filtering logic correctly excludes buffs where EndTick - fieldTick <= 0, ensuring only active buffs are cached. The use of Truncate32() for the remaining duration calculation aligns with the broader refactoring effort.


830-839: Good filtering of expired cooldowns.

The filtering and projection logic mirrors the buff handling above, maintaining consistency across cache persistence.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
Maple2.Tools/Extensions/LongExtensions.cs (1)

10-12: LGTM! Clean truncation logic.

The implementation correctly truncates 64-bit values to 32-bit by masking the lower 32 bits and casting to int, which properly handles wraparound (values > int.MaxValue become negative, matching Environment.TickCount behavior).

Optional performance optimization:

Consider marking this method with [MethodImpl(MethodImplOptions.AggressiveInlining)] to ensure it's inlined at call sites, as it's a simple operation called frequently in serialization paths:

+using System.Runtime.CompilerServices;+
namespace Maple2.Tools.Extensions;
public static class LongExtensions {
/// <summary>
/// Truncates a long value to a 32-bit int, handling overflow properly.
/// This is useful for converting Environment.TickCount64 to match Environment.TickCount behavior.
/// </summary>
/// <param name="value">The long value to truncate</param>
/// <returns>The truncated int value</returns>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Truncate32(this long value) {
return (int) (0xFFFFFFFF & value);
}
}
Maple2.Server.Game/Packets/BreakablePacket.cs (1)

26-29: Correct 32‑bit tick truncation; minor consistency refactor

Using Truncate32() here is correct and safer than direct casts. For consistency and tiny perf, also cache Environment.TickCount64 in the single‑update overload.

Apply this diff to the single-update method:

- public static ByteWriter Update(FieldBreakable breakable) {+ public static ByteWriter Update(FieldBreakable breakable) {
var pWriter = Packet.Of(SendOp.Breakable);
pWriter.Write<Command>(Command.Update);
pWriter.WriteString(breakable.EntityId);
pWriter.Write<BreakableState>(breakable.State);
pWriter.WriteBool(breakable.Visible);
- if (breakable.BaseTick > 0) {- pWriter.WriteInt((Environment.TickCount64 - breakable.BaseTick).Truncate32());+ long currentTick = Environment.TickCount64;+ if (breakable.BaseTick > 0) {+ pWriter.WriteInt((currentTick - breakable.BaseTick).Truncate32());
pWriter.WriteInt(breakable.BaseTick.Truncate32());
} else {
pWriter.WriteInt();
pWriter.WriteInt();
}

Additionally, to guarantee behavior even inside checked contexts, consider making the extension use an unchecked cast:

publicstaticintTruncate32(thislongvalue)=>unchecked((int)value);

Based on learnings

Also applies to: 45-47

Maple2.Server.Game/Session/GameSession.cs (1)

813-839: Clamp MsRemaining to int range to avoid overflow

Current cast may overflow if remaining ms > int.MaxValue. Clamp before casting.

Apply this diff:

- .Where(buff => buff.EndTick - fieldTick > 0)+ .Where(buff => buff.EndTick - fieldTick > 0)
.Select(buff => new BuffInfo {
Id = buff.Id,
Level = buff.Level,
- MsRemaining = (int) (buff.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(buff.EndTick - fieldTick, int.MaxValue),
Stacks = buff.Stacks,
Enabled = buff.Enabled,
StopTime = stopTime,
}),
- .Where(cooldown => cooldown.EndTick - fieldTick > 0)+ .Where(cooldown => cooldown.EndTick - fieldTick > 0)
.Select(cooldown => new SkillCooldownInfo {
SkillId = cooldown.SkillId,
SkillLevel = cooldown.SkillLevel,
GroupId = cooldown.GroupId,
- MsRemaining = (int) (cooldown.EndTick - fieldTick),+ MsRemaining = (int) Math.Min(cooldown.EndTick - fieldTick, int.MaxValue),
StopTime = stopTime,
Charges = cooldown.Charges,
}),

Optional: also clamp DeathInfo.MsRemaining to non-negative to avoid sending negative values when already expired.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c45ccca and 72b5e0f.

📒 Files selected for processing (14)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (1)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/FishingManager.cs (1)
Maple2.Server.Game/Packets/FishingPacket.cs (1)
  • FishingPacket (12-156)
Maple2.Server.Game/Session/GameSession.cs (2)
Maple2.Server.World/Service/WorldService.PlayerConfig.cs (2)
  • PlayerConfigResponse (18-43)
  • PlayerConfigResponse (45-48)
Maple2.Server.World/Containers/PlayerConfigLookUp.cs (1)
  • Save (23-62)
Maple2.Server.Game/Packets/BreakablePacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (11)
Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: Approve stack restoration in SetCacheBuffs Passing info.Stacks to AddBuff restores buff stacks correctly; BuffInfo.Stacks is initialized in PlayerConfigResponse.

Maple2.Model/Game/User/SkillCooldown.cs (1)

24-24: LGTM! Consistent use of Truncate32 for serialization.

The change from direct cast to Truncate32() makes the 32-bit truncation intent explicit and aligns with the refactoring pattern.

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: LGTM! Improved timing consistency.

The change from Environment.TickCount to Lobby.FieldTick centralizes timing through the field manager, ensuring consistent field-relative timing for dungeon room records.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM! Consistent packet serialization.

The change to Truncate32() makes the 32-bit truncation explicit for packet serialization, aligning with the refactoring pattern.

Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)

21-21: LGTM! Consistent packet serialization.

The change to Truncate32() for NextTick serialization aligns with the refactoring pattern and makes truncation intent explicit.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-323: LGTM! Consistent buff serialization.

The changes to use Truncate32() for both StartTick and EndTick align with the refactoring pattern and make the 32-bit truncation explicit for byte serialization.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM! Consistent use of FieldTickInt for portal timing.

The change to use FieldTickInt directly for quest portal timing is cleaner than casting FieldTick and aligns with the 32-bit tick representation pattern.


628-628: LGTM! Consistent portal timing.

Using FieldTickInt for the bonus map portal's EndTick aligns with the other portal timing changes and the 32-bit tick pattern.

Maple2.Server.Game/Manager/FishingManager.cs (1)

257-257: LGTM! Cleaner fishing timer calculation.

Using session.Field.FieldTickInt directly is cleaner than casting FieldTick and aligns with the refactoring to use the 32-bit tick property.

Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1)

264-270: Good addition: 32‑bit tick accessor mirrors TickCount semantics

The Truncate32-based property is appropriate for client-facing 32-bit tick usage and avoids unsafe casts. Nice doc and placement.

Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1)

59-59: IField implementers updated FieldManager defines FieldTickInt; no other IField implementers exist.

Comment threadMaple2.Server.Tests/Tools/LongExtensionsTests.cs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)

1-2: Restore missing NUnit using and replace C# 12 collection expression

[Test], [TestCase], and Assert won’t resolve without using NUnit.Framework;, so the test project doesn’t compile. The long[] testValues = [...] literal also requires C# 12; the repo still targets earlier language versions, so that syntax fails to build. Please add the NUnit using and fall back to a classic array initializer so the tests compile again.

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;
- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };

Also applies to: 121-135

🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1)

4-4: Verify the import is intentional.

The added import appears unused in this file.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • Maple2.Server.Game/Manager/BuffManager.cs
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/DungeonManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
  • Maple2.Server.Game/Packets/BreakablePacket.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
🧰 Additional context used
🧬 Code graph analysis (5)
Maple2.Model/Game/User/SkillCooldown.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/RegionSkillPacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (2)
Maple2.Model/Game/User/SkillCooldown.cs (2)

3-3: LGTM: Import required for extension method.

The import is necessary for using the Truncate32() extension method and is correctly placed.


24-24: LGTM: Improved clarity with explicit truncation.

The change from (int) EndTick to EndTick.Truncate32() is functionally equivalent but significantly improves code clarity by making the truncation intent explicit. This aligns with the broader refactoring pattern applied across the codebase for tick handling.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (2)

1-3: Fix missing NUnit import to compile tests

Add NUnit using so [Test]/Assert resolve.

Apply:

 using Maple2.Tools.Extensions;
using System;
+using NUnit.Framework;

121-136: Replace C# 12 collection expression with classic array initializer

Ensures compatibility with older language versions.

Apply:

- long[] testValues = [+ long[] testValues = new long[] {
0L,
1L,
-1L,
int.MaxValue,
int.MinValue,
(long) int.MaxValue + 1,
(long) int.MinValue - 1,
- 0xFFFFFFFF,+ 0xFFFFFFFF,
0x100000000L,
0x123456789ABCDEF0L,
long.MaxValue,
long.MinValue,
- ];+ };
🧹 Nitpick comments (1)
Maple2.Server.Game/Manager/DungeonManager.cs (1)

352-352: Avoid potential overflow: cast after dividing

Divide on long first, then cast to int.

Apply:

- UserRecord.TotalSeconds = (int) (Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000;+ UserRecord.TotalSeconds = (int) ((Lobby.DungeonRoomRecord.EndTick - Lobby.DungeonRoomRecord.StartTick) / 1000);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72b5e0f and c0dca8f.

📒 Files selected for processing (15)
  • Maple2.Model/Game/User/SkillCooldown.cs (2 hunks)
  • Maple2.Server.Game/Manager/BuffManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/DungeonManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs (1 hunks)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs (1 hunks)
  • Maple2.Server.Game/Manager/FishingManager.cs (1 hunks)
  • Maple2.Server.Game/Model/Field/Buff.cs (2 hunks)
  • Maple2.Server.Game/Packets/BreakablePacket.cs (3 hunks)
  • Maple2.Server.Game/Packets/InstrumentPacket.cs (1 hunks)
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs (2 hunks)
  • Maple2.Server.Game/Session/GameSession.cs (1 hunks)
  • Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1 hunks)
  • Maple2.Tools/Extensions/LongExtensions.cs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • Maple2.Server.Game/Manager/Field/PerformanceStageManager.cs
🚧 Files skipped from review as they are similar to previous changes (7)
  • Maple2.Server.Game/Manager/FishingManager.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
  • Maple2.Server.Game/Session/GameSession.cs
  • Maple2.Model/Game/User/SkillCooldown.cs
  • Maple2.Tools/Extensions/LongExtensions.cs
  • Maple2.Server.Game/Packets/RegionSkillPacket.cs
  • Maple2.Server.Game/Manager/Field/FieldManager/IField.cs
🧰 Additional context used
🧬 Code graph analysis (7)
Maple2.Server.Game/Packets/BreakablePacket.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Model/Field/Buff.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Packets/InstrumentPacket.cs (2)
Maple2.Server.Core/Helpers/DebugByteWriter.cs (1)
  • WriteInt (69-72)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)
Maple2.Model/Metadata/Constants.cs (1)
  • Constant (10-963)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/DungeonManager.cs (1)
Maple2.Model/Game/Dungeon/DungeonRoomRecord.cs (2)
  • DungeonRoomRecord (7-17)
  • DungeonRoomRecord (14-16)
Maple2.Server.Tests/Tools/LongExtensionsTests.cs (1)
Maple2.Tools/Extensions/LongExtensions.cs (1)
  • Truncate32 (10-12)
Maple2.Server.Game/Manager/BuffManager.cs (1)
Maple2.Database/Storage/Metadata/SkillMetadataStorage.cs (1)
  • TryGetEffect (49-70)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: build
🔇 Additional comments (7)
Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs (2)

187-188: LGTM: Safe 32-bit truncation for quest portal ticks.

The changes correctly use Truncate32() for EndTick and FieldTickInt for StartTick. The explicit cast to long before adding milliseconds prevents double-precision arithmetic, and Truncate32() safely masks the lower 32 bits without sign extension issues.


628-628: LGTM: Consistent tick truncation pattern.

The EndTick calculation correctly applies the same safe truncation pattern used for quest portals, ensuring consistent tick handling across portal types.

Maple2.Server.Game/Model/Field/Buff.cs (1)

322-324: Consistent 32-bit tick serialization

Using Truncate32() here is correct and consistent with packet expectations.

Maple2.Server.Game/Packets/InstrumentPacket.cs (1)

65-65: LGTM: Use Truncate32 for StartTick

Correctly avoids checked-cast overflow and preserves lower 32 bits.

Maple2.Server.Game/Packets/BreakablePacket.cs (1)

27-29: LGTM: Safe 32-bit truncation for tick diff and base tick

Truncate32() matches TickCount wrap semantics and avoids overflow on casts.

Also applies to: 45-47

Maple2.Server.Game/Manager/DungeonManager.cs (1)

324-326: EndTick assignment already uses FieldTick—time bases match

Maple2.Server.Game/Manager/BuffManager.cs (1)

501-516: LGTM! Good refactor and bug fix.

The changes improve code clarity and correctness:

  1. Parameter rename (buffscacheBuffs): Avoids shadowing the class-level buffs field, making the code easier to read and maintain.

  2. Stack preservation (line 513): Now passes info.Stacks to AddBuff, correctly preserving stack counts when loading cached buffs. Previously, stacks would default to 0, losing this information.

The validation logic and filtering (lines 507-512) appropriately handle invalid buffs and skip expired buffs that don't use in-game time.

@AngeloTadeucci
AngeloTadeucci merged commit c3067a2 into masterOct 15, 2025
4 of 5 checks passed
@AngeloTadeucci
AngeloTadeucci deleted the field-tick branch October 15, 2025 02:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@AngeloTadeucci