From 15bfdc56e310c5339bf1c3bad8e1148402ac09d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20N=C3=A6rvig=20W=C3=B8hlk?= Date: Tue, 14 Jan 2025 19:11:25 +0100 Subject: [PATCH] feat: bot control --- .../Controllers/BotsController.cs | 63 +++++ .../Models/Views/BotsViewModels.cs | 17 ++ Areas/Housekeeping/Views/Bots/Index.cshtml | 230 ++++++++++++++++++ .../Views}/Shared/_Housekeeping.cshtml | 2 + Controllers/Api/HotelApiController.cs | 2 +- Data/DataContext.cs | 1 + Data/Models/Bots.cs | 66 +++++ KeplerCMS.csproj | 6 +- Models/Enums/CommandQueueType.cs | 5 +- Models/Enums/Fuse.cs | 4 +- Services/Implementations/BotService.cs | 122 ++++++++++ Services/Implementations/RoomService.cs | 5 + Services/Interfaces/IBotService.cs | 20 ++ Services/Interfaces/IRoomService.cs | 1 + Startup.cs | 1 + Views/Groups/BadgeEditor.cshtml | 1 + Views/Profile/Index.cshtml | 1 + Views/Shared/_Layout.cshtml | 13 +- wwwroot/js/habbo.js | 11 + 19 files changed, 561 insertions(+), 10 deletions(-) create mode 100644 Areas/Housekeeping/Controllers/BotsController.cs create mode 100644 Areas/Housekeeping/Models/Views/BotsViewModels.cs create mode 100644 Areas/Housekeeping/Views/Bots/Index.cshtml rename {Views => Areas/Housekeeping/Views}/Shared/_Housekeeping.cshtml (98%) create mode 100644 Data/Models/Bots.cs create mode 100644 Services/Implementations/BotService.cs create mode 100644 Services/Interfaces/IBotService.cs diff --git a/Areas/Housekeeping/Controllers/BotsController.cs b/Areas/Housekeeping/Controllers/BotsController.cs new file mode 100644 index 0000000..c1ede5c --- /dev/null +++ b/Areas/Housekeeping/Controllers/BotsController.cs @@ -0,0 +1,63 @@ +using Microsoft.AspNetCore.Mvc; +using KeplerCMS.Filters; +using KeplerCMS.Services.Interfaces; +using System.Threading.Tasks; +using KeplerCMS.Areas.Housekeeping.Models.Views; +using KeplerCMS.Data.Models; +using KeplerCMS.Models; +using KeplerCMS.Models.Enums; + +namespace KeplerCMS.Areas.Housekeeping +{ + [Area("Housekeeping")] + public class BotsController : Controller + { + private readonly ICommandQueueService _commandQueueService; + private readonly IBotService _botService; + private readonly IRoomService _roomService; + + public BotsController(ICommandQueueService commandQueueService, IBotService botService, IRoomService roomService) + { + _commandQueueService = commandQueueService; + _botService = botService; + _roomService = roomService; + } + + + + [HousekeepingFilter(Fuse.fuse_bots)] + public async Task GetAllPublicRooms() + { + var rooms = await _roomService.GetPublicRooms(); + + return Json(rooms); + } + + [HousekeepingFilter(Fuse.fuse_bots)] + public async Task GetBot(int id) + { + var bot = await _botService.Get(id); + + return Json(bot); + } + + + [HousekeepingFilter(Fuse.fuse_bots)] + public async Task UpdateBot([FromBody] Bots bot) + { + var success = await _botService.UpdateBot(bot); + + return Json(success); + } + + + [HousekeepingFilter(Fuse.fuse_bots)] + public async Task Index(string Message = null) + { + ViewBag.Message = Message; + var bots = await _botService.GetAllBots(); + + return View(new BotsListView { Bots = bots }); + } + } +} diff --git a/Areas/Housekeeping/Models/Views/BotsViewModels.cs b/Areas/Housekeeping/Models/Views/BotsViewModels.cs new file mode 100644 index 0000000..e662e65 --- /dev/null +++ b/Areas/Housekeeping/Models/Views/BotsViewModels.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; +using KeplerCMS.Data.Models; +using KeplerCMS.Models; + +namespace KeplerCMS.Areas.Housekeeping.Models.Views +{ + public class BotsListView + { + public IEnumerable Bots { get; set; } + } + + +} diff --git a/Areas/Housekeeping/Views/Bots/Index.cshtml b/Areas/Housekeeping/Views/Bots/Index.cshtml new file mode 100644 index 0000000..c019106 --- /dev/null +++ b/Areas/Housekeeping/Views/Bots/Index.cshtml @@ -0,0 +1,230 @@ +@model KeplerCMS.Areas.Housekeeping.Models.Views.BotsListView + +@{ + ViewBag.Title = "Bots"; +} + +

