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);
|
||||
CreateTeamPlayerEntities();
|
||||
CreateWorldEntities();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
PlayerEntity? prevEntity = GetPlayerEntity();
|
||||
|
@ -235,7 +243,10 @@ internal class CreatureController : Controller
|
|||
|
||||
if (i == 0) _modelManager.Creature.PlayerEntityId = entity.Id;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateWorldEntities()
|
||||
{
|
||||
// Test monster
|
||||
MonsterEntity monster = _entityFactory.CreateMonster(102000014); // Monster001
|
||||
monster.Pos = new()
|
||||
|
|
|
@ -12,5 +12,25 @@ internal class FriendSystemController : Controller
|
|||
}
|
||||
|
||||
[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.Models;
|
||||
using GameServer.Network;
|
||||
using GameServer.Network.Messages;
|
||||
using GameServer.Systems.Event;
|
||||
using Protocol;
|
||||
|
||||
|
@ -56,4 +57,22 @@ internal class PlayerInfoController : Controller
|
|||
|
||||
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 GameServer.Controllers;
|
||||
using GameServer.Controllers.Attributes;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace GameServer.Extensions;
|
||||
|
@ -17,4 +18,17 @@ internal static class ServiceCollectionExtensions
|
|||
|
||||
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>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="icon.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
</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 FormationModel Formation { get; } = new();
|
||||
public ChatModel Chat { get; } = new();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using Core.Config;
|
||||
using Core.Extensions;
|
||||
using GameServer.Controllers.ChatCommands;
|
||||
using GameServer.Controllers.Factory;
|
||||
using GameServer.Controllers.Manager;
|
||||
using GameServer.Extensions;
|
||||
|
@ -22,22 +23,37 @@ internal static class Program
|
|||
{
|
||||
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);
|
||||
builder.Logging.AddConsole();
|
||||
|
||||
builder.SetupConfiguration();
|
||||
builder.Services.UseLocalResources()
|
||||
.AddControllers()
|
||||
.AddCommands()
|
||||
.AddSingleton<ConfigManager>()
|
||||
.AddSingleton<KcpGateway>().AddScoped<PlayerSession>()
|
||||
.AddScoped<MessageManager>().AddSingleton<EventHandlerFactory>()
|
||||
.AddScoped<RpcManager>().AddScoped<IRpcEndPoint, RpcSessionEndPoint>()
|
||||
.AddSingleton<SessionManager>()
|
||||
.AddScoped<EventSystem>().AddScoped<EntitySystem>().AddScoped<EntityFactory>()
|
||||
.AddScoped<ModelManager>().AddScoped<ControllerManager>()
|
||||
.AddScoped<ModelManager>().AddScoped<ControllerManager>().AddScoped<ChatCommandManager>()
|
||||
.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)
|
||||
|
|
|
@ -28,10 +28,19 @@ internal class MonsterEntity : EntityBase
|
|||
aiComponent.AiTeamInitId = 100;
|
||||
|
||||
EntityFsmComponent fsm = ComponentSystem.Create<EntityFsmComponent>();
|
||||
|
||||
fsm.Fsms.Add(new DFsm
|
||||
{
|
||||
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, // ??
|
||||
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>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="icon.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\.editorconfig" Link=".editorconfig" />
|
||||
</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