Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.





Info

hubConnection 에서 커넥트가 최초 성공하면 수신기 만들어죠

Code Block
themeEmacs
linenumberstrue
collapsetrue
protected override async Task OnInitializedAsync()
{
    LoginId = Guid.NewGuid().ToString();    //Fake Login ID

    hubConnection = new HubConnectionBuilder()
        .WithUrl(_navigationManager.ToAbsoluteUri("/chathub"))
        .Build();

    await hubConnection.StartAsync();

    // 수신기 설정
    hubConnection.On<RoomInfo, UserInfo, UpdateUserPos>("OnJoinRoom", (room, user, pos) =>
    {
        Console.WriteLine($"WS - OnJoinRoom");
        if (user.Id == LoginId)
        {
            Name = user.Name;
            RoomName = room.Name;

            SyncRoom syndMsg = new SyncRoom()
            {
                UserInfo = new UserInfo() { Name = "user", Id = LoginId },
                RoomInfo = new RoomInfo() { Name = "room1" }
            };

            hubConnection.SendAsync("SyncRoom", syndMsg).Wait();
        }
        else
        {
            _chatLand.AddUser(user.Id, user.Name, pos.AbsPosX, pos.AbsPosY, false, resource);
        }
    });

    // 다른 수신기 설정
    hubConnection.On<UserInfo, List<UpdateUserPos>>("OnSyncRoom", (user, updateUserPos) =>
    {
        Console.WriteLine($"WS - OnSyncRoom");
        if (user.Id == LoginId)
        {
            foreach (var pos in updateUserPos)
            {
                bool isMine = pos.Id == LoginId ? true : false;

                _chatLand.AddUser(pos.Id, pos.Name, pos.AbsPosX, pos.AbsPosY, isMine, resource);
            }
        }
    });

    //ChatMessage
    hubConnection.On<ChatMessage>("OnChatMessage", (chatMessage) =>
    {
        bool isMine = chatMessage.From.Id == LoginId ? true : false;
        _messages.Add(new Message(chatMessage.From.Name, chatMessage.Message, isMine));
        Console.WriteLine($"WS - OnChatMessage");
        _chatLand.ChatMessage(chatMessage);

        // Inform blazor the UI needs updating
        StateHasChanged();
    });

    hubConnection.On<UpdateUserPos>("OnUpdateUserPos", (userPos) =>
    {
        Console.WriteLine($"WS - OnUpdateUserPos");
        _chatLand.UpdateUserPos(userPos);
    });

    hubConnection.On<LeaveRoom>("OnLeaveRoom", (room) =>
    {
        Console.WriteLine($"WS - OnLeaveRoom");
        _chatLand.RemoveUser(room.UserInfo.Id);

        StateHasChanged();
    });

    JoinRoom sendMsg = new JoinRoom()
    {
        UserInfo = new UserInfo() { Name = "user", Id = LoginId },
        RoomInfo = new RoomInfo() { Name = "room1" }
    };

    await hubConnection.SendAsync("JoInRoom", sendMsg);
}




Info

  ChatMessage 의 History를 큐로 최대 50개까지만 최신기준 유지하고싶습니다. 그리고 이 히스토리를 뷰티 json형태로 반환하는 함수도 만들어

Code Block
themeEmacs
linenumberstrue
collapsetrue
using System.Collections.Concurrent;

namespace BlazorChatApp.Server.Hubs
{
    public class RoomActor : ReceiveActor
    {
        private readonly ILoggingAdapter log = Context.GetLogger();
        public Dictionary<string, UpdateUserPos> users = new Dictionary<string, UpdateUserPos>();
        private string roomName;
        private int userAutoNo = 0;
        private readonly IServiceScopeFactory scopeFactory;
        private readonly ConcurrentQueue<ChatMessage> chatHistory = new ConcurrentQueue<ChatMessage>();
        private const int MaxChatHistoryCount = 50;
        Random random = new Random();

        public RoomActor(string _roomName, IServiceScopeFactory _scopeFactory)
        {
            scopeFactory = _scopeFactory;
            roomName = _roomName;
            log.Info($"Create Room{roomName}");

            Receive<RoomCmd>(cmd => {
                log.Info("Received String message: {0}", cmd);
                //Sender.Tell(message);                
            });

            Receive<JoinRoom>(async cmd => {
                userAutoNo++;
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received JoinRoom message: {0}", jsonString);
                string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

                UserInfo userInfo = new UserInfo()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    Color = RandomColor
                };

                // Default Position
                double posx = random.Next(0, 300);
                double posy = random.Next(400, 550);

                UpdateUserPos updateUserPos = new UpdateUserPos()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    PosX = posx,
                    PosY = posy,
                    AbsPosX = posx,
                    AbsPosY = posy,
                    ConnectionId = cmd.ConnectionId
                };

                if (!users.ContainsKey(updateUserPos.Id))
                    users[cmd.UserInfo.Id] = updateUserPos;

                await OnJoinRoom(cmd.RoomInfo, userInfo, updateUserPos);
            });

            Receive<SyncRoom>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received SyncRoom message: {0}", jsonString);

                List<UpdateUserPos> updateUserPosList = users.Values.ToList();
                string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

                UserInfo userInfo = new UserInfo()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    Color = RandomColor
                };

                await OnSyncRoom(userInfo, updateUserPosList);
            });

            Receive<ChatMessage>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received ChatMessage message: {0}", jsonString);

                ChatMessage chatMessage = new ChatMessage()
                {
                    From = cmd.From,
                    Message = cmd.Message
                };

                AddChatMessageToHistory(chatMessage);
                await OnChatMessage(chatMessage);
            });

            Receive<UpdateUserPos>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received UpdateUserPos message: {0}", jsonString);

                double AbsPosX = users[cmd.Id].PosX + cmd.PosX;
                double AbsPosY = users[cmd.Id].PosY + cmd.PosY;

                if (users.ContainsKey(cmd.Id))
                {
                    users[cmd.Id].PosX = AbsPosX;
                    users[cmd.Id].PosY = AbsPosY;
                    users[cmd.Id].AbsPosX = AbsPosX;
                    users[cmd.Id].AbsPosY = AbsPosY;
                }

                log.Info($"UpdateUser : X=>{users[cmd.Id].AbsPosX} Y=>{users[cmd.Id].AbsPosY}");

                UpdateUserPos updateUserPos = new UpdateUserPos()
                {
                    Id = cmd.Id,
                    Name = cmd.Name,
                    PosX = cmd.PosX,
                    PosY = cmd.PosY,
                    AbsPosX = AbsPosX,
                    AbsPosY = AbsPosY
                };

                await OnUpdateUserPos(updateUserPos);
            });

            Receive<Disconnect>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received Disconnect message: {0}", jsonString);
                var disconnectUser = users.Values.Where(e => e.ConnectionId == cmd.ConnectionId).FirstOrDefault();

                if (disconnectUser != null)
                {
                    if (users.ContainsKey(disconnectUser.Id))
                    {
                        users.Remove(disconnectUser.Id);

                        var leaveMsg = new LeaveRoom()
                        {
                            UserInfo = new UserInfo() { Id = disconnectUser.Id }
                        };
                        await OnLeaveRoom(leaveMsg);
                    }
                }
            });

            Receive<LeaveRoom>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received LeaveRoom message: {0}", jsonString);

                if (users.ContainsKey(cmd.UserInfo.Id))
                {
                    users.Remove(cmd.UserInfo.Id);
                    await OnLeaveRoom(cmd);
                }
            });
        }

        private void AddChatMessageToHistory(ChatMessage chatMessage)
        {
            chatHistory.Enqueue(chatMessage);
            while (chatHistory.Count > MaxChatHistoryCount)
            {
                chatHistory.TryDequeue(out _);
            }
        }

        public string GetChatHistoryAsJson()
        {
            return JsonSerializer.Serialize(chatHistory.ToList());
        }

        public async Task OnJoinRoom(RoomInfo roomInfo, UserInfo user, UpdateUserPos updateUserPos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnJoinRoom", roomInfo, user, updateUserPos);
            }
        }

        public async Task OnSyncRoom(UserInfo user, List<UpdateUserPos> updateUserPos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnSyncRoom", user, updateUserPos);
            }
        }

        public async Task OnLeaveRoom(LeaveRoom leaveRoom)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnLeaveRoom", leaveRoom);
            }
        }

        public async Task OnUpdateUserPos(UpdateUserPos updatePos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnUpdateUserPos", updatePos);
            }
        }

        public async Task OnChatMessage(ChatMessage chatMessage)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnChatMessage", chatMessage);
            }
        }
    }
}