@ViewBag.Title

+

+ Here you can see a list of all the bots on the hotel. +

+@if (ViewBag.Message != null) +{ +

@ViewBag.Message

+} + + + + + + + + + + @{ + foreach (var bot in Model.Bots) + { + + + + + + } + } + +
RoomNameActions
@bot.Room.Name@bot.Name + +
+ + + + +@section scripts { + +} \ No newline at end of file diff --git a/Views/Shared/_Housekeeping.cshtml b/Areas/Housekeeping/Views/Shared/_Housekeeping.cshtml similarity index 98% rename from Views/Shared/_Housekeeping.cshtml rename to Areas/Housekeeping/Views/Shared/_Housekeeping.cshtml index b2576ea..ba29295 100644 --- a/Views/Shared/_Housekeeping.cshtml +++ b/Areas/Housekeeping/Views/Shared/_Housekeeping.cshtml @@ -30,6 +30,7 @@ { "/housekeeping/messengercampaign", HousekeepingMenu.AdminTools }, { "/housekeeping/settings", HousekeepingMenu.AdminTools }, { "/housekeeping/auditlog", HousekeepingMenu.AdminTools }, + { "/housekeeping/bots", HousekeepingMenu.AdminTools }, { "/housekeeping/rewards", HousekeepingMenu.AdminTools }, }; @@ -117,6 +118,7 @@ @await menuHelper.Render("Audit log", Url.Action("Index", "AuditLog"), new List { Fuse.fuse_administrator_access }) @await menuHelper.Render("Reward management", Url.Action("Index", "Rewards"), new List { Fuse.housekeeping_rewards }) @await menuHelper.Render("Catalogue", Url.Action("Index", "Catalogue"), new List { Fuse.fuse_administrator_access }) + @await menuHelper.Render("Bots", Url.Action("Index", "Bots"), new List { Fuse.fuse_bots }) diff --git a/Controllers/Api/HotelApiController.cs b/Controllers/Api/HotelApiController.cs index 9176337..7178f5f 100644 --- a/Controllers/Api/HotelApiController.cs +++ b/Controllers/Api/HotelApiController.cs @@ -71,7 +71,7 @@ public async Task UserSearch(string user) [Route("components/roomNavigation")] public IActionResult RoomNavigation(int roomId, string roomType) { - _commandQueueService.QueueCommand(Models.Enums.CommandQueueType.roomForward, new Models.CommandTemplate { UserId = int.Parse(User.Identity.Name), RoomId = roomId, RoomType = roomType }); + _commandQueueService.QueueCommand(Models.Enums.CommandQueueType.room_forward, new Models.CommandTemplate { UserId = int.Parse(User.Identity.Name), RoomId = roomId, RoomType = roomType }); return Content("ok"); } diff --git a/Data/DataContext.cs b/Data/DataContext.cs index c17c63f..b6b474a 100644 --- a/Data/DataContext.cs +++ b/Data/DataContext.cs @@ -52,6 +52,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) } public DbSet Users { get; set; } + public DbSet Bots { get; set; } public DbSet CommandQueue { get; set; } public DbSet Menu { get; set; } public DbSet Containers { get; set; } diff --git a/Data/Models/Bots.cs b/Data/Models/Bots.cs new file mode 100644 index 0000000..c7ebb8c --- /dev/null +++ b/Data/Models/Bots.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Threading.Tasks; + +namespace KeplerCMS.Data.Models +{ + [Table("rooms_bots")] + public class Bots + { + [Key] + [Column("id")] + public int Id { get; set; } + + [Column("name")] + [NotNull] + public string Name { get; set; } + + [Column("mission")] + [NotNull] + public string Mission { get; set; } + + [Column("x")] + public int X { get; set; } + + [Column("y")] + public int Y { get; set; } + + [Column("start_look")] + [NotNull] + public string StartLook { get; set; } + + [Column("figure")] + [NotNull] + public string figure { get; set; } + + [Column("walkspace")] + [NotNull] + public string Walkspace { get; set; } + + [Column("room_id")] + public int RoomId { get; set; } + + [Column("speech")] + [NotNull] + public string Speech { get; set; } + + [Column("response")] + [NotNull] + public string Response { get; set; } + + [Column("unrecognised_response")] + [NotNull] + public string UnrecognisedResponse { get; set; } + + [Column("hand_items")] + [NotNull] + public string HandItems { get; set; } + + [NotMapped] + public Rooms Room { get; set; } + } +} diff --git a/KeplerCMS.csproj b/KeplerCMS.csproj index 7d0e055..48de471 100644 --- a/KeplerCMS.csproj +++ b/KeplerCMS.csproj @@ -115,7 +115,11 @@ - + + + + + diff --git a/Models/Enums/CommandQueueType.cs b/Models/Enums/CommandQueueType.cs index 97b14b8..8372918 100644 --- a/Models/Enums/CommandQueueType.cs +++ b/Models/Enums/CommandQueueType.cs @@ -12,12 +12,13 @@ public enum CommandQueueType reduce_credits, send_friend_request, purchase_furni, - roomForward, + room_forward, campaign, remote_alert, remote_ban, remote_kick, update_room, - update_infobus + update_infobus, + reset_bots } } diff --git a/Models/Enums/Fuse.cs b/Models/Enums/Fuse.cs index f6458ae..cd18b7f 100644 --- a/Models/Enums/Fuse.cs +++ b/Models/Enums/Fuse.cs @@ -44,7 +44,9 @@ public enum Fuse [Description("housekeeping_rewards")] housekeeping_rewards, [Description("fuse_see_chat_log_link")] - fuse_see_chat_log_link + fuse_see_chat_log_link, + [Description("fuse_bots")] + fuse_bots } } diff --git a/Services/Implementations/BotService.cs b/Services/Implementations/BotService.cs new file mode 100644 index 0000000..8989cc7 --- /dev/null +++ b/Services/Implementations/BotService.cs @@ -0,0 +1,122 @@ +using KeplerCMS.Data; +using KeplerCMS.Data.Models; +using KeplerCMS.Models; +using KeplerCMS.Models.Enums; +using KeplerCMS.Services.Interfaces; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using KeplerCMS.Areas.Housekeeping.Models.Views; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using JsonSerializer = System.Text.Json.JsonSerializer; + +namespace KeplerCMS.Services +{ + public class BotService : IBotService + { + private readonly DataContext _context; + private readonly IRoomService _roomService; + private readonly ICommandQueueService _commandQueueService; + + public BotService(DataContext context, IRoomService roomService, ICommandQueueService commandQueueService) + { + _roomService = roomService; + _context = context; + _commandQueueService = commandQueueService; + } + + public async Task> GetForRoom(int roomId) + { + return await _context.Bots.Where(x => x.RoomId == roomId).ToListAsync(); + } + + public async Task Get(int botId) + { + return await _context.Bots.FirstOrDefaultAsync(x => x.Id == botId); + } + + public async Task> GetAllBots() + { + var allBots = await _context.Bots.ToListAsync(); + var allBotsWithRooms = new List(); + foreach (var bot in allBots) + { + var room = await _roomService.GetRoom(bot.RoomId); + if (room == null) continue; + bot.Room = room; + allBotsWithRooms.Add(bot); + } + return allBotsWithRooms; + } + + public async Task AddBot(Bots bot) + { + _context.Bots.Add(bot); + await _context.SaveChangesAsync(); + + return true; + } + + [HttpPost] + public async Task UpdateBot(Bots bot) + { + + var botData = await Get(bot.Id); + if (botData == null) return false; + var oldBotRoomId = botData.RoomId; + botData.Name = bot.Name; + botData.Mission = bot.Mission ?? ""; + botData.X = bot.X; + botData.Y = bot.Y; + botData.StartLook = bot.StartLook; + botData.figure = bot.figure; + botData.Walkspace = bot.Walkspace; + botData.RoomId = bot.RoomId; + botData.Speech = bot.Speech ?? "";; + botData.Response = bot.Response ?? "";; + botData.UnrecognisedResponse = bot.UnrecognisedResponse ?? "";; + botData.HandItems = bot.HandItems ?? "";; + + try + { + _context.Bots.Update(botData); + + await _context.SaveChangesAsync(); + + } catch { + return false; + } + + // TODO: Fix this shit + + if (oldBotRoomId != botData.RoomId) + { + _commandQueueService.QueueCommand(CommandQueueType.reset_bots, new CommandTemplate { RoomId = oldBotRoomId}); + _commandQueueService.QueueCommand(CommandQueueType.reset_bots, new CommandTemplate { RoomId = bot.RoomId}); + } + else + { + _commandQueueService.QueueCommand(CommandQueueType.reset_bots, new CommandTemplate { RoomId = bot.RoomId}); + } + + + + return true; + } + + public async Task DeleteBot(int botId) + { + var bot = await Get(botId); + if (bot == null) return false; + + _context.Bots.Remove(bot); + await _context.SaveChangesAsync(); + + return true; + } + } +} diff --git a/Services/Implementations/RoomService.cs b/Services/Implementations/RoomService.cs index 9cabf39..9d01d96 100644 --- a/Services/Implementations/RoomService.cs +++ b/Services/Implementations/RoomService.cs @@ -25,6 +25,11 @@ public RoomService(ICommandQueueService commandQueueService, DataContext context _context = context; } + public async Task> GetPublicRooms() + { + return await _context.Rooms.Where(s => s.OwnerId == 0).ToListAsync(); + } + public async Task> GetRoomsByOwner(int ownerId) { return await _context.Rooms.Where(s => s.OwnerId == ownerId).ToListAsync(); diff --git a/Services/Interfaces/IBotService.cs b/Services/Interfaces/IBotService.cs new file mode 100644 index 0000000..fb065e1 --- /dev/null +++ b/Services/Interfaces/IBotService.cs @@ -0,0 +1,20 @@ +using System.Collections; +using System.Collections.Generic; +using System.Threading.Tasks; +using KeplerCMS.Areas.Housekeeping.Models.Views; +using KeplerCMS.Data.Models; +using KeplerCMS.Models; +using KeplerCMS.Models.Enums; + +namespace KeplerCMS.Services.Interfaces +{ + public interface IBotService + { + public Task> GetForRoom(int roomId); + public Task Get(int botId); + public Task> GetAllBots(); + public Task AddBot(Bots bot); + public Task UpdateBot(Bots bot); + public Task DeleteBot(int botId); + } +} diff --git a/Services/Interfaces/IRoomService.cs b/Services/Interfaces/IRoomService.cs index ff1d92e..8db5b3f 100644 --- a/Services/Interfaces/IRoomService.cs +++ b/Services/Interfaces/IRoomService.cs @@ -7,6 +7,7 @@ namespace KeplerCMS.Services.Interfaces { public interface IRoomService { + Task> GetPublicRooms(); Task> GetRoomsByOwner(int ownerId); Task Search(string search, int take, int skip); Task UpdateRoom(RoomsUpdateModel model); diff --git a/Startup.cs b/Startup.cs index ae47b9b..5349c90 100644 --- a/Startup.cs +++ b/Startup.cs @@ -119,6 +119,7 @@ public void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddMjmlServices(o => { diff --git a/Views/Groups/BadgeEditor.cshtml b/Views/Groups/BadgeEditor.cshtml index 9ebb6ba..c3c668d 100644 --- a/Views/Groups/BadgeEditor.cshtml +++ b/Views/Groups/BadgeEditor.cshtml @@ -34,6 +34,7 @@ window.RufflePlayer = window.RufflePlayer || {}; window.RufflePlayer.config = { "autoplay": "auto", + "defaultFonts": ["Verdana"], }; window.addEventListener("load", (event) => { const ruffle = window.RufflePlayer.newest(); diff --git a/Views/Profile/Index.cshtml b/Views/Profile/Index.cshtml index 1e1bbfd..04f7fc8 100644 --- a/Views/Profile/Index.cshtml +++ b/Views/Profile/Index.cshtml @@ -204,6 +204,7 @@ window.RufflePlayer = window.RufflePlayer || {}; window.RufflePlayer.config = { "autoplay": "auto", + "defaultFonts": ["Verdana"], }; window.addEventListener("load", (event) => { const ruffle = window.RufflePlayer.newest(); diff --git a/Views/Shared/_Layout.cshtml b/Views/Shared/_Layout.cshtml index 6265394..17e7083 100644 --- a/Views/Shared/_Layout.cshtml +++ b/Views/Shared/_Layout.cshtml @@ -16,13 +16,15 @@ - + + + Habbo ~ @ViewData["Title"] - + - - - + + + @RenderSection("Styles", required: false) diff --git a/wwwroot/js/habbo.js b/wwwroot/js/habbo.js index 2f79e32..ef22491 100644 --- a/wwwroot/js/habbo.js +++ b/wwwroot/js/habbo.js @@ -108,6 +108,17 @@ function openEmptyHabboWindow(target) { return _openHabboWindow('', target); } function _isHabboPopupOpen() { return openedHabbo && !openedHabbo.closed && openedHabbo.focus; } function roomForward(link, roomId, roomType) { + + if(document.isHabboOnline) { + fetch(habboReqPath + "/components/roomNavigation?roomId=" + roomId + "&roomType=" + roomType + "&move=true", { + method: "GET", + headers: { + "Content-Type": "application/json", + } + }); + return; + } + var isHabboClient = false; try { isHabboClient = window.habboClient; } catch (error) {} if (isHabboClient) {