Chat commands and better monster AI
This commit is contained in:
parent
8506dbdf71
commit
7ad0f2bfcc
19 changed files with 428 additions and 4 deletions
12
GameServer/Controllers/Attributes/ChatCommandAttribute.cs
Normal file
12
GameServer/Controllers/Attributes/ChatCommandAttribute.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
namespace GameServer.Controllers.Attributes;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
|
internal class ChatCommandAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string Command { get; }
|
||||||
|
|
||||||
|
public ChatCommandAttribute(string command)
|
||||||
|
{
|
||||||
|
Command = command;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
namespace GameServer.Controllers.Attributes;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
internal class ChatCommandCategoryAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string Category { get; }
|
||||||
|
|
||||||
|
public ChatCommandCategoryAttribute(string category)
|
||||||
|
{
|
||||||
|
Category = category;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
namespace GameServer.Controllers.Attributes;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Method)]
|
||||||
|
internal class ChatCommandDescAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string Description { get; }
|
||||||
|
|
||||||
|
public ChatCommandDescAttribute(string description)
|
||||||
|
{
|
||||||
|
Description = description;
|
||||||
|
}
|
||||||
|
}
|
77
GameServer/Controllers/ChatCommands/ChatCommandManager.cs
Normal file
77
GameServer/Controllers/ChatCommands/ChatCommandManager.cs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
using GameServer.Controllers.Attributes;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace GameServer.Controllers.ChatCommands;
|
||||||
|
internal class ChatCommandManager
|
||||||
|
{
|
||||||
|
private delegate Task ChatCommandDelegate(IServiceProvider serviceProvider, string[] args);
|
||||||
|
private static readonly ImmutableDictionary<string, ImmutableDictionary<string, ChatCommandDelegate>> s_commandCategories;
|
||||||
|
private static readonly ImmutableArray<string> s_commandDescriptions;
|
||||||
|
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
static ChatCommandManager()
|
||||||
|
{
|
||||||
|
(s_commandCategories, s_commandDescriptions) = RegisterCommands();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<string> CommandDescriptions => s_commandDescriptions;
|
||||||
|
|
||||||
|
public ChatCommandManager(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InvokeCommandAsync(string category, string command, string[] args)
|
||||||
|
{
|
||||||
|
if (s_commandCategories.TryGetValue(category, out var commands))
|
||||||
|
{
|
||||||
|
if (commands.TryGetValue(command, out ChatCommandDelegate? commandDelegate))
|
||||||
|
await commandDelegate(_serviceProvider, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (ImmutableDictionary<string, ImmutableDictionary<string, ChatCommandDelegate>>, ImmutableArray<string>) RegisterCommands()
|
||||||
|
{
|
||||||
|
IEnumerable<Type> types = Assembly.GetExecutingAssembly().GetTypes()
|
||||||
|
.Where(type => type.GetCustomAttribute<ChatCommandCategoryAttribute>() != null);
|
||||||
|
|
||||||
|
MethodInfo getServiceMethod = typeof(ServiceProviderServiceExtensions).GetMethod(nameof(ServiceProviderServiceExtensions.GetRequiredService), [typeof(IServiceProvider)])!;
|
||||||
|
var categories = ImmutableDictionary.CreateBuilder<string, ImmutableDictionary<string, ChatCommandDelegate>>();
|
||||||
|
var descriptions = ImmutableArray.CreateBuilder<string>();
|
||||||
|
|
||||||
|
foreach (Type type in types)
|
||||||
|
{
|
||||||
|
var commands = ImmutableDictionary.CreateBuilder<string, ChatCommandDelegate>();
|
||||||
|
foreach (MethodInfo method in type.GetMethods())
|
||||||
|
{
|
||||||
|
ChatCommandAttribute? cmdAttribute = method.GetCustomAttribute<ChatCommandAttribute>();
|
||||||
|
if (cmdAttribute == null) continue;
|
||||||
|
|
||||||
|
ParameterExpression serviceProviderParam = Expression.Parameter(typeof(IServiceProvider));
|
||||||
|
ParameterExpression argsParam = Expression.Parameter(typeof(string[]));
|
||||||
|
|
||||||
|
MethodCallExpression getServiceCall = Expression.Call(getServiceMethod.MakeGenericMethod(type), serviceProviderParam);
|
||||||
|
Expression handlerCall = Expression.Call(getServiceCall, method, argsParam);
|
||||||
|
|
||||||
|
if (method.ReturnType == typeof(void)) // Allow non-async methods as well
|
||||||
|
handlerCall = Expression.Block(handlerCall, Expression.Constant(Task.CompletedTask));
|
||||||
|
|
||||||
|
Expression<ChatCommandDelegate> lambda = Expression.Lambda<ChatCommandDelegate>(handlerCall, serviceProviderParam, argsParam);
|
||||||
|
commands.Add(cmdAttribute.Command, lambda.Compile());
|
||||||
|
|
||||||
|
ChatCommandDescAttribute? desc = method.GetCustomAttribute<ChatCommandDescAttribute>();
|
||||||
|
if (desc != null)
|
||||||
|
descriptions.Add(desc.Description);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatCommandCategoryAttribute categoryAttribute = type.GetCustomAttribute<ChatCommandCategoryAttribute>()!;
|
||||||
|
categories.Add(categoryAttribute.Category, commands.ToImmutable());
|
||||||
|
}
|
||||||
|
|
||||||
|
return (categories.ToImmutable(), descriptions.ToImmutable());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
using Core.Config;
|
||||||
|
using GameServer.Controllers.Attributes;
|
||||||
|
using GameServer.Models;
|
||||||
|
using GameServer.Models.Chat;
|
||||||
|
using GameServer.Network;
|
||||||
|
using GameServer.Systems.Entity;
|
||||||
|
using Protocol;
|
||||||
|
|
||||||
|
namespace GameServer.Controllers.ChatCommands;
|
||||||
|
|
||||||
|
[ChatCommandCategory("spawn")]
|
||||||
|
internal class ChatSpawnCommandHandler
|
||||||
|
{
|
||||||
|
private readonly ChatRoom _helperRoom;
|
||||||
|
private readonly EntitySystem _entitySystem;
|
||||||
|
private readonly EntityFactory _entityFactory;
|
||||||
|
private readonly PlayerSession _session;
|
||||||
|
private readonly ConfigManager _configManager;
|
||||||
|
|
||||||
|
public ChatSpawnCommandHandler(ModelManager modelManager, EntitySystem entitySystem, EntityFactory entityFactory, PlayerSession session, ConfigManager configManager)
|
||||||
|
{
|
||||||
|
_helperRoom = modelManager.Chat.GetChatRoom(1338);
|
||||||
|
_entitySystem = entitySystem;
|
||||||
|
_entityFactory = entityFactory;
|
||||||
|
_session = session;
|
||||||
|
_configManager = configManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ChatCommand("monster")]
|
||||||
|
[ChatCommandDesc("/spawn monster [id] [x] [y] [z] - spawns monster with specified id and coordinates")]
|
||||||
|
public async Task OnSpawnMonsterCommand(string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length != 4 ||
|
||||||
|
!(int.TryParse(args[0], out int levelEntityId) &&
|
||||||
|
int.TryParse(args[1], out int x) &&
|
||||||
|
int.TryParse(args[2], out int y) &&
|
||||||
|
int.TryParse(args[3], out int z)))
|
||||||
|
{
|
||||||
|
_helperRoom.AddMessage(1338, 0, "Usage: /spawn monster [id] [x] [y] [z]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MonsterEntity monster = _entityFactory.CreateMonster(levelEntityId);
|
||||||
|
monster.Pos = new()
|
||||||
|
{
|
||||||
|
X = x,
|
||||||
|
Y = y,
|
||||||
|
Z = z
|
||||||
|
};
|
||||||
|
|
||||||
|
_entitySystem.Create(monster);
|
||||||
|
monster.InitProps(_configManager.GetConfig<BasePropertyConfig>(600000100)!); // TODO: monster property config
|
||||||
|
|
||||||
|
await _session.Push(MessageId.EntityAddNotify, new EntityAddNotify
|
||||||
|
{
|
||||||
|
IsAdd = true,
|
||||||
|
EntityPbs = { monster.Pb }
|
||||||
|
});
|
||||||
|
|
||||||
|
_helperRoom.AddMessage(1338, 0, $"Successfully spawned monster with id {levelEntityId} at ({x}, {y}, {z})");
|
||||||
|
}
|
||||||
|
}
|
88
GameServer/Controllers/ChatController.cs
Normal file
88
GameServer/Controllers/ChatController.cs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
using System.Text;
|
||||||
|
using GameServer.Controllers.Attributes;
|
||||||
|
using GameServer.Controllers.ChatCommands;
|
||||||
|
using GameServer.Models;
|
||||||
|
using GameServer.Models.Chat;
|
||||||
|
using GameServer.Network;
|
||||||
|
using GameServer.Network.Messages;
|
||||||
|
using Protocol;
|
||||||
|
|
||||||
|
namespace GameServer.Controllers;
|
||||||
|
internal class ChatController : Controller
|
||||||
|
{
|
||||||
|
private readonly ModelManager _modelManager;
|
||||||
|
|
||||||
|
public ChatController(PlayerSession session, ModelManager modelManager) : base(session)
|
||||||
|
{
|
||||||
|
_modelManager = modelManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[NetEvent(MessageId.PrivateChatDataRequest)]
|
||||||
|
public async Task<ResponseMessage> OnPrivateChatDataRequest()
|
||||||
|
{
|
||||||
|
if (!_modelManager.Chat.AllChatRooms.Any())
|
||||||
|
{
|
||||||
|
ChatRoom chatRoom = _modelManager.Chat.GetChatRoom(1338); // Reversed Helper
|
||||||
|
chatRoom.AddMessage(1338, (int)ChatContentType.Text, BuildWelcomeMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
await PushPrivateChatHistory();
|
||||||
|
return Response(MessageId.PrivateChatDataResponse, new PrivateChatDataResponse()); // Response doesn't contain any useful info, everything is in notifies.
|
||||||
|
}
|
||||||
|
|
||||||
|
[NetEvent(MessageId.PrivateChatRequest)]
|
||||||
|
public async Task<ResponseMessage> OnPrivateChatRequest(PrivateChatRequest request, ChatCommandManager chatCommandManager)
|
||||||
|
{
|
||||||
|
ChatRoom chatRoom = _modelManager.Chat.GetChatRoom(1338);
|
||||||
|
|
||||||
|
chatRoom.AddMessage(_modelManager.Player.Id, request.ChatContentType, request.Content);
|
||||||
|
if (!request.Content.StartsWith('/'))
|
||||||
|
{
|
||||||
|
chatRoom.AddMessage(1338, 0, "huh?");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string[] split = request.Content[1..].Split(' ');
|
||||||
|
if (split.Length >= 2)
|
||||||
|
{
|
||||||
|
await chatCommandManager.InvokeCommandAsync(split[0], split[1], split[2..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await PushPrivateChatHistory();
|
||||||
|
return Response(MessageId.PrivateChatResponse, new PrivateChatResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
[NetEvent(MessageId.PrivateChatOperateRequest)]
|
||||||
|
public ResponseMessage OnPrivateChatOperateRequest() => Response(MessageId.PrivateChatOperateResponse, new PrivateChatOperateResponse());
|
||||||
|
|
||||||
|
private async Task PushPrivateChatHistory()
|
||||||
|
{
|
||||||
|
await Session.Push(MessageId.PrivateChatHistoryNotify, new PrivateChatHistoryNotify
|
||||||
|
{
|
||||||
|
AllChats =
|
||||||
|
{
|
||||||
|
_modelManager.Chat.AllChatRooms
|
||||||
|
.Select(chatRoom => new PrivateChatHistoryContentProto
|
||||||
|
{
|
||||||
|
TargetUid = chatRoom.TargetUid,
|
||||||
|
Chats = { chatRoom.ChatHistory }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string BuildWelcomeMessage()
|
||||||
|
{
|
||||||
|
StringBuilder builder = new();
|
||||||
|
builder.AppendLine("Welcome to ReversedRooms WutheringWaves private server!\nTo get support, join:\ndiscord.gg/reversedrooms");
|
||||||
|
builder.AppendLine("List of all commands:");
|
||||||
|
|
||||||
|
foreach (string description in ChatCommandManager.CommandDescriptions)
|
||||||
|
{
|
||||||
|
builder.AppendLine(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,6 +28,7 @@ internal class CreatureController : Controller
|
||||||
{
|
{
|
||||||
_modelManager.Creature.SetSceneLoadingData(instanceId);
|
_modelManager.Creature.SetSceneLoadingData(instanceId);
|
||||||
CreateTeamPlayerEntities();
|
CreateTeamPlayerEntities();
|
||||||
|
CreateWorldEntities();
|
||||||
|
|
||||||
await Session.Push(MessageId.JoinSceneNotify, new JoinSceneNotify
|
await Session.Push(MessageId.JoinSceneNotify, new JoinSceneNotify
|
||||||
{
|
{
|
||||||
|
@ -150,6 +151,13 @@ internal class CreatureController : Controller
|
||||||
.FirstOrDefault(e => e is PlayerEntity playerEntity && playerEntity.ConfigId == roleId && playerEntity.PlayerId == _modelManager.Player.Id) as PlayerEntity;
|
.FirstOrDefault(e => e is PlayerEntity playerEntity && playerEntity.ConfigId == roleId && playerEntity.PlayerId == _modelManager.Player.Id) as PlayerEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<PlayerEntity> GetPlayerEntities()
|
||||||
|
{
|
||||||
|
return _entitySystem.EnumerateEntities()
|
||||||
|
.Where(e => e is PlayerEntity entity && entity.PlayerId == _modelManager.Player.Id)
|
||||||
|
.Cast<PlayerEntity>();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task SwitchPlayerEntity(int roleId)
|
public async Task SwitchPlayerEntity(int roleId)
|
||||||
{
|
{
|
||||||
PlayerEntity? prevEntity = GetPlayerEntity();
|
PlayerEntity? prevEntity = GetPlayerEntity();
|
||||||
|
@ -235,7 +243,10 @@ internal class CreatureController : Controller
|
||||||
|
|
||||||
if (i == 0) _modelManager.Creature.PlayerEntityId = entity.Id;
|
if (i == 0) _modelManager.Creature.PlayerEntityId = entity.Id;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateWorldEntities()
|
||||||
|
{
|
||||||
// Test monster
|
// Test monster
|
||||||
MonsterEntity monster = _entityFactory.CreateMonster(102000014); // Monster001
|
MonsterEntity monster = _entityFactory.CreateMonster(102000014); // Monster001
|
||||||
monster.Pos = new()
|
monster.Pos = new()
|
||||||
|
|
|
@ -12,5 +12,25 @@ internal class FriendSystemController : Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
[NetEvent(MessageId.FriendAllRequest)]
|
[NetEvent(MessageId.FriendAllRequest)]
|
||||||
public ResponseMessage OnFriendAllRequest() => Response(MessageId.FriendAllResponse, new FriendAllResponse());
|
public ResponseMessage OnFriendAllRequest() => Response(MessageId.FriendAllResponse, new FriendAllResponse
|
||||||
|
{
|
||||||
|
FriendInfoList =
|
||||||
|
{
|
||||||
|
CreateDummyFriendInfo(1338, "Taoqi", "discord.gg/reversedrooms", 1601)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private static FriendInfo CreateDummyFriendInfo(int id, string name, string signature, int headIconId) => new()
|
||||||
|
{
|
||||||
|
Info = new()
|
||||||
|
{
|
||||||
|
PlayerId = id,
|
||||||
|
Name = name,
|
||||||
|
Signature = signature,
|
||||||
|
Level = 5,
|
||||||
|
HeadId = headIconId,
|
||||||
|
IsOnline = true,
|
||||||
|
LastOfflineTime = -1
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using GameServer.Controllers.Attributes;
|
using GameServer.Controllers.Attributes;
|
||||||
using GameServer.Models;
|
using GameServer.Models;
|
||||||
using GameServer.Network;
|
using GameServer.Network;
|
||||||
|
using GameServer.Network.Messages;
|
||||||
using GameServer.Systems.Event;
|
using GameServer.Systems.Event;
|
||||||
using Protocol;
|
using Protocol;
|
||||||
|
|
||||||
|
@ -56,4 +57,22 @@ internal class PlayerInfoController : Controller
|
||||||
|
|
||||||
await Session.Push(MessageId.BasicInfoNotify, basicInfo);
|
await Session.Push(MessageId.BasicInfoNotify, basicInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NetEvent(MessageId.PlayerBasicInfoGetRequest)]
|
||||||
|
public ResponseMessage OnPlayerBasicInfoGetRequest()
|
||||||
|
{
|
||||||
|
return Response(MessageId.PlayerBasicInfoGetResponse, new PlayerBasicInfoGetResponse
|
||||||
|
{
|
||||||
|
Info = new PlayerDetails
|
||||||
|
{
|
||||||
|
Name = "Taoqi",
|
||||||
|
Signature = "discord.gg/reversedrooms",
|
||||||
|
HeadId = 1601,
|
||||||
|
PlayerId = 1338,
|
||||||
|
IsOnline = true,
|
||||||
|
LastOfflineTime = -1,
|
||||||
|
Level = 5
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using GameServer.Controllers;
|
using GameServer.Controllers;
|
||||||
|
using GameServer.Controllers.Attributes;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace GameServer.Extensions;
|
namespace GameServer.Extensions;
|
||||||
|
@ -17,4 +18,17 @@ internal static class ServiceCollectionExtensions
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IServiceCollection AddCommands(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
IEnumerable<Type> handlerTypes = Assembly.GetExecutingAssembly().GetTypes()
|
||||||
|
.Where(t => t.GetCustomAttribute<ChatCommandCategoryAttribute>() != null);
|
||||||
|
|
||||||
|
foreach (Type type in handlerTypes)
|
||||||
|
{
|
||||||
|
services.AddScoped(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,13 @@
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="icon.ico" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
32
GameServer/Models/Chat/ChatRoom.cs
Normal file
32
GameServer/Models/Chat/ChatRoom.cs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
using Google.Protobuf;
|
||||||
|
using Protocol;
|
||||||
|
|
||||||
|
namespace GameServer.Models.Chat;
|
||||||
|
internal class ChatRoom
|
||||||
|
{
|
||||||
|
private readonly List<ChatContentProto> _messages;
|
||||||
|
private int _msgIdCounter;
|
||||||
|
|
||||||
|
public int TargetUid { get; }
|
||||||
|
|
||||||
|
public ChatRoom(int targetUid)
|
||||||
|
{
|
||||||
|
TargetUid = targetUid;
|
||||||
|
_messages = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ChatContentProto> ChatHistory => _messages;
|
||||||
|
|
||||||
|
public void AddMessage(int senderId, int contentType, string content)
|
||||||
|
{
|
||||||
|
_messages.Add(new ChatContentProto
|
||||||
|
{
|
||||||
|
SenderUid = senderId,
|
||||||
|
ChatContentType = contentType,
|
||||||
|
Content = content,
|
||||||
|
MsgId = NextMessageId().ToString()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private int NextMessageId() => Interlocked.Increment(ref _msgIdCounter);
|
||||||
|
}
|
29
GameServer/Models/ChatModel.cs
Normal file
29
GameServer/Models/ChatModel.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using GameServer.Models.Chat;
|
||||||
|
|
||||||
|
namespace GameServer.Models;
|
||||||
|
internal class ChatModel
|
||||||
|
{
|
||||||
|
private readonly Dictionary<int, ChatRoom> _rooms;
|
||||||
|
|
||||||
|
public ChatModel()
|
||||||
|
{
|
||||||
|
_rooms = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets chat room for specified player id.
|
||||||
|
/// Creates new one if it doesn't exist.
|
||||||
|
/// </summary>
|
||||||
|
public ChatRoom GetChatRoom(int id)
|
||||||
|
{
|
||||||
|
if (!_rooms.TryGetValue(id, out ChatRoom? chatRoom))
|
||||||
|
{
|
||||||
|
chatRoom = new ChatRoom(id);
|
||||||
|
_rooms[id] = chatRoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
return chatRoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ChatRoom> AllChatRooms => _rooms.Values;
|
||||||
|
}
|
|
@ -30,4 +30,5 @@ internal class ModelManager
|
||||||
public CreatureModel Creature => _creatureModel ?? throw new InvalidOperationException($"Trying to access {nameof(CreatureModel)} instance before initialization!");
|
public CreatureModel Creature => _creatureModel ?? throw new InvalidOperationException($"Trying to access {nameof(CreatureModel)} instance before initialization!");
|
||||||
|
|
||||||
public FormationModel Formation { get; } = new();
|
public FormationModel Formation { get; } = new();
|
||||||
|
public ChatModel Chat { get; } = new();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Core.Config;
|
using Core.Config;
|
||||||
using Core.Extensions;
|
using Core.Extensions;
|
||||||
|
using GameServer.Controllers.ChatCommands;
|
||||||
using GameServer.Controllers.Factory;
|
using GameServer.Controllers.Factory;
|
||||||
using GameServer.Controllers.Manager;
|
using GameServer.Controllers.Manager;
|
||||||
using GameServer.Extensions;
|
using GameServer.Extensions;
|
||||||
|
@ -22,22 +23,37 @@ internal static class Program
|
||||||
{
|
{
|
||||||
private static async Task Main(string[] args)
|
private static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
|
Console.Title = "Wuthering Waves | Game Server";
|
||||||
|
Console.WriteLine(" __ __ __ .__ .__ __ __ \r\n/ \\ / \\__ ___/ |_| |__ ___________|__| ____ ____ / \\ / \\_____ ___ __ ____ ______\r\n\\ \\/\\/ / | \\ __\\ | \\_/ __ \\_ __ \\ |/ \\ / ___\\ \\ \\/\\/ /\\__ \\\\ \\/ // __ \\ / ___/\r\n \\ /| | /| | | Y \\ ___/| | \\/ | | \\/ /_/ > \\ / / __ \\\\ /\\ ___/ \\___ \\ \r\n \\__/\\ / |____/ |__| |___| /\\___ >__| |__|___| /\\___ / \\__/\\ / (____ /\\_/ \\___ >____ >\r\n \\/ \\/ \\/ \\//_____/ \\/ \\/ \\/ \\/ \n");
|
||||||
|
|
||||||
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
|
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
|
||||||
builder.Logging.AddConsole();
|
builder.Logging.AddConsole();
|
||||||
|
|
||||||
builder.SetupConfiguration();
|
builder.SetupConfiguration();
|
||||||
builder.Services.UseLocalResources()
|
builder.Services.UseLocalResources()
|
||||||
.AddControllers()
|
.AddControllers()
|
||||||
|
.AddCommands()
|
||||||
.AddSingleton<ConfigManager>()
|
.AddSingleton<ConfigManager>()
|
||||||
.AddSingleton<KcpGateway>().AddScoped<PlayerSession>()
|
.AddSingleton<KcpGateway>().AddScoped<PlayerSession>()
|
||||||
.AddScoped<MessageManager>().AddSingleton<EventHandlerFactory>()
|
.AddScoped<MessageManager>().AddSingleton<EventHandlerFactory>()
|
||||||
.AddScoped<RpcManager>().AddScoped<IRpcEndPoint, RpcSessionEndPoint>()
|
.AddScoped<RpcManager>().AddScoped<IRpcEndPoint, RpcSessionEndPoint>()
|
||||||
.AddSingleton<SessionManager>()
|
.AddSingleton<SessionManager>()
|
||||||
.AddScoped<EventSystem>().AddScoped<EntitySystem>().AddScoped<EntityFactory>()
|
.AddScoped<EventSystem>().AddScoped<EntitySystem>().AddScoped<EntityFactory>()
|
||||||
.AddScoped<ModelManager>().AddScoped<ControllerManager>()
|
.AddScoped<ModelManager>().AddScoped<ControllerManager>().AddScoped<ChatCommandManager>()
|
||||||
.AddHostedService<WWGameServer>();
|
.AddHostedService<WWGameServer>();
|
||||||
|
|
||||||
await builder.Build().RunAsync();
|
IHost host = builder.Build();
|
||||||
|
|
||||||
|
ILogger logger = host.Services.GetRequiredService<ILoggerFactory>().CreateLogger("WutheringWaves");
|
||||||
|
logger.LogInformation("Support: discord.gg/reversedrooms or discord.xeondev.com");
|
||||||
|
logger.LogInformation("Preparing server...");
|
||||||
|
|
||||||
|
host.Services.GetRequiredService<IHostApplicationLifetime>().ApplicationStarted.Register(() =>
|
||||||
|
{
|
||||||
|
logger.LogInformation("Server started! Let's play Wuthering Waves!");
|
||||||
|
});
|
||||||
|
|
||||||
|
await host.RunAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetupConfiguration(this HostApplicationBuilder builder)
|
private static void SetupConfiguration(this HostApplicationBuilder builder)
|
||||||
|
|
|
@ -28,10 +28,19 @@ internal class MonsterEntity : EntityBase
|
||||||
aiComponent.AiTeamInitId = 100;
|
aiComponent.AiTeamInitId = 100;
|
||||||
|
|
||||||
EntityFsmComponent fsm = ComponentSystem.Create<EntityFsmComponent>();
|
EntityFsmComponent fsm = ComponentSystem.Create<EntityFsmComponent>();
|
||||||
|
|
||||||
fsm.Fsms.Add(new DFsm
|
fsm.Fsms.Add(new DFsm
|
||||||
{
|
{
|
||||||
FsmId = 10007, // Main State Machine
|
FsmId = 10007, // Main State Machine
|
||||||
CurrentState = 10009, // Standby Entry
|
CurrentState = 10013, // Battle Branching
|
||||||
|
Status = 1, // ??
|
||||||
|
Flag = (int)EFsmStateFlag.Confirmed
|
||||||
|
});
|
||||||
|
|
||||||
|
fsm.Fsms.Add(new DFsm
|
||||||
|
{
|
||||||
|
FsmId = 10007, // Main State Machine
|
||||||
|
CurrentState = 10015, // Moving Combat
|
||||||
Status = 1, // ??
|
Status = 1, // ??
|
||||||
Flag = (int)EFsmStateFlag.Confirmed
|
Flag = (int)EFsmStateFlag.Confirmed
|
||||||
});
|
});
|
||||||
|
|
BIN
GameServer/icon.ico
Normal file
BIN
GameServer/icon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 205 KiB |
|
@ -4,8 +4,13 @@
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="icon.ico" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
BIN
SDKServer/icon.ico
Normal file
BIN
SDKServer/icon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 205 KiB |
Loading…
Reference in a new issue