Info

RoomActor에 사람이 아닌 자동응답을 하는 봇객체를 1개 추가하고싶습니다. JoinRoom 이벤트를 활용해 UserInfo를 추가 참고로 해당 모델은 액터모델이며 액터모델 특성을 고려해 작성

Code Block
themeEmacs
linenumberstrue
collapsetrue
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;

using Akka.Actor;
using Akka.Event;

using BlazorChatApp.Shared;

using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;

namespace BlazorChatApp.Server.Hubs
{
    public class RoomActor : ReceiveActor
    {
        private readonly ILoggingAdapter log = Context.GetLogger();

        public Dictionary<string, UpdateUserPos> users = new Dictionary<string, UpdateUserPos>();

        private string roomName;

        private int userAutoNo = 0;

        private readonly IServiceScopeFactory scopeFactory;

        private readonly ConcurrentQueue<ChatMessage> chatHistory = new ConcurrentQueue<ChatMessage>();

        private const int MaxChatHistoryCount = 50;

        private readonly UserInfo botUserInfo;
        private readonly UpdateUserPos botUpdateUserPos;

        Random random = new Random();

        public RoomActor(string _roomName, IServiceScopeFactory _scopeFactory)
        {
            scopeFactory = _scopeFactory;

            roomName = _roomName;

            log.Info($"Create Room{roomName}");

            // Initialize bot user
            botUserInfo = new UserInfo()
            {
                Id = "bot",
                Name = "ChatBot",
                Color = "#FF5733"
            };

            botUpdateUserPos = new UpdateUserPos()
            {
                Id = botUserInfo.Id,
                Name = botUserInfo.Name,
                PosX = 0,
                PosY = 0,
                AbsPosX = 0,
                AbsPosY = 0,
                ConnectionId = "bot-connection"
            };

            users[botUserInfo.Id] = botUpdateUserPos;

            Receive<RoomCmd>(cmd => {
                log.Info("Received String message: {0}", cmd);
                //Sender.Tell(message);                
            });

            Receive<JoinRoom>(async cmd => {
                userAutoNo++;
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received JoinRoom message: {0}", jsonString);
                string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

                UserInfo userInfo = new UserInfo()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    Color = RandomColor
                };

                // Default Position
                double posx = random.Next(0, 300);
                double posy = random.Next(400, 550);

                UpdateUserPos updateUserPos = new UpdateUserPos()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    PosX = posx,
                    PosY = posy,
                    AbsPosX = posx,
                    AbsPosY = posy,
                    ConnectionId = cmd.ConnectionId
                };

                if (!users.ContainsKey(updateUserPos.Id))
                    users[cmd.UserInfo.Id] = updateUserPos;

                await OnJoinRoom(cmd.RoomInfo, userInfo, updateUserPos);
            });

            Receive<SyncRoom>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received SyncRoom message: {0}", jsonString);

                List<UpdateUserPos> updateUserPosList = users.Values.ToList();
                string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

                UserInfo userInfo = new UserInfo()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    Color = RandomColor
                };

                await OnSyncRoom(userInfo, updateUserPosList);
            });

            Receive<ChatMessage>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received ChatMessage message: {0}", jsonString);

                ChatMessage chatMessage = new ChatMessage()
                {
                    From = cmd.From,
                    Message = cmd.Message
                };

                AddChatMessageToHistory(chatMessage);

                await OnChatMessage(chatMessage);

                // Bot response
                if (cmd.Message.Contains("bot", StringComparison.OrdinalIgnoreCase))
                {
                    var botResponse = new ChatMessage()
                    {
                        From = botUserInfo,
                        Message = "Hello! How can I assist you today?"
                    };

                    AddChatMessageToHistory(botResponse);
                    await OnChatMessage(botResponse);
                }
            });

            Receive<UpdateUserPos>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received UpdateUserPos message: {0}", jsonString);

                double AbsPosX = users[cmd.Id].PosX + cmd.PosX;
                double AbsPosY = users[cmd.Id].PosY + cmd.PosY;

                if (users.ContainsKey(cmd.Id))
                {
                    users[cmd.Id].PosX = AbsPosX;
                    users[cmd.Id].PosY = AbsPosY;
                    users[cmd.Id].AbsPosX = AbsPosX;
                    users[cmd.Id].AbsPosY = AbsPosY;
                }

                log.Info($"UpdateUser : X=>{users[cmd.Id].AbsPosX} Y=>{users[cmd.Id].AbsPosY}");

                UpdateUserPos updateUserPos = new UpdateUserPos()
                {
                    Id = cmd.Id,
                    Name = cmd.Name,
                    PosX = cmd.PosX,
                    PosY = cmd.PosY,
                    AbsPosX = AbsPosX,
                    AbsPosY = AbsPosY
                };

                await OnUpdateUserPos(updateUserPos);
            });

            Receive<Disconnect>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received Disconnect message: {0}", jsonString);
                var disconnectUser = users.Values.Where(e => e.ConnectionId == cmd.ConnectionId).FirstOrDefault();

                if (disconnectUser != null)
                {
                    if (users.ContainsKey(disconnectUser.Id))
                    {
                        users.Remove(disconnectUser.Id);

                        var leaveMsg = new LeaveRoom()
                        {
                            UserInfo = new UserInfo() { Id = disconnectUser.Id }
                        };
                        await OnLeaveRoom(leaveMsg);
                    }
                }
            });

            Receive<LeaveRoom>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received LeaveRoom message: {0}", jsonString);

                if (users.ContainsKey(cmd.UserInfo.Id))
                {
                    users.Remove(cmd.UserInfo.Id);
                    await OnLeaveRoom(cmd);
                }
            });
        }

        private void AddChatMessageToHistory(ChatMessage chatMessage)
        {
            chatHistory.Enqueue(chatMessage);
            while (chatHistory.Count > MaxChatHistoryCount)
            {
                chatHistory.TryDequeue(out _);
            }
        }

        private string GetChatHistoryAsJson()
        {
            return JsonSerializer.Serialize(chatHistory.ToList());
        }

        public async Task OnJoinRoom(RoomInfo roomInfo, UserInfo user, UpdateUserPos updateUserPos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnJoinRoom", roomInfo, user, updateUserPos);
            }
        }

        public async Task OnSyncRoom(UserInfo user, List<UpdateUserPos> updateUserPos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnSyncRoom", user, updateUserPos);
            }
        }

        public async Task OnLeaveRoom(LeaveRoom leaveRoom)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnLeaveRoom", leaveRoom);
            }
        }

        public async Task OnUpdateUserPos(UpdateUserPos updatePos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnUpdateUserPos", updatePos);
            }
        }

        public async Task OnChatMessage(ChatMessage chatMessage)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnChatMessage", chatMessage);
            }
        }
    }
}




