Move the report commands into exp_reports

The create-report, get-reports and clear-reports commands now live in the
plugin's own module next to the functions they call, with their locale.
The permissions keep their exp_scenario.command names because the command
authority derives them from the command name.

The Discord report alert in exp_scenario is gone since exp_reports posts to
its own webhook. The shared add_player stub takes an options table with
connected and admin defaulting to true and false, replacing the copy in
the exp_reports test environment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bbassieandClaude Opus 5.5 committed 2026-09-26 23:22:18 +00:00
1 parent e47f41d440
commit 9ddb7b362b
20 files changed
+95 -155

No files matched your search

@@ -4,7 +4,6 @@
return { return {
show_playtime = true, show_playtime = true,
entity_protection = true, entity_protection = true,
player_reports = true,
player_bans = true, player_bans = true,
player_mutes = true, player_mutes = true,
player_kicks = true, player_kicks = true,
@@ -1,5 +1,5 @@
--[[-- Commands - Reports --[[-- ExpReports - Commands
Adds a commands that allow players to report other players Commands which let players report each other and admins manage the reports
]] ]]
local Commands = require("modules/exp_commands") local Commands = require("modules/exp_commands")
@@ -19,19 +19,19 @@ local function reportable_player(input, player)
if not success then return status, result end if not success then return status, result end
--- @cast result LuaPlayer --- @cast result LuaPlayer
if player_has_permission(input, "exp_scenario.bypass.reports") then if player_has_permission(result, "exp_scenario.bypass.reports") then
return Commands.status.invalid_input{ "exp-commands_reports.player-immune" } return Commands.status.invalid_input{ "exp-reports_commands.player-immune" }
elseif player == input then elseif player == result then
return Commands.status.invalid_input{ "exp-commands_reports.self-report" } return Commands.status.invalid_input{ "exp-reports_commands.self-report" }
else else
return Commands.status.success(result) return Commands.status.success(result)
end end
end end
--- Reports a player and notifies admins, the outcome is printed once the controller answers --- Reports a player and notifies admins, the outcome is printed once the controller answers
Commands.new("create-report", { "exp-commands_reports.description-create" }) Commands.new("create-report", { "exp-reports_commands.description-create" })
:argument("player", { "exp-commands_reports.arg-player-create" }, reportable_player) :argument("player", { "exp-reports_commands.arg-player-create" }, reportable_player)
:argument("reason", { "exp-commands_reports.arg-reason" }, Commands.types.string) :argument("reason", { "exp-reports_commands.arg-reason" }, Commands.types.string)
:enable_auto_concatenation() :enable_auto_concatenation()
:add_aliases{ "report" } :add_aliases{ "report" }
:register(function(player, other_player, reason) :register(function(player, other_player, reason)
@@ -41,8 +41,8 @@ Commands.new("create-report", { "exp-commands_reports.description-create" })
end) end)
--- Lists the reports against a player, or the number against every player, printed once the controller answers --- Lists the reports against a player, or the number against every player, printed once the controller answers
Commands.new("get-reports", { "exp-commands_reports.description-get" }) Commands.new("get-reports", { "exp-reports_commands.description-get" })
:optional("player", { "exp-commands_reports.arg-player-get" }, Commands.types.player) :optional("player", { "exp-reports_commands.arg-player-get" }, Commands.types.player)
:add_aliases{ "reports" } :add_aliases{ "reports" }
:add_flags{ "admin_only" } :add_flags{ "admin_only" }
:register(function(player, other_player) :register(function(player, other_player)
@@ -51,9 +51,9 @@ Commands.new("get-reports", { "exp-commands_reports.description-get" })
end) end)
--- Clears all reports from a player or just the report from one player, printed once the controller answers --- Clears all reports from a player or just the report from one player, printed once the controller answers
Commands.new("clear-reports", { "exp-commands_reports.description-clear" }) Commands.new("clear-reports", { "exp-reports_commands.description-clear" })
:argument("player", { "exp-commands_reports.arg-player-clear" }, Commands.types.player) :argument("player", { "exp-reports_commands.arg-player-clear" }, Commands.types.player)
:optional("from-player", { "exp-commands_reports.arg-from-player" }, Commands.types.player) :optional("from-player", { "exp-reports_commands.arg-from-player" }, Commands.types.player)
:add_flags{ "admin_only" } :add_flags{ "admin_only" }
:register(function(player, other_player, from_player) :register(function(player, other_player, from_player)
--- @cast other_player LuaPlayer --- @cast other_player LuaPlayer
+12
View File
@@ -8,3 +8,15 @@ list-all-entry=__1__: __2__ __plural_for_parameter__2__{1=report|rest=reports}__
list-all-none=No players have reports against them. list-all-none=No players have reports against them.
deleted=__1__ had __2__ __plural_for_parameter__2__{1=report|rest=reports}__ removed by __3__. deleted=__1__ had __2__ __plural_for_parameter__2__{1=report|rest=reports}__ removed by __3__.
deleted-none=__1__ has no reports against them. deleted-none=__1__ has no reports against them.
[exp-reports_commands]
description-create=Reports a player and notifies moderators
description-get=Gets a list of all reports that a player has on them. If no player then lists all players and the number of reports on them.
description-clear=Clears all reports from a player or just the report from one player.
arg-player-create=Player you want to report.
arg-player-get=Player to get the reports of.
arg-player-clear=Player to clear the reports of.
arg-reason=Reason you want to report this player.
arg-from-player=Only remove the report from this player.
player-immune=This player can not be reported.
self-report=You cannot report yourself.
+12
View File
@@ -8,3 +8,15 @@ list-all-entry=__1__: __2__
list-all-none=沒有用戶被舉報。 list-all-none=沒有用戶被舉報。
deleted=__1__ 被舉報的 __2__ 個紀錄已被 __3__ 清除。 deleted=__1__ 被舉報的 __2__ 個紀錄已被 __3__ 清除。
deleted-none=__1__ 沒有被舉報的紀錄。 deleted-none=__1__ 沒有被舉報的紀錄。
[exp-reports_commands]
description-create=檢舉用戶並通知管理員。
description-get=取得用戶的報告清單。如果沒有設定用戶,則列出所有用戶以及有關他們的報告數量。
description-clear=清除一名用戶的所有報告或僅清除一名用戶的報告。
arg-player-create=用戶
arg-player-get=用戶
arg-player-clear=用戶
arg-reason=原因
arg-from-player=用戶
player-immune=用戶不能被舉報
self-report=你不能舉報自己。
+12
View File
@@ -8,3 +8,15 @@ list-all-entry=__1__: __2__
list-all-none=沒有用戶被舉報。 list-all-none=沒有用戶被舉報。
deleted=__1__ 被舉報的 __2__ 個紀錄已被 __3__ 清除。 deleted=__1__ 被舉報的 __2__ 個紀錄已被 __3__ 清除。
deleted-none=__1__ 沒有被舉報的紀錄。 deleted-none=__1__ 沒有被舉報的紀錄。
[exp-reports_commands]
description-create=檢舉用戶並通知管理員。
description-get=取得用戶的報告清單。如果沒有設定用戶,則列出所有用戶以及有關他們的報告數量。
description-clear=清除一名用戶的所有報告或僅清除一名用戶的報告。
arg-player-create=用戶
arg-player-get=用戶
arg-player-clear=用戶
arg-reason=原因
arg-from-player=用戶
player-immune=用戶不能被舉報
self-report=你不能舉報自己。
+4 -1
View File
@@ -1,12 +1,15 @@
{ {
"name": "exp_reports", "name": "exp_reports",
"load": [ "load": [
"commands.lua"
], ],
"require": [ "require": [
"globals.lua" "globals.lua"
], ],
"dependencies": { "dependencies": {
"clusterio": "*", "clusterio": "*",
"exp_util": "*" "exp_util": "*",
"exp_commands": "*",
"exp_roles": "*"
} }
} }
-13
View File
@@ -13,15 +13,10 @@ local plugin_root = assert(source:match("^@(.*)/test/module/env%.lua$"))
local Framework = assert(loadfile(shared_root .. "/framework.lua"))() --- @type Framework local Framework = assert(loadfile(shared_root .. "/framework.lua"))() --- @type Framework
--- A stubbed player which also carries the admin flag the module reads
--- @class ExpReports.TestPlayer : Stubs.Player
--- @field admin boolean
--- The environment given to each test: the stubs extended with a fresh copy --- The environment given to each test: the stubs extended with a fresh copy
--- of the reports module and the fixture helpers --- of the reports module and the fixture helpers
--- @class ExpReports.TestEnv : Stubs --- @class ExpReports.TestEnv : Stubs
--- @field Reports ExpReports A fresh copy of the reports module --- @field Reports ExpReports A fresh copy of the reports module
--- @field add_player fun(name: string, is_connected: boolean?, is_admin: boolean?): ExpReports.TestPlayer
--- @field report fun(player_name: string, by_player_name: string, reason: string?): ExpReports.Report A report as the controller sends it --- @field report fun(player_name: string, by_player_name: string, reason: string?): ExpReports.Report A report as the controller sends it
return Framework.suite(function(env) return Framework.suite(function(env)
@@ -34,14 +29,6 @@ return Framework.suite(function(env)
} }
env.Reports = assert(loadfile(plugin_root .. "/module/control.lua"))() --- @type ExpReports env.Reports = assert(loadfile(plugin_root .. "/module/control.lua"))() --- @type ExpReports
-- The module reads player.admin, which the strict stub raises on unless it is set
local add_player = env.add_player
function env.add_player(name, is_connected, is_admin)
local player = add_player(name, is_connected) --[[@as ExpReports.TestPlayer]]
player.admin = is_admin == true
return player
end
local next_id = 0 local next_id = 0
function env.report(player_name, by_player_name, reason) function env.report(player_name, by_player_name, reason)
next_id = next_id + 1 next_id = next_id + 1
+15 -15
View File
@@ -1,9 +1,9 @@
local Suite = ... --- @type Suite<ExpReports.TestEnv> local Suite = ... --- @type Suite<ExpReports.TestEnv>
Suite.test("receive_created() tells everyone and raises on_player_reported", function(env) Suite.test("receive_created() tells everyone and raises on_player_reported", function(env)
env.add_player("alice", true, true) env.add_player{ name = "alice", admin = true }
local bob = env.add_player("bob") local bob = env.add_player{ name = "bob" }
env.add_player("carol") env.add_player{ name = "carol" }
local report = env.report("bob", "alice") local report = env.report("bob", "alice")
env.Reports.receive_created{ report = report, reports = { report, env.report("bob", "carol") } } env.Reports.receive_created{ report = report, reports = { report, env.report("bob", "carol") } }
@@ -26,8 +26,8 @@ Suite.test("receive_created() tells everyone and raises on_player_reported", fun
end) end)
Suite.test("receive_created() raises nothing when the reported player has left", function(env) Suite.test("receive_created() raises nothing when the reported player has left", function(env)
env.add_player("alice") env.add_player{ name = "alice" }
env.add_player("bob", false) env.add_player{ name = "bob", connected = false }
local report = env.report("bob", "alice") local report = env.report("bob", "alice")
env.Reports.receive_created{ report = report, reports = { report } } env.Reports.receive_created{ report = report, reports = { report } }
Suite.eq(env.printed, { { to = "alice", { "exp-reports.created", "bob", "griefing" } } }, "the report is still announced") Suite.eq(env.printed, { { to = "alice", { "exp-reports.created", "bob", "griefing" } } }, "the report is still announced")
@@ -35,7 +35,7 @@ Suite.test("receive_created() raises nothing when the reported player has left",
end) end)
Suite.test("receive_list() prints the reports against a player to the caller", function(env) Suite.test("receive_list() prints the reports against a player to the caller", function(env)
env.add_player("alice") env.add_player{ name = "alice" }
env.Reports.receive_list{ env.Reports.receive_list{
caller = "alice", caller = "alice",
player_name = "bob", player_name = "bob",
@@ -49,7 +49,7 @@ Suite.test("receive_list() prints the reports against a player to the caller", f
end) end)
Suite.test("receive_list() prints how many reports each player has", function(env) Suite.test("receive_list() prints how many reports each player has", function(env)
env.add_player("alice") env.add_player{ name = "alice" }
env.Reports.receive_list{ env.Reports.receive_list{
caller = "alice", caller = "alice",
reports = { env.report("dave", "alice"), env.report("bob", "carol"), env.report("dave", "carol") }, reports = { env.report("dave", "alice"), env.report("bob", "carol"), env.report("dave", "carol") },
@@ -62,20 +62,20 @@ Suite.test("receive_list() prints how many reports each player has", function(en
end) end)
Suite.test("receive_list() says when nobody is reported", function(env) Suite.test("receive_list() says when nobody is reported", function(env)
env.add_player("alice") env.add_player{ name = "alice" }
env.Reports.receive_list{ caller = "alice", reports = {} } env.Reports.receive_list{ caller = "alice", reports = {} }
Suite.eq(env.printed, { { to = "alice", { "exp-reports.list-all-none" } } }, "the caller is told there are none") Suite.eq(env.printed, { { to = "alice", { "exp-reports.list-all-none" } } }, "the caller is told there are none")
end) end)
Suite.test("receive_list() prints nothing once the caller has left", function(env) Suite.test("receive_list() prints nothing once the caller has left", function(env)
env.add_player("alice", false) env.add_player{ name = "alice", connected = false }
env.Reports.receive_list{ caller = "alice", reports = { env.report("bob", "carol") } } env.Reports.receive_list{ caller = "alice", reports = { env.report("bob", "carol") } }
Suite.empty(env.printed, "nothing is printed") Suite.empty(env.printed, "nothing is printed")
end) end)
Suite.test("receive_deleted() announces the deletion and raises on_reports_deleted", function(env) Suite.test("receive_deleted() announces the deletion and raises on_reports_deleted", function(env)
env.add_player("alice") env.add_player{ name = "alice" }
local bob = env.add_player("bob") local bob = env.add_player{ name = "bob" }
env.Reports.receive_deleted{ caller = "alice", player_name = "bob", count = 2 } env.Reports.receive_deleted{ caller = "alice", player_name = "bob", count = 2 }
Suite.eq(env.printed, { { "exp-reports.deleted", "bob", 2, "alice" } }, "everyone is told") Suite.eq(env.printed, { { "exp-reports.deleted", "bob", 2, "alice" } }, "everyone is told")
Suite.eq(env.events, { Suite.eq(env.events, {
@@ -84,16 +84,16 @@ Suite.test("receive_deleted() announces the deletion and raises on_reports_delet
end) end)
Suite.test("receive_deleted() tells the caller when there was nothing to delete", function(env) Suite.test("receive_deleted() tells the caller when there was nothing to delete", function(env)
env.add_player("alice") env.add_player{ name = "alice" }
env.add_player("bob") env.add_player{ name = "bob" }
env.Reports.receive_deleted{ caller = "alice", player_name = "bob", count = 0 } env.Reports.receive_deleted{ caller = "alice", player_name = "bob", count = 0 }
Suite.eq(env.printed, { { to = "alice", { "exp-reports.deleted-none", "bob" } } }, "only the caller is told") Suite.eq(env.printed, { { to = "alice", { "exp-reports.deleted-none", "bob" } } }, "only the caller is told")
Suite.empty(env.events, "nothing was deleted") Suite.empty(env.events, "nothing was deleted")
end) end)
Suite.test("receive_error() prints the refusal to the caller while they are online", function(env) Suite.test("receive_error() prints the refusal to the caller while they are online", function(env)
env.add_player("alice") env.add_player{ name = "alice" }
env.add_player("bob", false) env.add_player{ name = "bob", connected = false }
env.Reports.receive_error{ caller = "alice", message = "alice has already reported bob" } env.Reports.receive_error{ caller = "alice", message = "alice has already reported bob" }
env.Reports.receive_error{ caller = "bob", message = "gone" } env.Reports.receive_error{ caller = "bob", message = "gone" }
Suite.eq(env.printed, { { to = "alice", "alice has already reported bob" } }, "the offline player is skipped") Suite.eq(env.printed, { { to = "alice", "alice has already reported bob" } }, "the offline player is skipped")
+6 -6
View File
@@ -1,8 +1,8 @@
local Suite = ... --- @type Suite<ExpReports.TestEnv> local Suite = ... --- @type Suite<ExpReports.TestEnv>
Suite.test("create_report() sends the report to the controller", function(env) Suite.test("create_report() sends the report to the controller", function(env)
local alice = env.add_player("alice") local alice = env.add_player{ name = "alice" }
local bob = env.add_player("bob") local bob = env.add_player{ name = "bob" }
env.Reports.create_report(alice, bob, "griefing") env.Reports.create_report(alice, bob, "griefing")
Suite.eq(env.sent, { Suite.eq(env.sent, {
{ channel = "exp_reports:create", data = { player_name = "bob", by_player_name = "alice", reason = "griefing" } }, { channel = "exp_reports:create", data = { player_name = "bob", by_player_name = "alice", reason = "griefing" } },
@@ -10,8 +10,8 @@ Suite.test("create_report() sends the report to the controller", function(env)
end) end)
Suite.test("list_reports() sends the caller and the player", function(env) Suite.test("list_reports() sends the caller and the player", function(env)
local alice = env.add_player("alice") local alice = env.add_player{ name = "alice" }
local bob = env.add_player("bob") local bob = env.add_player{ name = "bob" }
env.Reports.list_reports(alice, bob) env.Reports.list_reports(alice, bob)
env.Reports.list_reports(alice) env.Reports.list_reports(alice)
Suite.eq(env.sent, { Suite.eq(env.sent, {
@@ -21,8 +21,8 @@ Suite.test("list_reports() sends the caller and the player", function(env)
end) end)
Suite.test("delete_reports() sends the caller, the player and the reporter", function(env) Suite.test("delete_reports() sends the caller, the player and the reporter", function(env)
local alice = env.add_player("alice") local alice = env.add_player{ name = "alice" }
local bob = env.add_player("bob") local bob = env.add_player{ name = "bob" }
env.Reports.delete_reports(alice, bob, "carol") env.Reports.delete_reports(alice, bob, "carol")
env.Reports.delete_reports(alice, bob) env.Reports.delete_reports(alice, bob)
Suite.eq(env.sent, { Suite.eq(env.sent, {
File renamed without changes.
+2 -2
View File
@@ -5,8 +5,8 @@ local test, check, eq, empty = Suite.test, Suite.check, Suite.eq, Suite.empty
--- alice is a moderator and bob a regular, with changes sent to the controller --- alice is a moderator and bob a regular, with changes sent to the controller
local function setup(env) local function setup(env)
local players = { local players = {
alice = env.add_player("alice"), alice = env.add_player{ name = "alice" },
bob = env.add_player("bob"), bob = env.add_player{ name = "bob" },
} }
env.initialise{ env.initialise{
env.assignment("alice", { "Moderator" }), env.assignment("alice", { "Moderator" }),
+3 -3
View File
@@ -5,9 +5,9 @@ local test, check, eq = Suite.test, Suite.check, Suite.eq
--- alice and dave are moderators with dave offline, zed has never joined --- alice and dave are moderators with dave offline, zed has never joined
local function setup(env) local function setup(env)
local players = { local players = {
alice = env.add_player("alice"), alice = env.add_player{ name = "alice" },
bob = env.add_player("bob"), bob = env.add_player{ name = "bob" },
dave = env.add_player("dave", false), dave = env.add_player{ name = "dave", connected = false },
} }
env.initialise{ env.initialise{
env.assignment("alice", { "Moderator" }), env.assignment("alice", { "Moderator" }),
+3 -3
View File
@@ -5,9 +5,9 @@ local test, check, eq = Suite.test, Suite.check, Suite.eq
--- alice is a moderator, bob is a regular, and carol has only the default role --- alice is a moderator, bob is a regular, and carol has only the default role
local function setup(env) local function setup(env)
local players = { local players = {
alice = env.add_player("alice"), alice = env.add_player{ name = "alice" },
bob = env.add_player("bob"), bob = env.add_player{ name = "bob" },
carol = env.add_player("carol"), carol = env.add_player{ name = "carol" },
} }
env.initialise{ env.initialise{
env.assignment("alice", { "Moderator" }), env.assignment("alice", { "Moderator" }),
+2 -2
View File
@@ -8,8 +8,8 @@ local admin_state = {} --- @type table<string, boolean>
--- alice is a moderator and carol has only the default role, both connected --- alice is a moderator and carol has only the default role, both connected
local function setup(env) local function setup(env)
local players = { local players = {
alice = env.add_player("alice"), alice = env.add_player{ name = "alice" },
carol = env.add_player("carol"), carol = env.add_player{ name = "carol" },
} }
admin_state = {} admin_state = {}
env.Roles.define_permission_trigger("exp_scenario.player.admin", function(player, state) env.Roles.define_permission_trigger("exp_scenario.player.admin", function(player, state)
-1
View File
@@ -30,7 +30,6 @@ require("modules/exp_scenario/commands/me")
require("modules/exp_scenario/commands/rainbow") require("modules/exp_scenario/commands/rainbow")
require("modules/exp_scenario/commands/ratio") require("modules/exp_scenario/commands/ratio")
require("modules/exp_scenario/commands/repair") require("modules/exp_scenario/commands/repair")
require("modules/exp_scenario/commands/reports")
require("modules/exp_scenario/commands/roles") require("modules/exp_scenario/commands/roles")
require("modules/exp_scenario/commands/search") require("modules/exp_scenario/commands/search")
require("modules/exp_scenario/commands/spectate") require("modules/exp_scenario/commands/spectate")
@@ -97,40 +97,6 @@ if config.entity_protection then
end end
end end
--- Reports added and removed
if config.player_reports then
local Reports = require("modules/exp_reports")
--- @param event EventData.ExpReports.on_player_reported
events[Reports.on_player_reported] = function(event)
local player_name, by_player_name = get_player_name(event)
emit_event{
title = "Report",
description = "A player was reported",
color = Colors.yellow,
fields = {
{ name = "Player", inline = true, value = append_playtime(player_name) },
{ name = "By", inline = true, value = append_playtime(by_player_name) },
{ name = "Report Count", inline = true, value = tostring(event.report_count) },
{ name = "Reason", value = event.reason },
},
}
end
--- @param event EventData.ExpReports.on_reports_deleted
events[Reports.on_reports_deleted] = function(event)
local player_name, by_player_name = get_player_name(event)
emit_event{
title = "Reports Removed",
description = "A player has reports removed",
color = Colors.green,
fields = {
{ name = "Player", inline = true, value = append_playtime(player_name) },
{ name = "By", inline = true, value = append_playtime(by_player_name) },
{ name = "Report Count", inline = true, value = tostring(event.count) },
},
}
end
end
--- When a player is jailed or unjailed --- When a player is jailed or unjailed
if config.player_jail then if config.player_jail then
local Jail = require("modules/exp_scenario/control/jail") local Jail = require("modules/exp_scenario/control/jail")
-12
View File
@@ -161,18 +161,6 @@ description=Repairs entities on your force around you.
response-revive=__1__ entities were revived. response-revive=__1__ entities were revived.
response-heal=__1__ entities were healed. response-heal=__1__ entities were healed.
[exp-commands_reports]
description-create=Reports a player and notifies moderators
description-get=Gets a list of all reports that a player has on them. If no player then lists all players and the number of reports on them.
description-clear=Clears all reports from a player or just the report from one player.
arg-player-create=Player you want to report.
arg-player-get=Player to get the reports of.
arg-player-clear=Player to clear the reports of.
arg-reason=Reason you want to report this player.
arg-from-player=Only remove the report from this player.
player-immune=This player can not be reported.
self-report=You cannot report yourself.
[exp-commands_roles] [exp-commands_roles]
description-assign=Assigns a role to a player. description-assign=Assigns a role to a player.
description-unassign=Unassigns a role from a player. description-unassign=Unassigns a role from a player.
-22
View File
@@ -165,28 +165,6 @@ arg-range=半徑
response-revive=__1__ 個建築恢復。 response-revive=__1__ 個建築恢復。
response-heal=回滿 __2__ 個建築耐久。 response-heal=回滿 __2__ 個建築耐久。
[exp-commands_reports]
description-create=檢舉用戶並通知管理員。
description-get=取得用戶的報告清單。如果沒有設定用戶,則列出所有用戶以及有關他們的報告數量。
description-clear=清除一名用戶的所有報告或僅清除一名用戶的報告。
arg-player-create=用戶
arg-player-get=用戶
arg-player-clear=用戶
arg-reason=原因
arg-from-player=用戶
player-immune=用戶不能被舉報
self-report=你不能舉報自己。
response=__1__ 因 __2__ 被舉報了。
response-admin=__1__ 因 __3__ 被 __2__ 舉報了。
already-reported=你已經舉報過該用戶了,你可以讓管理員清除報告來重寫。
not-reported=該用戶沒有被舉報的紀錄。
not-reported-by=該用戶沒有被 __1__ 舉報的紀錄。
reports-title==該用戶現在的被舉報紀錄:
player-title=__1__ 有 __2__ 項被舉報的紀錄:
list-element=__1__: __2__
removed-all=__1__ 被舉報的所有紀錄已被 __2__ 清除。
removed=__1__ 被舉報的一個紀錄已被 __2__ 清除。
[exp-commands_roles] [exp-commands_roles]
description-assign=為用戶指配用戶組。 description-assign=為用戶指配用戶組。
description-unassign=為用戶取消指配用戶組。 description-unassign=為用戶取消指配用戶組。
-22
View File
@@ -165,28 +165,6 @@ arg-range=半徑
response-revive=__1__ 個建築恢復。 response-revive=__1__ 個建築恢復。
response-heal=回滿 __2__ 個建築耐久。 response-heal=回滿 __2__ 個建築耐久。
[exp-commands_reports]
description-create=檢舉用戶並通知管理員。
description-get=取得用戶的報告清單。如果沒有設定用戶,則列出所有用戶以及有關他們的報告數量。
description-clear=清除一名用戶的所有報告或僅清除一名用戶的報告。
arg-player-create=用戶
arg-player-get=用戶
arg-player-clear=用戶
arg-reason=原因
arg-from-player=用戶
player-immune=用戶不能被舉報
self-report=你不能舉報自己。
response=__1__ 因 __2__ 被舉報了。
response-admin=__1__ 因 __3__ 被 __2__ 舉報了。
already-reported=你已經舉報過該用戶了,你可以讓管理員清除報告來重寫。
not-reported=該用戶沒有被舉報的紀錄。
not-reported-by=該用戶沒有被 __1__ 舉報的紀錄。
reports-title==該用戶現在的被舉報紀錄:
player-title=__1__ 有 __2__ 項被舉報的紀錄:
list-element=__1__: __2__
removed-all=__1__ 被舉報的所有紀錄已被 __2__ 清除。
removed=__1__ 被舉報的一個紀錄已被 __2__ 清除。
[exp-commands_roles] [exp-commands_roles]
description-assign=為用戶指配用戶組。 description-assign=為用戶指配用戶組。
description-unassign=為用戶取消指配用戶組。 description-unassign=為用戶取消指配用戶組。
+10 -4
View File
@@ -100,17 +100,23 @@ function Stubs.new()
get_player = function(key) return players[key] end, get_player = function(key) return players[key] end,
}, { "player" }) }, { "player" })
--- @class Stubs.PlayerParams
--- @field name string
--- @field connected boolean? Defaults to true
--- @field admin boolean? Defaults to false
--- Add a player to the stubbed game, indexes are assigned in join order --- Add a player to the stubbed game, indexes are assigned in join order
--- @param name string --- @param params Stubs.PlayerParams
--- @param is_connected boolean? Defaults to connected
--- @return Stubs.Player --- @return Stubs.Player
function stubs.add_player(name, is_connected) function stubs.add_player(params)
local name = params.name
local index = #players_by_index + 1 local index = #players_by_index + 1
--- @class Stubs.Player --- @class Stubs.Player
local player = Stubs.strict("LuaPlayer " .. name, { local player = Stubs.strict("LuaPlayer " .. name, {
name = name, name = name,
index = index, index = index,
connected = is_connected ~= false, connected = params.connected ~= false,
admin = params.admin == true,
valid = true, valid = true,
play_sound = function(opts) play_sound = function(opts)
stubs.sounds[#stubs.sounds + 1] = name .. ":" .. opts.path stubs.sounds[#stubs.sounds + 1] = name .. ":" .. opts.path