Command Description

This commit is contained in:
linmeideli committed 2026-05-23 20:26:35 +08:00
1 parent f94c0e052c
commit 0b748eb200
13 files changed
+356 -48

No files matched your search

+4
View File
@@ -30,6 +30,7 @@ COPY src/Empostor.Plugins.QqVerify/Empostor.Plugins.QqVerify.csproj ./Empostor.P
COPY src/Empostor.Plugins.Titles/Empostor.Plugins.Titles.csproj ./Empostor.Plugins.Titles/
COPY src/Empostor.Plugins.Welcome/Empostor.Plugins.Welcome.csproj ./Empostor.Plugins.Welcome/
COPY src/Empostor.Plugins.MapVote/Empostor.Plugins.MapVote.csproj ./Empostor.Plugins.MapVote/
COPY src/Empostor.Plugins.Message/Empostor.Plugins.Message.csproj ./Empostor.Plugins.Message/
# Restore dependencies
RUN dotnet restore Empostor.Server/Empostor.Server.csproj -a $TARGETARCH
@@ -64,6 +65,8 @@ RUN dotnet publish Empostor.Plugin.Chat/Empostor.Plugin.Chat.csproj \
dotnet publish Empostor.Plugins.Welcome/Empostor.Plugins.Welcome.csproj \
-c Release -a $TARGETARCH --self-contained false -o /publish/plugins --no-restore && \
dotnet publish Empostor.Plugins.MapVote/Empostor.Plugins.MapVote.csproj \
-c Release -a $TARGETARCH --self-contained false -o /publish/plugins --no-restore && \
dotnet publish Empostor.Plugins.Message/Empostor.Plugins.Message.csproj \
-c Release -a $TARGETARCH --self-contained false -o /publish/plugins --no-restore
# ============================================
@@ -91,6 +94,7 @@ COPY --from=build /publish/plugins/Empostor.Plugins.QqVerify.dll ./plugins/
COPY --from=build /publish/plugins/Empostor.Plugins.Titles.dll ./plugins/
COPY --from=build /publish/plugins/Empostor.Plugins.Welcome.dll ./plugins/
COPY --from=build /publish/plugins/Empostor.Plugins.MapVote.dll ./plugins/
COPY --from=build /publish/plugins/Empostor.Plugins.Message.dll ./plugins/
# Copy marketplace data
COPY marketplace/ ./marketplace/
+45 -3
View File
@@ -189,7 +189,21 @@ public sealed class LanguageService
"command.players.not_in_lobby": "This command can only be used in the lobby.",
"command.players.header": "=== Players ({0}) ===",
"command.players.entry": "{0} | {1} | {2}ms",
"command.ping.result": "Your ping: {0}ms"
"command.ping.result": "Your ping: {0}ms",
"command.help.description": "Show available commands.",
"command.help.usage": "help [command]",
"command.stat.description": "Show your player statistics.",
"command.stat.usage": "stat",
"command.setcolor.description": "Change your player color.",
"command.setcolor.usage": "setcolor <0-17>",
"command.players.description": "List players in the current game.",
"command.players.usage": "players",
"command.ping.description": "Show your network ping.",
"command.ping.usage": "ping",
"command.note.description": "Set or clear a lobby note (host only).",
"command.note.usage": "note <text> | note clear",
"command.max.description": "Set max players for the lobby (host only).",
"command.max.usage": "max <1-15>"
}
""";
@@ -228,7 +242,21 @@ public sealed class LanguageService
"command.players.not_in_lobby": "此指令只能在大厅中使用。",
"command.players.header": "=== 在线玩家 ({0}) ===",
"command.players.entry": "{0} | {1} | {2}ms",
"command.ping.result": "你的延迟:{0}ms"
"command.ping.result": "你的延迟:{0}ms",
"command.help.description": "显示可用命令。",
"command.help.usage": "help [命令]",
"command.stat.description": "显示你的游戏统计。",
"command.stat.usage": "stat",
"command.setcolor.description": "修改你的颜色。",
"command.setcolor.usage": "setcolor <0-17>",
"command.players.description": "列出当前房间的玩家。",
"command.players.usage": "players",
"command.ping.description": "显示你的网络延迟。",
"command.ping.usage": "ping",
"command.note.description": "设置或清除房间备注(仅房主)。",
"command.note.usage": "note <文字> | note clear",
"command.max.description": "设置房间最大人数(仅房主)。",
"command.max.usage": "max <1-15>"
}
""";
@@ -267,7 +295,21 @@ public sealed class LanguageService
"command.players.not_in_lobby": "此指令只能在大廳中使用。",
"command.players.header": "=== 線上玩家 ({0}) ===",
"command.players.entry": "{0} | {1} | {2}ms",
"command.ping.result": "你的延遲:{0}ms"
"command.ping.result": "你的延遲:{0}ms",
"command.help.description": "顯示可用命令。",
"command.help.usage": "help [命令]",
"command.stat.description": "顯示你的遊戲統計。",
"command.stat.usage": "stat",
"command.setcolor.description": "修改你的顏色。",
"command.setcolor.usage": "setcolor <0-17>",
"command.players.description": "列出當前房間的玩家。",
"command.players.usage": "players",
"command.ping.description": "顯示你的網路延遲。",
"command.ping.usage": "ping",
"command.note.description": "設置或清除房間備註(僅房主)。",
"command.note.usage": "note <文字> | note clear",
"command.max.description": "設置房間最大人數(僅房主)。",
"command.max.usage": "max <1-15>"
}
""";
+106 -5
View File
@@ -1,3 +1,4 @@
using System.Text;
using System.Threading.Tasks;
using Empostor.Api.Commands;
using Microsoft.Extensions.Logging;
@@ -25,23 +26,106 @@ public sealed class NarratorCommand : ICommand
public async ValueTask<bool> ExecuteAsync(CommandContext ctx)
{
var args = ctx.Args;
// Host commands
if (args.Length > 0 && ctx.Sender.IsHost)
{
var sub = args[0].ToLowerInvariant();
if (sub == "enable" || sub == "on")
{
_service.SetEnabled(ctx.Game, true);
await ctx.PlayerControl.SendChatToPlayerAsync(
T(ctx, "narrator.host_enabled", "Narrator enabled for this game."), ctx.PlayerControl);
return true;
}
if (sub == "disable" || sub == "off")
{
_service.SetEnabled(ctx.Game, false);
await ctx.PlayerControl.SendChatToPlayerAsync(
T(ctx, "narrator.host_disabled", "Narrator disabled for this game."), ctx.PlayerControl);
return true;
}
if (sub == "status")
{
var enabled = _service.IsEnabled(ctx.Game);
var max = _service.GetMaxUses(ctx.Game);
var statusText = T(ctx, enabled ? "narrator.status_enabled" : "narrator.status_disabled",
enabled ? "enabled" : "disabled");
var msg = T(ctx, "narrator.host_status", "Status: {0} | Max uses per player per game: {1}")
.Replace("{0}", statusText)
.Replace("{1}", max.ToString());
await ctx.PlayerControl.SendChatToPlayerAsync(msg, ctx.PlayerControl);
return true;
}
if (sub == "limit")
{
if (args.Length < 2 || !int.TryParse(args[1], out var limit) || limit < 0)
{
await ctx.PlayerControl.SendChatToPlayerAsync(
T(ctx, "narrator.host_limit_usage", "Usage: #narrator limit <number>"), ctx.PlayerControl);
return true;
}
_service.SetMaxUses(ctx.Game, limit);
if (limit == 0)
await ctx.PlayerControl.SendChatToPlayerAsync(
T(ctx, "narrator.host_limit_zero", "Limit set to 0 (effectively disabled)."), ctx.PlayerControl);
else
await ctx.PlayerControl.SendChatToPlayerAsync(
T(ctx, "narrator.host_limit_set", "Limit set to {0} per player per game.")
.Replace("{0}", limit.ToString()),
ctx.PlayerControl);
return true;
}
}
// Show host commands if no args provided
if (args.Length == 0)
{
await ShowUsageAsync(ctx);
return true;
}
// Check game state — meeting must be active
if (!_service.IsMeetingActive(ctx.Game))
{
await ctx.PlayerControl.SendChatToPlayerAsync(
"[Narrator] You can only use this command during a meeting.", ctx.PlayerControl);
T(ctx, "narrator.meeting_only", "You can only use #narrator during a meeting."), ctx.PlayerControl);
return true;
}
// Check if narrator is enabled
if (!_service.IsEnabled(ctx.Game))
{
await ctx.PlayerControl.SendChatToPlayerAsync(
T(ctx, "narrator.disabled", "The narrator is currently disabled by the host."), ctx.PlayerControl);
return true;
}
var playerName = ctx.PlayerControl.PlayerInfo.PlayerName;
// Check usage limits
var (allowed, error) = _service.TryUse(ctx.Game, playerName);
if (!allowed)
{
await ctx.PlayerControl.SendChatToPlayerAsync(
$"[Narrator] {error}", ctx.PlayerControl);
return true;
}
var playerMessage = ctx.RawArgs?.Trim();
if (string.IsNullOrEmpty(playerMessage))
{
await ctx.PlayerControl.SendChatToPlayerAsync(
"Usage: /narrator <your question or statement>\nExample: /narrator I'm being accused but I have a visual task, how do I prove myself?",
ctx.PlayerControl);
await ShowUsageAsync(ctx);
return true;
}
_logger.LogInformation("[Narrator] {player} asks: {message}", ctx.PlayerControl.PlayerInfo.PlayerName, playerMessage);
_logger.LogInformation("[Narrator] {player} asks: {message}", playerName, playerMessage);
var context = _service.BuildContext(ctx.Game, ctx.PlayerControl);
var reply = await _service.AskNarratorAsync(context, playerMessage);
@@ -51,4 +135,21 @@ public sealed class NarratorCommand : ICommand
return true;
}
private async ValueTask ShowUsageAsync(CommandContext ctx)
{
var sb = new StringBuilder();
sb.AppendLine(T(ctx, "narrator.usage",
"Usage: #narrator <your question or statement>"));
if (ctx.Sender.IsHost)
sb.AppendLine(T(ctx, "narrator.host_commands",
"Host commands: #narrator enable | disable | limit <number>"));
await ctx.PlayerControl.SendChatToPlayerAsync(sb.ToString(), ctx.PlayerControl);
}
private static string T(CommandContext ctx, string key, string defaultText)
{
string result = ctx.Lang.Get(key, ctx.SenderLanguage);
return result == key ? defaultText : result;
}
}
@@ -29,6 +29,8 @@ public sealed class NarratorPlugin : PluginBase, IPluginLanguageProvider
{
["en"] = new Dictionary<string, string>
{
["command.narrator.description"] = "Ask the narrator for AI-powered advice during a meeting.",
["command.narrator.usage"] = "narrator <your question>",
["narrator.meeting_only"] = "You can only use #narrator during a meeting.",
["narrator.disabled"] = "The narrator is currently disabled by the host.",
["narrator.status_enabled"] = "enabled",
@@ -44,6 +46,8 @@ public sealed class NarratorPlugin : PluginBase, IPluginLanguageProvider
},
["zh_CN"] = new Dictionary<string, string>
{
["command.narrator.description"] = "在会议中向旁白寻求AI建议。",
["command.narrator.usage"] = "narrator <你要提的问题>",
["narrator.meeting_only"] = "只能在会议中使用 #narrator。",
["narrator.disabled"] = "房主已禁用旁白功能。",
["narrator.status_enabled"] = "已启用",
@@ -59,6 +63,8 @@ public sealed class NarratorPlugin : PluginBase, IPluginLanguageProvider
},
["zh_TW"] = new Dictionary<string, string>
{
["command.narrator.description"] = "在會議中向旁白尋求AI建議。",
["command.narrator.usage"] = "narrator <你要提的問題>",
["narrator.meeting_only"] = "只能在會議中使用 #narrator。",
["narrator.disabled"] = "房主已停用旁白功能。",
["narrator.status_enabled"] = "已啟用",
@@ -29,6 +29,8 @@ public sealed class MapVotePlugin : PluginBase, IPluginLanguageProvider
{
["en"] = new Dictionary<string, string>
{
["command.votemap.description"] = "Vote for the next map.",
["command.votemap.usage"] = "votemap <map>",
["mapvote.disabled"] = "Map voting is currently disabled by the host.",
["mapvote.unknown_map"] = "Unknown map: {0}. Available: Skeld, Mira, Polus, Airship, Fungle",
["mapvote.voted"] = "{0} voted for {1}.",
@@ -46,6 +48,8 @@ public sealed class MapVotePlugin : PluginBase, IPluginLanguageProvider
},
["zh_CN"] = new Dictionary<string, string>
{
["command.votemap.description"] = "投票选择下一张地图。",
["command.votemap.usage"] = "votemap <地图名>",
["mapvote.disabled"] = "投票选图功能已被房主禁用。",
["mapvote.unknown_map"] = "未知地图:{0}。可选:Skeld, Mira, Polus, Airship, Fungle",
["mapvote.voted"] = "{0} 投票选择了 {1}。",
@@ -63,6 +67,8 @@ public sealed class MapVotePlugin : PluginBase, IPluginLanguageProvider
},
["zh_TW"] = new Dictionary<string, string>
{
["command.votemap.description"] = "投票選擇下一張地圖。",
["command.votemap.usage"] = "votemap <地圖名>",
["mapvote.disabled"] = "投票選圖功能已被房主停用。",
["mapvote.unknown_map"] = "未知地圖:{0}。可選:Skeld, Mira, Polus, Airship, Fungle",
["mapvote.voted"] = "{0} 投票選擇了 {1}。",
@@ -31,12 +31,7 @@ public sealed class MessageCommand : ICommand
}
var targetFc = ctx.Args[0].Trim().ToUpperInvariant();
var content = ctx.RawArgs!;
// Remove the friend code prefix from the raw args to get the message content
var contentStart = ctx.RawArgs!.IndexOf(targetFc, StringComparison.OrdinalIgnoreCase);
if (contentStart >= 0)
content = ctx.RawArgs[(contentStart + ctx.Args[0].Length)..].Trim();
var content = ctx.RawArgs!.Substring(ctx.Args[0].Length).Trim();
if (string.IsNullOrWhiteSpace(content))
{
@@ -1,10 +1,7 @@
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Empostor.Api.Events;
using Empostor.Api.Events.Client;
using Empostor.Api.Events.Game;
namespace Empostor.Plugins.Message;
@@ -17,46 +14,18 @@ public sealed class MessageEventListener : IEventListener
_store = store;
}
[EventListener]
public async ValueTask OnClientConnected(IClientConnectedEvent e)
{
await DeliverMessages(e.Client.FriendCode, e.Client.Language, null);
}
[EventListener]
public async ValueTask OnPlayerJoined(IGamePlayerJoinedEvent e)
{
var fc = e.Player.Client.FriendCode;
if (string.IsNullOrEmpty(fc)) return;
// Deliver any undelivered messages when player joins a game
var messages = _store.TakeAll(fc);
if (messages.Count == 0) return;
var ctrl = e.Player.Character;
if (ctrl == null) return;
await DeliverToPlayer(messages, ctrl, e.Player.Client.Name ?? "Player");
}
private async ValueTask DeliverMessages(string? friendCode, Api.Languages.Language language, Api.Innersloth.IInnerPlayerControl? ctrl)
{
if (string.IsNullOrEmpty(friendCode)) return;
var messages = _store.TakeAll(friendCode);
if (messages.Count == 0) return;
// Messages were already delivered via OnPlayerJoined with character reference
// OnClientConnected happens before player has a character, so store them back and wait for game join
foreach (var msg in messages)
_store.Add(msg);
}
private async ValueTask DeliverToPlayer(
System.Collections.Generic.IReadOnlyList<PendingMessage> messages,
Empostor.Api.Innersloth.IInnerPlayerControl ctrl,
string playerName)
{
var sb = new StringBuilder();
sb.AppendLine(string.Format("--- You have {0} pending message(s) ---", messages.Count));
@@ -29,6 +29,8 @@ public sealed class MessagePlugin : PluginBase, IPluginLanguageProvider
{
["en"] = new Dictionary<string, string>
{
["command.msg.description"] = "Leave a message for a player by friend code.",
["command.msg.usage"] = "msg <friendcode> <message>",
["message.usage"] = "Usage: #msg <friendcode> <message>\nExample: #msg ABCDEFG Hey, let's play again!",
["message.sent"] = "Message sent to {0}.",
["message.too_long"] = "Message is too long. Max {0} characters.",
@@ -41,6 +43,8 @@ public sealed class MessagePlugin : PluginBase, IPluginLanguageProvider
},
["zh_CN"] = new Dictionary<string, string>
{
["command.msg.description"] = "通过好友代码给玩家留言。",
["command.msg.usage"] = "msg <好友代码> <留言内容>",
["message.usage"] = "用法:#msg <好友代码> <留言内容>\n示例:#msg ABCDEFG 下次一起玩!",
["message.sent"] = "留言已发送给 {0}。",
["message.too_long"] = "留言内容过长,最多 {0} 个字符。",
@@ -53,6 +57,8 @@ public sealed class MessagePlugin : PluginBase, IPluginLanguageProvider
},
["zh_TW"] = new Dictionary<string, string>
{
["command.msg.description"] = "透過好友代碼給玩家留言。",
["command.msg.usage"] = "msg <好友代碼> <留言內容>",
["message.usage"] = "用法:#msg <好友代碼> <留言內容>\n範例:#msg ABCDEFG 下次一起玩!",
["message.sent"] = "留言已發送給 {0}。",
["message.too_long"] = "留言內容過長,最多 {0} 個字元。",
@@ -0,0 +1,137 @@
{
"version": 1,
"dependencies": {
"net8.0": {
"BouncyCastle.Cryptography": {
"type": "Transitive",
"resolved": "2.6.1",
"contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA=="
},
"Microsoft.AspNetCore.Http.Abstractions": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "Nxs7Z1q3f1STfLYKJSVXCs1iBl+Ya6E8o4Oy1bCxJ/rNI44E/0f6tbsrVqAWfB7jlnJfyaAtIalBVxPKUPQb4Q==",
"dependencies": {
"Microsoft.AspNetCore.Http.Features": "2.2.0",
"System.Text.Encodings.Web": "4.5.0"
}
},
"Microsoft.AspNetCore.Http.Features": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "ziFz5zH8f33En4dX81LW84I6XrYXKf9jg6aM39cM+LffN9KJahViKZ61dGMSO2gd3e+qe5yBRwsesvyqlZaSMg==",
"dependencies": {
"Microsoft.Extensions.Primitives": "2.2.0"
}
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==",
"dependencies": {
"Microsoft.Extensions.Primitives": "8.0.0"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
"resolved": "9.0.6",
"contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA=="
},
"Microsoft.Extensions.Diagnostics.Abstractions": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "JHYCQG7HmugNYUhOl368g+NMxYE/N/AiclCYRNlgCY9eVyiBkOHMwK4x60RYMxv9EL3+rmj1mqHvdCiPpC+D4Q==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
"Microsoft.Extensions.Options": "8.0.0",
"System.Diagnostics.DiagnosticSource": "8.0.0"
}
},
"Microsoft.Extensions.FileProviders.Abstractions": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==",
"dependencies": {
"Microsoft.Extensions.Primitives": "8.0.0"
}
},
"Microsoft.Extensions.Hosting.Abstractions": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "AG7HWwVRdCHlaA++1oKDxLsXIBxmDpMPb3VoyOoAghEWnkUvEAdYQUwnV4jJbAaa/nMYNiEh5ByoLauZBEiovg==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
"Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
"Microsoft.Extensions.Logging.Abstractions": "8.0.0"
}
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
}
},
"Microsoft.Extensions.ObjectPool": {
"type": "Transitive",
"resolved": "8.0.1",
"contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA=="
},
"Microsoft.Extensions.Options": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
"Microsoft.Extensions.Primitives": "8.0.0"
}
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g=="
},
"Serilog": {
"type": "Transitive",
"resolved": "4.3.1-dev-02373",
"contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ=="
},
"System.Diagnostics.DiagnosticSource": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ=="
},
"System.Text.Encodings.Web": {
"type": "Transitive",
"resolved": "4.5.0",
"contentHash": "Xg4G4Indi4dqP1iuAiMSwpiWS54ZghzR644OtsRCm/m/lBMG8dUBhLVN7hLm8NNrNTR+iGbshCPTwrvxZPlm4g=="
},
"empostor.api": {
"type": "Project",
"dependencies": {
"Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )",
"Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )",
"Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )",
"NextFast.Hazel": "[1.0.2-dev, )",
"NextFast.Hazel.Abstractions": "[1.0.2-dev, )"
}
},
"NextFast.Hazel": {
"type": "Project",
"dependencies": {
"BouncyCastle.Cryptography": "[2.6.1, )",
"Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )",
"Microsoft.Extensions.ObjectPool": "[8.0.1, )",
"NextFast.Hazel.Abstractions": "[1.0.2-dev, )",
"Serilog": "[4.3.1-dev-02373, )"
}
},
"NextFast.Hazel.Abstractions": {
"type": "Project"
}
}
}
}
@@ -29,18 +29,24 @@ public sealed class PlayerChannelPlugin : PluginBase, IPluginLanguageProvider
{
["en"] = new Dictionary<string, string>
{
["command.channel.description"] = "Send a message to your player channel.",
["command.channel.usage"] = "channel <message>",
["playerchannel.unknown_friendcode"] = "[Refuse Channel] Unknown Friendcode",
["playerchannel.not_in_channel"] = "[Refuse Channel] Not in any channel",
["playerchannel.message_format"] = "[{0}] {1}",
},
["zh_CN"] = new Dictionary<string, string>
{
["command.channel.description"] = "向你的玩家频道发送消息。",
["command.channel.usage"] = "channel <消息>",
["playerchannel.unknown_friendcode"] = "[Refuse Channel] 未知的好友代码",
["playerchannel.not_in_channel"] = "[Refuse Channel] 不在任何频道中",
["playerchannel.message_format"] = "[{0}] {1}",
},
["zh_TW"] = new Dictionary<string, string>
{
["command.channel.description"] = "向你的玩家頻道發送訊息。",
["command.channel.usage"] = "channel <訊息>",
["playerchannel.unknown_friendcode"] = "[Refuse Channel] 未知的好友代碼",
["playerchannel.not_in_channel"] = "[Refuse Channel] 不在任何頻道中",
["playerchannel.message_format"] = "[{0}] {1}",
@@ -29,6 +29,8 @@ public sealed class QqVerifyPlugin : PluginBase, IPluginLanguageProvider
{
["en"] = new Dictionary<string, string>
{
["command.verify.description"] = "Verify your QQ number for group access.",
["command.verify.usage"] = "verify <QQ number>",
["qqverify.chinese_only"] = "This command is only available for Chinese language players.\n此功能仅支持简体/繁体中文玩家使用。",
["qqverify.no_friendcode"] = "Unable to get your friend code. Please make sure you are logged in.",
["qqverify.usage_message"] = "Usage: #verify <your QQ number>\nExample: #verify 123456789",
@@ -36,6 +38,8 @@ public sealed class QqVerifyPlugin : PluginBase, IPluginLanguageProvider
},
["zh_CN"] = new Dictionary<string, string>
{
["command.verify.description"] = "验证你的QQ号以获取群组访问权限。",
["command.verify.usage"] = "verify <QQ号>",
["qqverify.chinese_only"] = "此功能仅支持简体/繁体中文玩家使用。\nThis command is only available for Chinese language players.",
["qqverify.no_friendcode"] = "无法获取你的好友代码,请确保已登录账号。",
["qqverify.usage_message"] = "用法:#verify <你的QQ号>\n示例:#verify 123456789",
@@ -43,6 +47,8 @@ public sealed class QqVerifyPlugin : PluginBase, IPluginLanguageProvider
},
["zh_TW"] = new Dictionary<string, string>
{
["command.verify.description"] = "驗證你的QQ號以獲取群組存取權限。",
["command.verify.usage"] = "verify <QQ號>",
["qqverify.chinese_only"] = "此功能僅支援簡體/繁體中文玩家使用。\nThis command is only available for Chinese language players.",
["qqverify.no_friendcode"] = "無法獲取你的好友代碼,請確保已登入帳號。",
["qqverify.usage_message"] = "用法:#verify <你的QQ號>\n範例:#verify 123456789",
@@ -34,8 +34,8 @@ public sealed class HelpCommand : ICommand
}
var sb = new StringBuilder();
sb.AppendLine(ctx.GetString("command.help.entry").Format(target.Name, target.Description));
sb.AppendLine(ctx.GetString("command.usage").Format(target.Usage));
sb.AppendLine(ctx.GetString("command.help.entry").Format(target.Name, GetDesc(ctx, target)));
sb.AppendLine(ctx.GetString("command.usage").Format(GetUsage(ctx, target)));
if (target.Aliases.Length > 0)
sb.AppendLine(ctx.GetString("command.help.aliases")
.Format(string.Join(", ", target.Aliases.Select(a => "#" + a))));
@@ -47,10 +47,24 @@ public sealed class HelpCommand : ICommand
var list = new StringBuilder(ctx.GetString("command.help.list").Get() + "\n");
foreach (var cmd in _service.All.OrderBy(c => c.Name))
{
list.AppendLine(ctx.GetString("command.help.entry").Format(cmd.Name, cmd.Description));
list.AppendLine(ctx.GetString("command.help.entry").Format(cmd.Name, GetDesc(ctx, cmd)));
}
await ctx.PlayerControl.SendChatToPlayerAsync(list.ToString().TrimEnd(), ctx.PlayerControl);
return true;
}
private static string GetDesc(CommandContext ctx, ICommand cmd)
{
var key = $"command.{cmd.Name}.description";
var result = ctx.Lang.Get(key, ctx.SenderLanguage);
return result == key ? cmd.Description : result.Get();
}
private static string GetUsage(CommandContext ctx, ICommand cmd)
{
var key = $"command.{cmd.Name}.usage";
var result = ctx.Lang.Get(key, ctx.SenderLanguage);
return result == key ? cmd.Usage : result.Get();
}
}
+16
View File
@@ -39,6 +39,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Empostor.Plugin.Narrator",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Empostor.Plugins.MapVote", "Empostor.Plugins.MapVote\Empostor.Plugins.MapVote.csproj", "{9D67CAC6-D296-404C-9189-2FF9B86D287C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Empostor.Plugins.Message", "Empostor.Plugins.Message\Empostor.Plugins.Message.csproj", "{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -241,6 +243,18 @@ Global
{9D67CAC6-D296-404C-9189-2FF9B86D287C}.Release|x64.Build.0 = Release|Any CPU
{9D67CAC6-D296-404C-9189-2FF9B86D287C}.Release|x86.ActiveCfg = Release|Any CPU
{9D67CAC6-D296-404C-9189-2FF9B86D287C}.Release|x86.Build.0 = Release|Any CPU
{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8}.Debug|x64.ActiveCfg = Debug|Any CPU
{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8}.Debug|x64.Build.0 = Debug|Any CPU
{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8}.Debug|x86.ActiveCfg = Debug|Any CPU
{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8}.Debug|x86.Build.0 = Debug|Any CPU
{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8}.Release|Any CPU.Build.0 = Release|Any CPU
{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8}.Release|x64.ActiveCfg = Release|Any CPU
{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8}.Release|x64.Build.0 = Release|Any CPU
{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8}.Release|x86.ActiveCfg = Release|Any CPU
{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -257,7 +271,9 @@ Global
{D4B6C8A2-5F3E-4C1D-9B7A-6E2F8A4C1D3F} = {E0009DCB-32A6-45C4-A06C-7F62D4091A29}
{9D1FD146-E7D9-4AFF-9B8E-25E6021A69D7} = {E0009DCB-32A6-45C4-A06C-7F62D4091A29}
{ADC4F301-51C0-45DB-B97A-BE3844DFD19B} = {E0009DCB-32A6-45C4-A06C-7F62D4091A29}
{FE6D40CC-4BE5-4E38-9DCA-E6832709FE3F} = {E0009DCB-32A6-45C4-A06C-7F62D4091A29}
{9D67CAC6-D296-404C-9189-2FF9B86D287C} = {E0009DCB-32A6-45C4-A06C-7F62D4091A29}
{D05FE3E6-1BD9-4D32-89EB-5DE02A785EF8} = {E0009DCB-32A6-45C4-A06C-7F62D4091A29}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DAF5625C-7E46-4DCC-AF2C-11D20D965454}