Info

RoomActor 에 타이머기능을 넣어죠 10초에한번씩 반복작동 이벤트를 발생 액터타이머를 이용

Code Block
themeEmacs
linenumberstrue
collapsetrue
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;

using Akka.Actor;
using Akka.Event;

using BlazorChatApp.Shared;

using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;

namespace BlazorChatApp.Server.Hubs
{
    public class RoomActor : ReceiveActor
    {
        private readonly ILoggingAdapter log = Context.GetLogger();

        public Dictionary<string, UpdateUserPos> users = new Dictionary<string, UpdateUserPos>();

        private string roomName;

        private int userAutoNo = 0;

        private readonly IServiceScopeFactory scopeFactory;

        private readonly ConcurrentQueue<ChatMessage> chatHistory = new ConcurrentQueue<ChatMessage>();

        private const int MaxChatHistoryCount = 50;

        private readonly UserInfo botUserInfo;
        private readonly UpdateUserPos botUpdateUserPos;

        Random random = new Random();

        public RoomActor(string _roomName, IServiceScopeFactory _scopeFactory)
        {
            scopeFactory = _scopeFactory;

            roomName = _roomName;

            log.Info($"Create Room{roomName}");

            string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

            // Initialize bot user
            botUserInfo = new UserInfo()
            {
                Id = "bot-1",
                Name = "ChatBot-1",
                Color = RandomColor
            };

            botUpdateUserPos = new UpdateUserPos()
            {
                Id = botUserInfo.Id,
                Name = botUserInfo.Name,
                PosX = 250,
                PosY = 250,
                AbsPosX = 250,
                AbsPosY = 250,
                ConnectionId = "bot-connection"
            };

            users[botUserInfo.Id] = botUpdateUserPos;

            // Schedule a timer to send a Tick message every 10 seconds
            Context.System.Scheduler.ScheduleTellRepeatedly(
                TimeSpan.FromSeconds(10),
                TimeSpan.FromSeconds(10),
                Self,
                new Tick(),
                Self
            );

            Receive<RoomCmd>(cmd => {
                log.Info("Received String message: {0}", cmd);
                //Sender.Tell(message);                
            });

            Receive<JoinRoom>(async cmd => {
                userAutoNo++;
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received JoinRoom message: {0}", jsonString);
                string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

                UserInfo userInfo = new UserInfo()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    Color = RandomColor
                };

                // Default Position
                double posx = random.Next(0, 300);
                double posy = random.Next(400, 550);

                UpdateUserPos updateUserPos = new UpdateUserPos()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    PosX = posx,
                    PosY = posy,
                    AbsPosX = posx,
                    AbsPosY = posy,
                    ConnectionId = cmd.ConnectionId
                };

                if (!users.ContainsKey(updateUserPos.Id))
                    users[cmd.UserInfo.Id] = updateUserPos;

                await OnJoinRoom(cmd.RoomInfo, userInfo, updateUserPos);
            });

            Receive<SyncRoom>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received SyncRoom message: {0}", jsonString);

                List<UpdateUserPos> updateUserPosList = users.Values.ToList();
                string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

                UserInfo userInfo = new UserInfo()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    Color = RandomColor
                };

                await OnSyncRoom(botUserInfo, updateUserPosList);

                await OnSyncRoom(userInfo, updateUserPosList);
            });

            Receive<ChatMessage>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received ChatMessage message: {0}", jsonString);

                ChatMessage chatMessage = new ChatMessage()
                {
                    From = cmd.From,
                    Message = cmd.Message
                };

                AddChatMessageToHistory(chatMessage);

                await OnChatMessage(chatMessage);
            });

            Receive<UpdateUserPos>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received UpdateUserPos message: {0}", jsonString);

                double AbsPosX = users[cmd.Id].PosX + cmd.PosX;
                double AbsPosY = users[cmd.Id].PosY + cmd.PosY;

                if (users.ContainsKey(cmd.Id))
                {
                    users[cmd.Id].PosX = AbsPosX;
                    users[cmd.Id].PosY = AbsPosY;
                    users[cmd.Id].AbsPosX = AbsPosX;
                    users[cmd.Id].AbsPosY = AbsPosY;
                }

                log.Info($"UpdateUser : X=>{users[cmd.Id].AbsPosX} Y=>{users[cmd.Id].AbsPosY}");

                UpdateUserPos updateUserPos = new UpdateUserPos()
                {
                    Id = cmd.Id,
                    Name = cmd.Name,
                    PosX = cmd.PosX,
                    PosY = cmd.PosY,
                    AbsPosX = AbsPosX,
                    AbsPosY = AbsPosY
                };

                await OnUpdateUserPos(updateUserPos);
            });

            Receive<Disconnect>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received Disconnect message: {0}", jsonString);
                var disconnectUser = users.Values.Where(e => e.ConnectionId == cmd.ConnectionId).FirstOrDefault();

                if (disconnectUser != null)
                {
                    if (users.ContainsKey(disconnectUser.Id))
                    {
                        users.Remove(disconnectUser.Id);

                        var leaveMsg = new LeaveRoom()
                        {
                            UserInfo = new UserInfo() { Id = disconnectUser.Id }
                        };
                        await OnLeaveRoom(leaveMsg);
                    }
                }
            });

            Receive<LeaveRoom>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received LeaveRoom message: {0}", jsonString);

                if (users.ContainsKey(cmd.UserInfo.Id))
                {
                    users.Remove(cmd.UserInfo.Id);
                    await OnLeaveRoom(cmd);
                }
            });

            // Handle Tick message
            Receive<Tick>(_ => {
                log.Info("Tick event triggered");
                // Add your custom logic here to be executed every 10 seconds
            });
        }

        private void AddChatMessageToHistory(ChatMessage chatMessage)
        {
            chatHistory.Enqueue(chatMessage);
            while (chatHistory.Count > MaxChatHistoryCount)
            {
                chatHistory.TryDequeue(out _);
            }
        }

        private string GetChatHistoryAsJson()
        {
            return JsonSerializer.Serialize(chatHistory.ToList());
        }

        public async Task OnJoinRoom(RoomInfo roomInfo, UserInfo user, UpdateUserPos updateUserPos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnJoinRoom", roomInfo, user, updateUserPos);
            }
        }

        public async Task OnSyncRoom(UserInfo user, List<UpdateUserPos> updateUserPos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnSyncRoom", user, updateUserPos);
            }
        }

        public async Task OnLeaveRoom(LeaveRoom leaveRoom)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnLeaveRoom", leaveRoom);
            }
        }

        public async Task OnUpdateUserPos(UpdateUserPos updatePos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnUpdateUserPos", updatePos);
            }
        }

        public async Task OnChatMessage(ChatMessage chatMessage)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnChatMessage", chatMessage);
            }
        }

        // Define Tick message class
        public class Tick { }
    }
}



