Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Maple2.File.Ingest/Mapper/ItemMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public ItemMapper(M2dReader xmlReader) {
}

protected override IEnumerable<ItemMetadata> Map() {
IEnumerable<(int Id, ItemExtraction Extraction)> itemExtractionData = tableParser.ParseItemExtraction();
Dictionary<int, int> itemExtractionTryCount = tableParser.ParseItemExtraction()
.ToDictionary(entry => entry.Id, entry => entry.Extraction.TryCount);

Expand Down
2 changes: 2 additions & 0 deletions Maple2.File.Ingest/Mapper/MapDataMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ private FieldAccelerationStructure ParseMapEntities(IEnumerable<IMapEntity> enti
Rotation: placeable.Rotation,
Scale: placeable.Scale,
Bounds: entityBounds,
BreakDefense: vibrate.brokenDefence,
BreakTick: vibrate.brokenTick,
VibrateIndex: vibrateObjectId++);

break;
Expand Down
2 changes: 1 addition & 1 deletion Maple2.Model/Enum/Skill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public enum ApplyTargetType {
Friendly = 2,
Player1 = 3, // Unknown,
Player2 = 5, // Unknown,
Player3 = 6, // Unknown, Recovery
RegionBuff = 6,
Player4 = 7, // Unknown, Debuff (Archeon's ice bombs)
HungryMobs = 8
}
Expand Down
14 changes: 13 additions & 1 deletion Maple2.Model/Game/Field/FieldAccelerationStructure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,10 @@ public List<FieldVibrateEntity> QueryVibrateObjectsCenterList(Vector3 center, Ve

return vibrateObjects;
}

public FieldVibrateEntity? GetVibrateEntity(string entityId) {
return vibrateEntities.FirstOrDefault(vibrateEntity => vibrateEntity.Id.Id == entityId);
}
#endregion

#region Initialization
Expand Down Expand Up @@ -570,6 +574,8 @@ public void AddEntities(Dictionary<Vector3S, List<FieldEntity>> gridAlignedEntit
Rotation: new Vector3(0, 0, 0),
Scale: 1,
Bounds: new BoundingBox3(),
BreakDefense: 0,
BreakTick: 0,
VibrateIndex: i));
}

Expand Down Expand Up @@ -759,6 +765,8 @@ public void WriteTo(FieldEntity entity, IByteWriter writer) {
switch (entity) {
case FieldVibrateEntity vibrateEntity:
writer.Write(vibrateEntity.VibrateIndex);
writer.WriteInt(vibrateEntity.BreakDefense);
writer.WriteInt(vibrateEntity.BreakTick);
break;
case FieldSpawnTile spawnTile:
break;
Expand Down Expand Up @@ -811,6 +819,8 @@ public void ReadFrom(IByteReader reader) {
Rotation: new Vector3(0, 0, 0),
Scale: 1,
Bounds: new BoundingBox3(),
BreakDefense: 0,
BreakTick: 0,
VibrateIndex: i));
}

