171 lines
4.8 KiB
C#
171 lines
4.8 KiB
C#
using System.Diagnostics;
|
||
using ClientTester.Packet;
|
||
using LiteNetLib;
|
||
using LiteNetLib.Utils;
|
||
using Serilog;
|
||
|
||
namespace ClientTester.DummyService;
|
||
|
||
public class DummyClients
|
||
{
|
||
private NetManager manager;
|
||
private EventBasedNetListener listener;
|
||
private NetDataWriter? writer;
|
||
public NetPeer? peer;
|
||
public int clientId; // 일단 이게 hashKey가 됨 => 0 ~ 1000번까지는 더미용응로 뺴둠
|
||
|
||
// info
|
||
private Vector3 position = new Vector3();
|
||
private int rotY = 0;
|
||
private float moveSpeed = 3.5f;
|
||
private float distance = 0.0f;
|
||
private float preTime = 0.0f;
|
||
|
||
// 이동 계산용
|
||
private readonly Stopwatch moveClock = Stopwatch.StartNew();
|
||
private float posX = 0f;
|
||
private float posZ = 0f;
|
||
private float dirX = 0f;
|
||
private float dirZ = 0f;
|
||
|
||
// 맵 경계
|
||
public MapBounds Map { get; set; } = new MapBounds(-50f, 50f, -50f, 50f);
|
||
|
||
// 통계
|
||
public int SentCount
|
||
{
|
||
set;
|
||
get;
|
||
}
|
||
|
||
public int ReceivedCount
|
||
{
|
||
set;
|
||
get;
|
||
}
|
||
|
||
public int RttCount
|
||
{
|
||
set;
|
||
get;
|
||
}
|
||
|
||
public DummyClients(int clientId, string ip, int port, string key)
|
||
{
|
||
this.clientId = clientId;
|
||
listener = new EventBasedNetListener();
|
||
manager = new NetManager(listener);
|
||
writer = new NetDataWriter();
|
||
|
||
listener.PeerConnectedEvent += netPeer =>
|
||
{
|
||
peer = netPeer;
|
||
Log.Information("[Client {ClientId:00}] 연결됨", this.clientId);
|
||
|
||
// clientID가 토큰의 hashKey라고 가정함
|
||
DummyAccTokenPacket recvTokenPacket = new DummyAccTokenPacket();
|
||
recvTokenPacket.Token = clientId;
|
||
|
||
byte[] data = PacketSerializer.Serialize((ushort)PacketCode.DUMMY_ACC_TOKEN, recvTokenPacket);
|
||
writer.Put(data);
|
||
peer.Send(writer, DeliveryMethod.ReliableOrdered);
|
||
writer.Reset();
|
||
};
|
||
|
||
listener.NetworkReceiveEvent += (peer, reader, channel, deliveryMethod) =>
|
||
{
|
||
ReceivedCount++;
|
||
reader.Recycle();
|
||
};
|
||
|
||
listener.PeerDisconnectedEvent += (peer, info) =>
|
||
{
|
||
Log.Warning("[Client {ClientId:00}] 연결 끊김: {Reason}", this.clientId, info.Reason);
|
||
this.peer = null;
|
||
};
|
||
|
||
manager.Start();
|
||
manager.Connect(ip, port, key);
|
||
}
|
||
|
||
public void UpdateDummy()
|
||
{
|
||
// 델타 타임 계산 (초 단위)
|
||
float now = (float)moveClock.Elapsed.TotalSeconds;
|
||
float delta = preTime > 0f ? now - preTime : 0.1f;
|
||
preTime = now;
|
||
|
||
// 남은 거리가 없으면 새 방향·목표 거리 설정
|
||
if (distance <= 0f)
|
||
{
|
||
// 벽에 붙어있으면 반대 방향 강제, 아니면 ±30도 회전
|
||
int wallRotY = Map.GetRotYAwayFromWall(posX, posZ);
|
||
rotY = wallRotY >= 0
|
||
? (wallRotY + Random.Shared.Next(-30, 31) + 360) % 360
|
||
: (rotY + Random.Shared.Next(-30, 31) + 360) % 360;
|
||
|
||
float rad = rotY * MathF.PI / 180f;
|
||
dirX = MathF.Sin(rad);
|
||
dirZ = MathF.Cos(rad);
|
||
|
||
// 3초~12초에 도달할 수 있는 거리 = moveSpeed × 랜덤 초
|
||
float seconds = 3f + (float)Random.Shared.NextDouble() * 9f;
|
||
distance = moveSpeed * seconds;
|
||
}
|
||
|
||
// 이번 틱 이동량 (남은 거리 초과 방지)
|
||
float step = MathF.Min(moveSpeed * delta, distance);
|
||
float nextX = posX + dirX * step;
|
||
float nextZ = posZ + dirZ * step;
|
||
|
||
// 벽 충돌 시 clamp + 다음 틱에 방향 재설정
|
||
bool hitWall = Map.Clamp(ref nextX, ref nextZ);
|
||
posX = nextX;
|
||
posZ = nextZ;
|
||
distance = hitWall ? 0f : distance - step;
|
||
|
||
// 정수 Vector3 갱신
|
||
position.X = (int)MathF.Round(posX);
|
||
position.Z = (int)MathF.Round(posZ);
|
||
}
|
||
|
||
public void SendTransform()
|
||
{
|
||
if (peer == null || writer == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
UpdateDummy();
|
||
TransformPlayerPacket transformPlayerPacket = new TransformPlayerPacket
|
||
{
|
||
PlayerId = clientId,
|
||
RotY = rotY,
|
||
Position = new Packet.Position
|
||
{
|
||
X = position.X,
|
||
Y = 0, // 높이는 버린다.
|
||
Z = position.Z
|
||
}
|
||
};
|
||
|
||
// Protobuf 직렬화 + 헤더 조립
|
||
byte[] data = PacketSerializer.Serialize((ushort)PacketCode.TRANSFORM_PLAYER, transformPlayerPacket);
|
||
writer.Put(data);
|
||
// 이동은 손실 감수함
|
||
peer.Send(writer, DeliveryMethod.Unreliable);
|
||
SentCount++;
|
||
writer.Reset();
|
||
}
|
||
|
||
public void PollEvents()
|
||
{
|
||
manager.PollEvents();
|
||
}
|
||
|
||
public void Stop()
|
||
{
|
||
manager.Stop();
|
||
}
|
||
}
|