Info

OnUpdateUserPos에 botUpdateUserPos 를 이용해 Tick에서 특정반경내에서 알아서 움직이게 코드추가

Code Block
themeEmacs
linenumberstrue
collapsetrue
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;

using Akka.Actor;
using Akka.Event;

using BlazorChatApp.Shared;

using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;

namespace BlazorChatApp.Server.Hubs
{
    // Define Tick message class
    public class Tick { }

    public class RoomActor : ReceiveActor
    {
        private readonly ILoggingAdapter log = Context.GetLogger();

        public Dictionary<string, UpdateUserPos> users = new Dictionary<string, UpdateUserPos>();

        private string roomName;

        private int userAutoNo = 0;

        private readonly IServiceScopeFactory scopeFactory;

        private readonly ConcurrentQueue<ChatMessage> chatHistory = new ConcurrentQueue<ChatMessage>();

        private const int MaxChatHistoryCount = 50;

        private readonly UserInfo botUserInfo;
        private readonly UpdateUserPos botUpdateUserPos;

        Random random = new Random();

        public RoomActor(string _roomName, IServiceScopeFactory _scopeFactory)
        {
            scopeFactory = _scopeFactory;

            roomName = _roomName;

            log.Info($"Create Room{roomName}");

            string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

            // Schedule a timer to send a Tick message every 10 seconds
            Context.System.Scheduler.ScheduleTellRepeatedly(
                TimeSpan.FromSeconds(10),
                TimeSpan.FromSeconds(10),
                Self,
                new Tick(),
                Self
            );

            // Initialize bot user
            botUserInfo = new UserInfo()
            {
                Id = "bot-1",
                Name = "ChatBot-1",
                Color = RandomColor
            };

            botUpdateUserPos = new UpdateUserPos()
            {
                Id = botUserInfo.Id,
                Name = botUserInfo.Name,
                PosX = 250,
                PosY = 250,
                AbsPosX = 250,
                AbsPosY = 250,
                ConnectionId = "bot-connection"
            };

            users[botUserInfo.Id] = botUpdateUserPos;

            Receive<RoomCmd>(cmd => {
                log.Info("Received String message: {0}", cmd);
                //Sender.Tell(message);                
            });

            Receive<JoinRoom>(async cmd => {
                userAutoNo++;
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received JoinRoom message: {0}", jsonString);
                string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

                UserInfo userInfo = new UserInfo()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    Color = RandomColor
                };

                // Default Position
                double posx = random.Next(0, 300);
                double posy = random.Next(400, 550);

                UpdateUserPos updateUserPos = new UpdateUserPos()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    PosX = posx,
                    PosY = posy,
                    AbsPosX = posx,
                    AbsPosY = posy,
                    ConnectionId = cmd.ConnectionId
                };

                if (!users.ContainsKey(updateUserPos.Id))
                    users[cmd.UserInfo.Id] = updateUserPos;

                await OnJoinRoom(cmd.RoomInfo, userInfo, updateUserPos);
            });

            Receive<SyncRoom>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received SyncRoom message: {0}", jsonString);

                List<UpdateUserPos> updateUserPosList = users.Values.ToList();
                string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