Expand Down Expand Up @@ -904,7 +914,9 @@ public FieldEntity ReadEntity(IByteReader reader) {
Rotation: rotation,
Scale: scale,
Bounds: bounds,
VibrateIndex: reader.ReadInt());
VibrateIndex: reader.ReadInt(),
BreakDefense: reader.ReadInt(),
BreakTick: reader.ReadInt());
case FieldEntityType.SpawnTile:
return new FieldSpawnTile(
Id: id,
Expand Down
2 changes: 2 additions & 0 deletions Maple2.Model/Metadata/FieldEntity/FieldEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public record FieldVibrateEntity(
Vector3 Rotation,
float Scale,
BoundingBox3 Bounds,
int BreakDefense,
int BreakTick,
int VibrateIndex) : FieldEntity(Id, Position, Rotation, Scale, Bounds);

public record FieldSpawnTile(
Expand Down
4 changes: 4 additions & 0 deletions Maple2.Server.Game/Manager/Config/BuffManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,10 @@ private void ModifyBuffStackCount(Buff buff) {
}
foreach (AdditionalEffectMetadataModifyOverlapCount modifyOverlapCount in buff.Metadata.ModifyOverlapCount) {
foreach (Buff buffResult in EnumerateBuffs(modifyOverlapCount.Id).Where(b => b.Stack(modifyOverlapCount.OffsetCount))) {
if (buffResult.Stacks <= 0) {
Remove(buffResult.Id, buffResult.Caster.ObjectId);
continue;
}
Actor.Field.Broadcast(BuffPacket.Update(buffResult));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,16 +349,13 @@ private SemaphoreSlim GetMapLock(int mapId) {

private FieldManager? GetInternal(int mapId, long ownerId = 0, int roomId = 0) {
if (roomId != 0) { // Specified room
FieldManager? foundField = FindRoom(mapId, roomId);
FieldManager? foundField = FindRoom();
if (foundField != null) {
return foundField;
}
}

if (ServerTableMetadata.InstanceFieldTable.Entries.TryGetValue(mapId, out InstanceFieldMetadata? metadata)) {
if (ownerId == 0 && roomId == 0) {
return Create(mapId);
}
switch (metadata.Type) {
case InstanceType.ugcMap: // this is both homes and UGD. Currently just doing homes.
if (roomId != 0) { // User wants to go into decorplanner or blueprint designer
Expand All @@ -370,14 +367,24 @@ private SemaphoreSlim GetMapLock(int mapId) {
return homeField;
case InstanceType.DungeonLobby:
return Create(mapId, ownerId: ownerId, roomId: roomId); // TODO: this should never happen.
case InstanceType.channelScale:
if (fields.TryGetValue(mapId, out ConcurrentDictionary<int, FieldManager>? scalingFields) && !scalingFields.IsEmpty) {
return scalingFields.Values.FirstOrDefault(f => !f.Disposed);
}
break;
default:
if (ownerId == 0 && roomId == 0) {
return Create(mapId);
}
break;
}
}

if (!fields.TryGetValue(mapId, out ConcurrentDictionary<int, FieldManager>? mapFields)) {
return Create(mapId, ownerId: ownerId, roomId: roomId);
}

if (roomId == 0 && mapFields.Count > 0) {
if (roomId == 0 && !mapFields.IsEmpty) {
FieldManager? firstField = mapFields.Values.FirstOrDefault();
if (firstField != null) {
return firstField;
Expand All @@ -387,7 +394,7 @@ private SemaphoreSlim GetMapLock(int mapId) {
return mapFields.TryGetValue(roomId, out FieldManager? field) ? field :
Create(mapId, ownerId: ownerId, roomId: roomId);

FieldManager? FindRoom(int mapId, int roomId) {
FieldManager? FindRoom() {
if (fields.TryGetValue(mapId, out ConcurrentDictionary<int, FieldManager>? roomFields) && roomFields.TryGetValue(roomId, out FieldManager? field)) {
return field;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,8 @@ public IEnumerable<IActor> GetTargets(IActor caster, Prism[] prisms, ApplyTarget
return [];
case ApplyTargetType.HungryMobs:
return prisms.Filter(Pets.Values.Where(pet => pet.OwnerId == 0), limit, ignore);
case ApplyTargetType.RegionBuff:
return prisms.Filter(Players.Values, limit, ignore);
default:
Log.Debug("Unhandled SkillEntity:{Entity}", targetType);
return [];
Expand Down
15 changes: 12 additions & 3 deletions Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public FieldManager(MapMetadata metadata, UgcMapMetadata ugcMetadata, MapEntityM
TriggerObjects = new TriggerCollection(entities);

Scheduler = new EventQueue();
FieldActor = new FieldActor(this, npcMetadata); // pulls from argument because member NpcMetadata is null here
FieldActor = new FieldActor(this, NextLocalId(), metadata, npcMetadata); // pulls from argument because member NpcMetadata is null here
cancel = new CancellationTokenSource();
thread = new Thread(UpdateLoop);
Ai = new AiManager(this);
Expand All @@ -116,6 +116,7 @@ public virtual void Init() {
}

initialized = true;
FieldTick = Environment.TickCount64;

if (MapData.TryGet(Metadata.XBlock, out FieldAccelerationStructure? accelerationStructure)) {
AccelerationStructure = accelerationStructure;
Expand Down Expand Up @@ -570,14 +571,22 @@ public void MovePlayerAlongPath(string pathName) {
}
}

public void VibrateObjects(SkillRecord record, Vector3 position) {
float rangeDistance = record.Attack.Range.Distance;
public void VibrateObjects(DamageRecord record, Vector3 position) {
if (record.AttackMetadata.BrokenOffence == 0) {
// No items are going to vibrate/break.
return;
}

float rangeDistance = record.AttackMetadata.Range.Distance;
if (AccelerationStructure is null) {
return;
}

List<FieldVibrateEntity> vibrateObjects = AccelerationStructure.QueryVibrateObjectsCenterList(position, 2 * new Vector3(rangeDistance, rangeDistance, rangeDistance));
foreach (FieldVibrateEntity vibrate in vibrateObjects) {
if (vibrate.BreakDefense < record.AttackMetadata.BrokenOffence) {
// TODO Keep a record of when the vibrate object was broken. Don't send if it's currently broken and respawning.
}
Broadcast(VibratePacket.Attack(vibrate.Id.Id, record));
}
}
Comment thread
Zintixx marked this conversation as resolved.
Expand Down
8 changes: 4 additions & 4 deletions Maple2.Server.Game/Model/Field/Actor/FieldActor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@
using Maple2.Tools.VectorMath;
using Maple2.Tools.Collision;
using Maple2.Database.Storage;
using Maple2.Model.Metadata;
using Maple2.Server.Game.Manager;
using Maple2.Server.Game.Model.ActorStateComponent;
using Maple2.Server.Game.Model.Skill;

namespace Maple2.Server.Game.Model;

// Dummy Actor for field to own entities.
internal sealed class FieldActor : IActor {
public class FieldActor : Actor<MapMetadata> {
public FieldManager Field { get; }
public NpcMetadataStorage NpcMetadata { get; init; }

public int ObjectId => 0;
public bool IsDead => false;
public IPrism Shape => new PointPrism(Position);
public override IPrism Shape => new PointPrism(Position);
public ActorState State => ActorState.None;
public ActorSubState SubState => ActorSubState.None;
public Vector3 Position { get => Transform.Position; set => Transform.Position = value; }
Expand All @@ -30,7 +30,7 @@ internal sealed class FieldActor : IActor {
public SkillState SkillState { get; init; }
public SkillQueue ActiveSkills { get; init; }

public FieldActor(FieldManager field, NpcMetadataStorage npcMetadata) {
public FieldActor(FieldManager field, int objectId, MapMetadata mapMetadata, NpcMetadataStorage npcMetadata) : base(field, objectId, mapMetadata, npcMetadata) {
Field = field;
Stats = new StatsManager(this);
Buffs = new BuffManager(this);
Expand Down
4 changes: 2 additions & 2 deletions Maple2.Server.Game/Model/Field/Entity/FieldSkill.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,7 @@ public override void Update(long tickCount) {
// }
// }

Field.VibrateObjects(record, Position);

Field.VibrateObjects(damage, Position);
foreach (IActor target in targets) {
target.ApplyDamage(Caster, damage, attack);
// TODO: Set PrevUid?
Expand All @@ -188,6 +187,7 @@ public override void Update(long tickCount) {
Field.Broadcast(SkillDamagePacket.Target(record, targetRecords));
Field.Broadcast(SkillDamagePacket.Region(damage));
}

Caster.ApplyEffects(attack.SkillsOnDamage, Caster, damage, targets: targets);
Caster.ApplyEffects(attack.Skills, Caster, Caster, skillId: Value.Id, targets: targets);
}
Expand Down
1 change: 1 addition & 0 deletions Maple2.Server.Game/PacketHandlers/RequestCubeHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ private void HandleLiftupObject(GameSession session, IByteReader packet) {

session.HeldLiftup = weapon;
session.Field.Broadcast(CubePacket.LiftupObject(session.Player, session.HeldLiftup));
session.Player.InBattle = true;
}

private void HandleLiftupDrop(GameSession session) {
Expand Down
37 changes: 24 additions & 13 deletions Maple2.Server.Game/PacketHandlers/VibrateHandler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Numerics;
using Maple2.Database.Storage;
using Maple2.Model.Metadata;
using Maple2.Model.Metadata.FieldEntity;
using Maple2.PacketLib.Tools;
using Maple2.Server.Core.Constants;
using Maple2.Server.Core.PacketHandlers;
Expand All @@ -24,26 +25,36 @@ public override void Handle(GameSession session, IByteReader packet) {
long skillUid = packet.ReadLong();
int skillId = packet.ReadInt();
short level = packet.ReadShort();
if (!SkillMetadata.TryGet(skillId, level, out SkillMetadata? metadata)) {
Logger.Error("Invalid skill use: {SkillId},{Level}", skillId, level);
return;
}

var record = new SkillRecord(metadata, skillUid, session.Player);
byte motionPoint = packet.ReadByte();
if (!record.TrySetMotionPoint(motionPoint)) {
Logger.Error("Invalid MotionPoint({MotionPoint}) for {Record}", motionPoint, record);
return;
}
byte attackPoint = packet.ReadByte();
if (!record.TrySetAttackPoint(attackPoint)) {
Logger.Error("Invalid AttackPoint({AttackPoint}) for {Record}", attackPoint, record);

SkillRecord? record = session.Player.ActiveSkills.Get(skillUid);
if (record == null) {
Logger.Warning("Invalid Skill {SkillUid}", skillUid);
return;
}

DamageRecord damage = new(record.Metadata, record.Attack) {
CasterId = session.Player.ObjectId,
TargetUid = record.TargetUid,
OwnerId = session.Player.ObjectId,
SkillId = record.SkillId,
Level = record.Level,
MotionPoint = record.MotionPoint,
AttackPoint = record.AttackPoint,
Position = record.Position,
Direction = record.Direction,
};

Comment thread
Zintixx marked this conversation as resolved.
record.ServerTick = packet.ReadInt();
record.Position = packet.Read<Vector3>();

session.Field?.Broadcast(VibratePacket.Attack(entityId, record));
FieldVibrateEntity? vibrate = session.Field?.AccelerationStructure?.GetVibrateEntity(entityId);
if (vibrate != null && vibrate.BreakDefense < record.Attack.BrokenOffence) {
//TODO: Keep a record of when the vibrate was broken.
}

// Packet gets sent regardless
session.Field?.Broadcast(VibratePacket.Attack(entityId, damage));
}
}
14 changes: 7 additions & 7 deletions Maple2.Server.Game/Packets/VibratePacket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ private enum Command : byte {
Invoke = 2,
}

public static ByteWriter Attack(string entityId, SkillRecord skill) {
public static ByteWriter Attack(string entityId, DamageRecord damage) {
var pWriter = Packet.Of(SendOp.Vibrate);
pWriter.Write<Command>(Command.Attack);
pWriter.WriteString(entityId);
pWriter.WriteLong(skill.CastUid);
pWriter.WriteInt(skill.SkillId);
pWriter.WriteShort(skill.Level);
pWriter.WriteByte(skill.MotionPoint);
pWriter.WriteByte(skill.AttackPoint);
pWriter.Write<Vector3S>(skill.Position);
pWriter.WriteLong(damage.SkillUid);
pWriter.WriteInt(damage.SkillId);
pWriter.WriteShort(damage.Level);
pWriter.WriteByte(damage.MotionPoint);
pWriter.WriteByte(damage.AttackPoint);
pWriter.Write<Vector3S>(damage.Position);
pWriter.WriteInt(Environment.TickCount);
pWriter.WriteString();
pWriter.WriteByte();
Expand Down