                UserInfo userInfo = new UserInfo()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    Color = RandomColor
                };

                await OnSyncRoom(botUserInfo, updateUserPosList);

                await OnSyncRoom(userInfo, updateUserPosList);
            });

            Receive<ChatMessage>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received ChatMessage message: {0}", jsonString);

                ChatMessage chatMessage = new ChatMessage()
                {
                    From = cmd.From,
                    Message = cmd.Message
                };

                AddChatMessageToHistory(chatMessage);

                await OnChatMessage(chatMessage);
            });

            Receive<UpdateUserPos>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received UpdateUserPos message: {0}", jsonString);

                double AbsPosX = users[cmd.Id].PosX + cmd.PosX;
                double AbsPosY = users[cmd.Id].PosY + cmd.PosY;

                if (users.ContainsKey(cmd.Id))
                {
                    users[cmd.Id].PosX = AbsPosX;
                    users[cmd.Id].PosY = AbsPosY;
                    users[cmd.Id].AbsPosX = AbsPosX;
                    users[cmd.Id].AbsPosY = AbsPosY;
                }

                log.Info($"UpdateUser : X=>{users[cmd.Id].AbsPosX} Y=>{users[cmd.Id].AbsPosY}");

                UpdateUserPos updateUserPos = new UpdateUserPos()
                {
                    Id = cmd.Id,
                    Name = cmd.Name,
                    PosX = cmd.PosX,
                    PosY = cmd.PosY,
                    AbsPosX = AbsPosX,
                    AbsPosY = AbsPosY
                };

                await OnUpdateUserPos(updateUserPos);
            });

            Receive<Disconnect>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received Disconnect message: {0}", jsonString);
                var disconnectUser = users.Values.Where(e => e.ConnectionId == cmd.ConnectionId).FirstOrDefault();

                if (disconnectUser != null)
                {
                    if (users.ContainsKey(disconnectUser.Id))
                    {
                        users.Remove(disconnectUser.Id);

                        var leaveMsg = new LeaveRoom()
                        {
                            UserInfo = new UserInfo() { Id = disconnectUser.Id }
                        };
                        await OnLeaveRoom(leaveMsg);
                    }
                }
            });

            Receive<LeaveRoom>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received LeaveRoom message: {0}", jsonString);

                if (users.ContainsKey(cmd.UserInfo.Id))
                {
                    users.Remove(cmd.UserInfo.Id);
                    await OnLeaveRoom(cmd);
                }
            });

            // Handle Tick message
            Receive<Tick>(_ => {
                log.Info("Tick event triggered");

                // Move botUpdateUserPos within a specific range
                double moveX = random.NextDouble() * 20 - 10; // Move between -10 and 10
                double moveY = random.NextDouble() * 20 - 10; // Move between -10 and 10

                botUpdateUserPos.PosX += moveX;
                botUpdateUserPos.PosY += moveY;
                botUpdateUserPos.AbsPosX += moveX;
                botUpdateUserPos.AbsPosY += moveY;

                // Ensure bot stays within a specific range (e.g., 200 to 300 for both X and Y)
                botUpdateUserPos.PosX = Math.Clamp(botUpdateUserPos.PosX, 200, 300);
                botUpdateUserPos.PosY = Math.Clamp(botUpdateUserPos.PosY, 200, 300);
                botUpdateUserPos.AbsPosX = Math.Clamp(botUpdateUserPos.AbsPosX, 200, 300);
                botUpdateUserPos.AbsPosY = Math.Clamp(botUpdateUserPos.AbsPosY, 200, 300);

                // Update bot position
                Self.Tell(botUpdateUserPos);
            });
        }

        private void AddChatMessageToHistory(ChatMessage chatMessage)
        {
            chatHistory.Enqueue(chatMessage);
            while (chatHistory.Count > MaxChatHistoryCount)
            {
                chatHistory.TryDequeue(out _);
            }
        }

        private string GetChatHistoryAsJson()
        {
            return JsonSerializer.Serialize(chatHistory.ToList());
        }

        public async Task OnJoinRoom(RoomInfo roomInfo, UserInfo user, UpdateUserPos updateUserPos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnJoinRoom", roomInfo, user, updateUserPos);
            }
        }

        public async Task OnSyncRoom(UserInfo user, List<UpdateUserPos> updateUserPos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnSyncRoom", user, updateUserPos);
            }
        }

        public async Task OnLeaveRoom(LeaveRoom leaveRoom)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnLeaveRoom", leaveRoom);
            }
        }

        public async Task OnUpdateUserPos(UpdateUserPos updatePos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnUpdateUserPos", updatePos);
            }
        }

        public async Task OnChatMessage(ChatMessage chatMessage)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnChatMessage", chatMessage);
            }
        }
    }
}



Info

화면밖에 안나가게 ~ 반대로 움직일수있게 조절 한번에 움직이는 것은 5로 제약

Code Block
themeEmacs
linenumberstrue
collapsetrue
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;

using Akka.Actor;
using Akka.Event;

using BlazorChatApp.Shared;

using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;

namespace BlazorChatApp.Server.Hubs
{
    // Define Tick message class
    public class Tick { }

    public class RoomActor : ReceiveActor
    {
        private readonly ILoggingAdapter log = Context.GetLogger();

        public Dictionary<string, UpdateUserPos> users = new Dictionary<string, UpdateUserPos>();

        private string roomName;

        private int userAutoNo = 0;

        private readonly IServiceScopeFactory scopeFactory;

        private readonly ConcurrentQueue<ChatMessage> chatHistory = new ConcurrentQueue<ChatMessage>();

        private const int MaxChatHistoryCount = 50;

        private readonly UserInfo botUserInfo;
        private readonly UpdateUserPos botUpdateUserPos;

        Random random = new Random();

        public RoomActor(string _roomName, IServiceScopeFactory _scopeFactory)
        {
            scopeFactory = _scopeFactory;

            roomName = _roomName;

            log.Info($"Create Room{roomName}");

            string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

            // Schedule a timer to send a Tick message every 10 seconds
            Context.System.Scheduler.ScheduleTellRepeatedly(
                TimeSpan.FromSeconds(10),
                TimeSpan.FromSeconds(3),
                Self,
                new Tick(),
                Self
            );

            // Initialize bot user
            botUserInfo = new UserInfo()
            {
                Id = "bot-1",
                Name = "ChatBot-1",
                Color = RandomColor
            };

            botUpdateUserPos = new UpdateUserPos()
            {
                Id = botUserInfo.Id,
                Name = botUserInfo.Name,
                PosX = 250,
                PosY = 250,
                AbsPosX = 250,
                AbsPosY = 250,
                ConnectionId = "bot-connection"
            };

            users[botUserInfo.Id] = botUpdateUserPos;

            Receive<RoomCmd>(cmd => {
                log.Info("Received String message: {0}", cmd);
                //Sender.Tell(message);                
            });

            Receive<JoinRoom>(async cmd => {
                userAutoNo++;
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received JoinRoom message: {0}", jsonString);
                string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

                UserInfo userInfo = new UserInfo()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    Color = RandomColor
                };

                // Default Position
                double posx = random.Next(0, 300);
                double posy = random.Next(400, 550);

                UpdateUserPos updateUserPos = new UpdateUserPos()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    PosX = posx,
                    PosY = posy,
                    AbsPosX = posx,
                    AbsPosY = posy,
                    ConnectionId = cmd.ConnectionId
                };

                if (!users.ContainsKey(updateUserPos.Id))
                    users[cmd.UserInfo.Id] = updateUserPos;

                await OnJoinRoom(cmd.RoomInfo, userInfo, updateUserPos);
            });

            Receive<SyncRoom>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received SyncRoom message: {0}", jsonString);

                List<UpdateUserPos> updateUserPosList = users.Values.ToList();
                string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

                UserInfo userInfo = new UserInfo()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    Color = RandomColor
                };

                await OnSyncRoom(botUserInfo, updateUserPosList);

                await OnSyncRoom(userInfo, updateUserPosList);
            });

            Receive<ChatMessage>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received ChatMessage message: {0}", jsonString);

                ChatMessage chatMessage = new ChatMessage()
                {
                    From = cmd.From,
                    Message = cmd.Message
                };

                AddChatMessageToHistory(chatMessage);

                await OnChatMessage(chatMessage);
            });

            Receive<UpdateUserPos>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received UpdateUserPos message: {0}", jsonString);

                double AbsPosX = users[cmd.Id].PosX + cmd.PosX;
                double AbsPosY = users[cmd.Id].PosY + cmd.PosY;

                if (users.ContainsKey(cmd.Id))
                {
                    users[cmd.Id].PosX = AbsPosX;
                    users[cmd.Id].PosY = AbsPosY;
                    users[cmd.Id].AbsPosX = AbsPosX;
                    users[cmd.Id].AbsPosY = AbsPosY;
                }

                log.Info($"UpdateUser : X=>{users[cmd.Id].AbsPosX} Y=>{users[cmd.Id].AbsPosY}");

                UpdateUserPos updateUserPos = new UpdateUserPos()
                {
                    Id = cmd.Id,
                    Name = cmd.Name,
                    PosX = cmd.PosX,
                    PosY = cmd.PosY,
                    AbsPosX = AbsPosX,
                    AbsPosY = AbsPosY
                };

                await OnUpdateUserPos(updateUserPos);
            });

            Receive<Disconnect>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received Disconnect message: {0}", jsonString);
                var disconnectUser = users.Values.Where(e => e.ConnectionId == cmd.ConnectionId).FirstOrDefault();

                if (disconnectUser != null)
                {
                    if (users.ContainsKey(disconnectUser.Id))
                    {
                        users.Remove(disconnectUser.Id);

                        var leaveMsg = new LeaveRoom()
                        {
                            UserInfo = new UserInfo() { Id = disconnectUser.Id }
                        };
                        await OnLeaveRoom(leaveMsg);
                    }
                }
            });

            Receive<LeaveRoom>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received LeaveRoom message: {0}", jsonString);

                if (users.ContainsKey(cmd.UserInfo.Id))
                {
                    users.Remove(cmd.UserInfo.Id);
                    await OnLeaveRoom(cmd);
                }
            });

            // Handle Tick message
            Receive<Tick>(_ => {
                log.Info("Tick event triggered");

                // Move botUpdateUserPos within a specific range
                double moveX = random.NextDouble() * 10 - 5; // Move between -5 and 5
                double moveY = random.NextDouble() * 10 - 5; // Move between -5 and 5

                botUpdateUserPos.PosX += moveX;
                botUpdateUserPos.PosY += moveY;
                botUpdateUserPos.AbsPosX += moveX;
                botUpdateUserPos.AbsPosY += moveY;

                // Ensure bot stays within a specific range (e.g., 200 to 300 for both X and Y)
                if (botUpdateUserPos.PosX < 200 || botUpdateUserPos.PosX > 300)
                {
                    botUpdateUserPos.PosX -= moveX; // Reverse the movement
                    botUpdateUserPos.AbsPosX -= moveX;
                }

                if (botUpdateUserPos.PosY < 200 || botUpdateUserPos.PosY > 300)
                {
                    botUpdateUserPos.PosY -= moveY; // Reverse the movement
                    botUpdateUserPos.AbsPosY -= moveY;
                }

                // Update bot position
                Self.Tell(botUpdateUserPos);
            });
        }

        private void AddChatMessageToHistory(ChatMessage chatMessage)
        {
            chatHistory.Enqueue(chatMessage);
            while (chatHistory.Count > MaxChatHistoryCount)
            {
                chatHistory.TryDequeue(out _);
            }
        }

        private string GetChatHistoryAsJson()
        {
            return JsonSerializer.Serialize(chatHistory.ToList());
        }

        public async Task OnJoinRoom(RoomInfo roomInfo, UserInfo user, UpdateUserPos updateUserPos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnJoinRoom", roomInfo, user, updateUserPos);
            }
        }

        public async Task OnSyncRoom(UserInfo user, List<UpdateUserPos> updateUserPos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnSyncRoom", user, updateUserPos);
            }
        }

        public async Task OnLeaveRoom(LeaveRoom leaveRoom)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnLeaveRoom", leaveRoom);
            }
        }

        public async Task OnUpdateUserPos(UpdateUserPos updatePos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnUpdateUserPos", updatePos);
            }
        }

        public async Task OnChatMessage(ChatMessage chatMessage)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnChatMessage", chatMessage);
            }
        }
    }
}






Info

소원을 들어주는 메타공간 새해복 많이 받으세요 메시지를 포함 다양한 새해 인사를 랜덤하게 덕담으로

Code Block
themeEmacs
linenumberstrue
collapsetrue
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;

using Akka.Actor;
using Akka.Event;

using BlazorChatApp.Shared;

using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;

namespace BlazorChatApp.Server.Hubs
{
    // Define Tick message class
    public class Tick { }

    public class RoomActor : ReceiveActor
    {
        private readonly ILoggingAdapter log = Context.GetLogger();

        public Dictionary<string, UpdateUserPos> users = new Dictionary<string, UpdateUserPos>();

        private string roomName;

        private int userAutoNo = 0;

        private readonly IServiceScopeFactory scopeFactory;

        private readonly ConcurrentQueue<ChatMessage> chatHistory = new ConcurrentQueue<ChatMessage>();

        private const int MaxChatHistoryCount = 50;

        private readonly UserInfo botUserInfo;
        private readonly UpdateUserPos botUpdateUserPos;

        Random random = new Random();

        public RoomActor(string _roomName, IServiceScopeFactory _scopeFactory)
        {
            scopeFactory = _scopeFactory;

            roomName = _roomName;

            log.Info($"Create Room{roomName}");

            string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

            // Schedule a timer to send a Tick message every 10 seconds
            Context.System.Scheduler.ScheduleTellRepeatedly(
                TimeSpan.FromSeconds(10),
                TimeSpan.FromSeconds(3),
                Self,
                new Tick(),
                Self
            );

            // Initialize bot user
            botUserInfo = new UserInfo()
            {
                Id = "bot-1",
                Name = "ChatBot-1",
                Color = RandomColor
            };

            botUpdateUserPos = new UpdateUserPos()
            {
                Id = botUserInfo.Id,
                Name = botUserInfo.Name,
                PosX = 250,
                PosY = 250,
                AbsPosX = 250,
                AbsPosY = 250,
                ConnectionId = "bot-connection"
            };

            users[botUserInfo.Id] = botUpdateUserPos;

            Receive<RoomCmd>(cmd => {
                log.Info("Received String message: {0}", cmd);
                //Sender.Tell(message);                
            });

            Receive<JoinRoom>(async cmd => {
                userAutoNo++;
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received JoinRoom message: {0}", jsonString);
                string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

                UserInfo userInfo = new UserInfo()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    Color = RandomColor
                };

                // Default Position
                double posx = random.Next(0, 300);
                double posy = random.Next(400, 550);

                UpdateUserPos updateUserPos = new UpdateUserPos()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    PosX = posx,
                    PosY = posy,
                    AbsPosX = posx,
                    AbsPosY = posy,
                    ConnectionId = cmd.ConnectionId
                };

                if (!users.ContainsKey(updateUserPos.Id))
                    users[cmd.UserInfo.Id] = updateUserPos;

                await OnJoinRoom(cmd.RoomInfo, userInfo, updateUserPos);
            });

            Receive<SyncRoom>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received SyncRoom message: {0}", jsonString);

                List<UpdateUserPos> updateUserPosList = users.Values.ToList();
                string RandomColor = string.Format("#{0:X6}", random.Next(0xFFFFFF));

                UserInfo userInfo = new UserInfo()
                {
                    Id = cmd.UserInfo.Id,
                    Name = $"User-{userAutoNo}",
                    Color = RandomColor
                };

                await OnSyncRoom(botUserInfo, updateUserPosList);

                await OnSyncRoom(userInfo, updateUserPosList);
            });

            Receive<ChatMessage>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received ChatMessage message: {0}", jsonString);

                ChatMessage chatMessage = new ChatMessage()
                {
                    From = cmd.From,
                    Message = cmd.Message
                };

                AddChatMessageToHistory(chatMessage);

                await OnChatMessage(chatMessage);
            });

            Receive<UpdateUserPos>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received UpdateUserPos message: {0}", jsonString);

                double AbsPosX = users[cmd.Id].PosX + cmd.PosX;
                double AbsPosY = users[cmd.Id].PosY + cmd.PosY;

                if (users.ContainsKey(cmd.Id))
                {
                    users[cmd.Id].PosX = AbsPosX;
                    users[cmd.Id].PosY = AbsPosY;
                    users[cmd.Id].AbsPosX = AbsPosX;
                    users[cmd.Id].AbsPosY = AbsPosY;
                }

                log.Info($"UpdateUser : X=>{users[cmd.Id].AbsPosX} Y=>{users[cmd.Id].AbsPosY}");

                UpdateUserPos updateUserPos = new UpdateUserPos()
                {
                    Id = cmd.Id,
                    Name = cmd.Name,
                    PosX = cmd.PosX,
                    PosY = cmd.PosY,
                    AbsPosX = AbsPosX,
                    AbsPosY = AbsPosY
                };

                await OnUpdateUserPos(updateUserPos);
            });

            Receive<Disconnect>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received Disconnect message: {0}", jsonString);
                var disconnectUser = users.Values.Where(e => e.ConnectionId == cmd.ConnectionId).FirstOrDefault();

                if (disconnectUser != null)
                {
                    if (users.ContainsKey(disconnectUser.Id))
                    {
                        users.Remove(disconnectUser.Id);

                        var leaveMsg = new LeaveRoom()
                        {
                            UserInfo = new UserInfo() { Id = disconnectUser.Id }
                        };
                        await OnLeaveRoom(leaveMsg);
                    }
                }
            });

            Receive<LeaveRoom>(async cmd => {
                string jsonString = JsonSerializer.Serialize(cmd);
                log.Info("Received LeaveRoom message: {0}", jsonString);

                if (users.ContainsKey(cmd.UserInfo.Id))
                {
                    users.Remove(cmd.UserInfo.Id);
                    await OnLeaveRoom(cmd);
                }
            });

            // Handle Tick message
            Receive<Tick>(async _ => {
                log.Info("Tick event triggered");

                // Move botUpdateUserPos within a specific range
                double moveX = random.NextDouble() * 40 - 20; // Move between -20 and 20
                double moveY = 0;

                // 25% chance to move in Y direction
                if (random.Next(4) == 0)
                {
                    moveY = random.NextDouble() * 40 - 20; // Move between -20 and 20
                }

                double newPosX = botUpdateUserPos.PosX + moveX;
                double newPosY = botUpdateUserPos.PosY + moveY;

                // Ensure bot stays within the screen boundaries (e.g., 0 to 800 for X and 0 to 600 for Y)
                if (newPosX >= 0 && newPosX <= 800 && newPosY >= 0 && newPosY <= 600)
                {
                    botUpdateUserPos.PosX = newPosX;
                    botUpdateUserPos.PosY = newPosY;
                    botUpdateUserPos.AbsPosX += moveX;
                    botUpdateUserPos.AbsPosY += moveY;

                    // Update bot position
                    Self.Tell(botUpdateUserPos);
                }

                // Send random New Year greeting
                string[] greetings = new string[]
                {
                    "새해 복 많이 받으세요!",
                    "행복한 새해 되세요!",
                    "건강하고 행복한 한 해 되세요!",
                    "새해에는 모든 소원이 이루어지길 바랍니다!",
                    "희망찬 새해 되세요!"
                };

                string randomGreeting = greetings[random.Next(greetings.Length)];

                ChatMessage greetingMessage = new ChatMessage()
                {
                    From = botUserInfo.Name,
                    Message = randomGreeting
                };

                AddChatMessageToHistory(greetingMessage);

                await OnChatMessage(greetingMessage);
            });
        }

        private void AddChatMessageToHistory(ChatMessage chatMessage)
        {
            chatHistory.Enqueue(chatMessage);
            while (chatHistory.Count > MaxChatHistoryCount)
            {
                chatHistory.TryDequeue(out _);
            }
        }

        private string GetChatHistoryAsJson()
        {
            return JsonSerializer.Serialize(chatHistory.ToList());
        }

        public async Task OnJoinRoom(RoomInfo roomInfo, UserInfo user, UpdateUserPos updateUserPos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnJoinRoom", roomInfo, user, updateUserPos);
            }
        }

        public async Task OnSyncRoom(UserInfo user, List<UpdateUserPos> updateUserPos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnSyncRoom", user, updateUserPos);
            }
        }

        public async Task OnLeaveRoom(LeaveRoom leaveRoom)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnLeaveRoom", leaveRoom);
            }
        }

        public async Task OnUpdateUserPos(UpdateUserPos updatePos)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnUpdateUserPos", updatePos);
            }
        }

        public async Task OnChatMessage(ChatMessage chatMessage)
        {
            using (var scope = scopeFactory.CreateScope())
            {
                var wsHub = scope.ServiceProvider.GetRequiredService<IHubContext<ChatHub>>();
                await wsHub.Clients.All.SendAsync("OnChatMessage", chatMessage);
            }
        }
    }
}






Info

명언중에서 새해 힘찬 목표를 가질수 있는 단어로 다시구성

Code Block
themeEmacs
linenumberstrue
collapsetrue
string[] quotes = new string[]
{
    "새해에는 목표를 향해 힘차게 나아가세요!",
    "새해에는 더 큰 도전을 향해 나아가세요!",
    "새해에는 꿈을 이루기 위해 최선을 다하세요!",
    "새해에는 새로운 목표를 세우고 달성하세요!",
    "새해에는 더 높은 곳을 향해 도전하세요!",
    "새해에는 자신을 믿고 목표를 이루세요!",
    "새해에는 더 큰 성취를 이루세요!",
    "새해에는 끊임없이 도전하세요!",
    "새해에는 목표를 향해 한 걸음 더 나아가세요!",
    "새해에는 더 큰 꿈을 꾸고 이루세요!",
    "새해에는 새로운 시작을 맞이하세요!",
    "새해에는 더 큰 목표를 세우고 달성하세요!",
    "새해에는 더 많은 성취를 이루세요!",
    "새해에는 더 큰 도전을 향해 나아가세요!",
    "새해에는 목표를 향해 힘차게 나아가세요!",
    "새해에는 꿈을 이루기 위해 최선을 다하세요!",
    "새해에는 새로운 목표를 세우고 달성하세요!",
    "새해에는 더 높은 곳을 향해 도전하세요!",
    "새해에는 자신을 믿고 목표를 이루세요!",
    "새해에는 더 큰 성취를 이루세요!",
    "새해에는 끊임없이 도전하세요!",
    "새해에는 목표를 향해 한 걸음 더 나아가세요!",
    "새해에는 더 큰 꿈을 꾸고 이루세요!",
    "새해에는 새로운 시작을 맞이하세요!",
    "새해에는 더 큰 목표를 세우고 달성하세요!",
    "새해에는 더 많은 성취를 이루세요!",
    "새해에는 더 큰 도전을 향해 나아가세요!",
    "새해에는 목표를 향해 힘차게 나아가세요!",
    "새해에는 꿈을 이루기 위해 최선을 다하세요!",
    "새해에는 새로운 목표를 세우고 달성하세요!",
    "새해에는 더 높은 곳을 향해 도전하세요!",
    "새해에는 자신을 믿고 목표를 이루세요!",
    "새해에는 더 큰 성취를 이루세요!",
    "새해에는 끊임없이 도전하세요!",
    "새해에는 목표를 향해 한 걸음 더 나아가세요!",
    "새해에는 더 큰 꿈을 꾸고 이루세요!",
    "새해에는 새로운 시작을 맞이하세요!",
    "새해에는 더 큰 목표를 세우고 달성하세요!",
    "새해에는 더 많은 성취를 이루세요!",
    "새해에는 더 큰 도전을 향해 나아가세요!",
    "새해에는 목표를 향해 힘차게 나아가세요!",
    "새해에는 꿈을 이루기 위해 최선을 다하세요!",
    "새해에는 새로운 목표를 세우고 달성하세요!",
    "새해에는 더 높은 곳을 향해 도전하세요!",
    "새해에는 자신을 믿고 목표를 이루세요!",
    "새해에는 더 큰 성취를 이루세요!",
    "새해에는 끊임없이 도전하세요!",
    "새해에는 목표를 향해 한 걸음 더 나아가세요!",
    "새해에는 더 큰 꿈을 꾸고 이루세요!",
    "새해에는 새로운 시작을 맞이하세요!"
};





Info

  DrawImageAsync img-chatbox 에서 , Chatbox를 그리니 이미지가 뭉개집니다. 이미지가아닌 도형을 말풍선처럼 그려 글자 크기에 맞게 표현하는것로 개선

Code Block
themeEmacs
linenumberstrue
collapsetrue
public async ValueTask Render(SceneContext game, Canvas2DContext context)
{
    string NameText = Name;

    if (!string.IsNullOrEmpty(ChatMessage))
    {
        NameText = NameText + "-" + ChatMessage;
        ChatViewTime--;
    }

    if (ChatViewTime < 0)
    {
        ChatMessage = string.Empty;
    }

    await context.SaveAsync();

    // 닉네임
    await context.SetFontAsync("14px 바탕체");
    await context.SetFillStyleAsync("Blue");
    await context.FillTextAsync(Name, _transform.Local.Position.X + 10, _transform.Local.Position.Y + 75);

    if (!string.IsNullOrEmpty(ChatMessage))
    {
        // 채팅 Box
        int padding = 10;
        int dynamicWidth = 50 + ((ChatMessage.Length - 3) * 15);
        int dynamicHeight = 50;

        float boxX = _transform.Local.Position.X + 20;
        float boxY = _transform.Local.Position.Y - 40;

        // 말풍선 배경
        await context.SetFillStyleAsync("White");
        await context.FillRectAsync(boxX, boxY, dynamicWidth, dynamicHeight);

        // 말풍선 테두리
        await context.SetStrokeStyleAsync("Black");
        await context.StrokeRectAsync(boxX, boxY, dynamicWidth, dynamicHeight);

        // 채팅 메시지
        await context.SetFillStyleAsync("Black");
        await context.FillTextAsync(ChatMessage, boxX + padding, boxY + padding + 20);
    }

    if (_isMine)
    {
        // 추가적인 렌더링 로직이 필요하다면 여기에 작성
    }

    await context.RestoreAsync();
}




Info

사각형이 아니라 말풍선처럼 타워에 꼭지점도 표현

Code Block
themeEmacs
linenumberstrue
collapsetrue
public async ValueTask Render(SceneContext game, Canvas2DContext context)
{
    string NameText = Name;

    if (!string.IsNullOrEmpty(ChatMessage))
    {
        NameText = NameText + "-" + ChatMessage;
        ChatViewTime--;
    }

    if (ChatViewTime < 0)
    {
        ChatMessage = string.Empty;
    }

    await context.SaveAsync();

    // 닉네임
    await context.SetFontAsync("14px 바탕체");
    await context.SetFillStyleAsync("Blue");
    await context.FillTextAsync(Name, _transform.Local.Position.X + 10, _transform.Local.Position.Y + 75);

    if (!string.IsNullOrEmpty(ChatMessage))
    {
        // 채팅 Box
        int padding = 10;
        int dynamicWidth = 50 + ((ChatMessage.Length - 3) * 15);
        int dynamicHeight = 50;

        float boxX = _transform.Local.Position.X + 20;
        float boxY = _transform.Local.Position.Y - 40;
        float tailWidth = 10;
        float tailHeight = 10;

        // 말풍선 배경
        await context.BeginPathAsync();
        await context.MoveToAsync(boxX, boxY);
        await context.LineToAsync(boxX + dynamicWidth, boxY);
        await context.LineToAsync(boxX + dynamicWidth, boxY + dynamicHeight);
        await context.LineToAsync(boxX + dynamicWidth / 2 + tailWidth, boxY + dynamicHeight);
        await context.LineToAsync(boxX + dynamicWidth / 2, boxY + dynamicHeight + tailHeight);
        await context.LineToAsync(boxX + dynamicWidth / 2 - tailWidth, boxY + dynamicHeight);
        await context.LineToAsync(boxX, boxY + dynamicHeight);
        await context.ClosePathAsync();
        await context.SetFillStyleAsync("White");
        await context.FillAsync();

        // 말풍선 테두리
        await context.SetStrokeStyleAsync("Black");
        await context.StrokeAsync();

        // 채팅 메시지
        await context.SetFillStyleAsync("Black");
        await context.FillTextAsync(ChatMessage, boxX + padding, boxY + padding + 20);
    }

    if (_isMine)
    {
        // 추가적인 렌더링 로직이 필요하다면 여기에 작성
    }

    await context.RestoreAsync();
}



Info


Code Block
themeEmacs
linenumberstrue
collapsetrue



Info


Code Block
themeEmacs
linenumberstrue
collapsetrue



Info


Code Block
themeEmacs
linenumberstrue
collapsetrue



Info


Code Block
themeEmacs
linenumberstrue
collapsetrue



Info


Code Block
themeEmacs
linenumberstrue
collapsetrue



Info


Code Block
themeEmacs
linenumberstrue
collapsetrue



Info


Code Block
themeEmacs
linenumberstrue
collapsetrue








Info


Code Block
themeEmacs
linenumberstrue
collapsetrue