Skip to content

Commit 0d47c42

Browse files
committed
fixed compatibility with mcdr 2.6, supported language preference, !!seen reload
1 parent 0aff79d commit 0d47c42

File tree

10 files changed

+262
-132
lines changed

10 files changed

+262
-132
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
seen.json
22
.vscode/settings.json
33
.idea
4+
5+
*.mcdr

lang/en_us.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,18 @@ mcd_seen.text.top_normal: §dplayer only§r
2828
mcd_seen.text.top_bot: §5bot only§r
2929
mcd_seen.text.top_merge: §7all players§r/§emerged§r
3030
mcd_seen.text.top_all: §7all players§r
31+
mcd_seen.text.reloaded: Plugin reloaded
3132

3233
# Hover texts
3334
mcd_seen.hover.help_msg_suggest: "Click to fill {}"
3435
mcd_seen.hover.query_player: "Click to query player {}"
3536
mcd_seen.hover.show_help: "Click to show help"
3637

3738
# Format texts
38-
mcd_seen.fmt.delta_time: "sec min hrs day"
39-
mcd_seen.fmt.seen_top: "Here are the {} players §cofflined§r for the longest time({}):"
40-
mcd_seen.fmt.seen_top_full: "Here are all the players' offline time data({})"
41-
mcd_seen.fmt.liver_top: "Here are the players §acurrently online§r({}):"
39+
mcd_seen.fmt.time_seen: "sec min hrs day"
40+
mcd_seen.fmt.seen_top: "Here are the {num} players §cofflined§r for the longest time({arg}):"
41+
mcd_seen.fmt.seen_top_full: "Here are all the players' offline time data({arg})"
42+
mcd_seen.fmt.liver_top: "Here are the players §acurrently online§r({arg}):"
4243

4344
# Error texts
4445
mcd_seen.error.player_data_not_found: Player data not found! Click here for help

lang/zh_cn.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,18 @@ mcd_seen.text.top_normal: §d仅真人玩家§r
2828
mcd_seen.text.top_bot: §5仅假人§r
2929
mcd_seen.text.top_merge: §7所有玩家§r/§e合并显示§r
3030
mcd_seen.text.top_all: §7所有玩家§r
31+
mcd_seen.text.reloaded: 插件已重载
3132

3233
# Hover texts
3334
mcd_seen.hover.help_msg_suggest: "点击以填入§7{}§r"
3435
mcd_seen.hover.query_player: "点击以查询玩家§e{}§r的数据"
3536
mcd_seen.hover.show_help: "点击以获取插件帮助信息"
3637

3738
# Format texts
38-
mcd_seen.fmt.delta_time: "秒 分 小时 天"
39-
mcd_seen.fmt.seen_top: "摸鱼榜前{}的§c鸽子§r({})如下: "
40-
mcd_seen.fmt.seen_top_full: "摸鱼榜全部§c鸽子§r({})如下: "
41-
mcd_seen.fmt.liver_top: "当前在线的§a肝帝§r({})如下: "
39+
mcd_seen.fmt.time_seen: "秒 分 小时 天"
40+
mcd_seen.fmt.seen_top: "摸鱼榜前§6{num}§r的§c鸽子§r({arg})如下: "
41+
mcd_seen.fmt.seen_top_full: "摸鱼榜全部§c鸽子§r({arg})如下: "
42+
mcd_seen.fmt.liver_top: "当前在线的§a肝帝§r({arg})如下: "
4243

4344
# Error texts
4445
mcd_seen.error.player_data_not_found: 没有该玩家的数据

mcd_seen/__init__.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
from mcdreforged.api.types import Info, PluginServerInterface
33
from mcdreforged.api.decorator import new_thread
44

5-
from mcd_seen.constants import SEEN_PREFIX, META
6-
from mcd_seen.utils import verify_player_name, bot_name, tr, logger
5+
from mcd_seen.utils import verify_player_name, bot_name, tr, logger, psi
76
from mcd_seen.storage import storage, bot_list
87
from mcd_seen.config import config
98
from mcd_seen.interface import register_command
@@ -29,13 +28,18 @@ def on_server_stop(*args, **kwargs):
2928
storage.correct([])
3029

3130

32-
@new_thread(META.name + '_PluginLoad')
31+
def on_unload(*args, **kwargs):
32+
logger.unset_file()
33+
34+
35+
@new_thread(psi.get_self_metadata().name + '_PluginLoad')
3336
def warn_first_load():
3437
logger.warning('Load Seen plugin when server is empty is suggested to make sure all the datas are right')
3538

3639

3740
def on_load(server: PluginServerInterface, prev_module):
38-
server.register_help_message(SEEN_PREFIX, tr('mcd_seen.text.reg_help_msg'))
41+
for prefix in config.seen_prefix:
42+
server.register_help_message(prefix, tr('mcd_seen.text.reg_help_msg'))
3943
register_command(server)
4044
if prev_module is not None:
4145
try:

mcd_seen/config.py

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,76 @@
11
import json
22

3-
from mcd_seen.constants import CONFIG_FILE
4-
3+
from typing import Union, List
54
from mcdreforged.api.utils import Serializable
65
from mcdreforged.api.types import ServerInterface
76

7+
from mcd_seen.constants import CONFIG_FILE
8+
9+
10+
psi = ServerInterface.get_instance().as_plugin_server_interface()
11+
812

913
class Config(Serializable):
14+
primary_prefix: Union[str, List[str]] = '!!seen'
15+
primary_rank_prefix: Union[str, List[str]] = '!!seen-top'
16+
secondary_rank_prefix: Union[str, List[str]] = '!!liver-top'
1017
seen_top_max: int = 10
1118
player_prior_in_merge: bool = True
1219
log_seens: bool = True
1320
identify_bot: bool = True
1421
bot_list_delay: float = 0.3
22+
verbosity: bool
23+
debug_commands: bool
24+
debug_prefixes: Union[str, List[str]]
25+
26+
@staticmethod
27+
def get_iterable(original: Union[str, List[str]]) -> List[str]:
28+
if isinstance(original, str):
29+
return [original]
30+
return original
31+
32+
@property
33+
def seen_prefix(self):
34+
return self.get_iterable(self.primary_prefix)
35+
36+
@property
37+
def seen_top_prefix(self):
38+
return self.get_iterable(self.primary_rank_prefix)
39+
40+
@property
41+
def liver_top_prefix(self):
42+
return self.get_iterable(self.secondary_rank_prefix)
43+
44+
@property
45+
def debug_prefix(self):
46+
return self.get_iterable(self.serialize().get('debug_prefixes', '!!liver'))
47+
48+
@property
49+
def prefixes(self):
50+
result = []
51+
for item in [self.seen_prefix, self.seen_top_prefix, self.liver_top_prefix]:
52+
result += item
53+
return result
54+
55+
@property
56+
def verbose_mode(self):
57+
return self.serialize().get('verbosity', False)
58+
59+
@property
60+
def debug(self):
61+
return self.serialize().get('debug_commands', False)
1562

1663
def save(self) -> None:
1764
with open(CONFIG_FILE, 'w', encoding='UTF-8') as f:
1865
json.dump(self.serialize(), f, indent=4, ensure_ascii=False)
1966

2067
@classmethod
2168
def load(cls) -> 'Config':
22-
return ServerInterface.get_instance().as_plugin_server_interface().load_config_simple(
23-
CONFIG_FILE, default_config=cls.get_default().serialize(), in_data_folder=False, echo_in_console=True,
69+
return psi.load_config_simple(
70+
CONFIG_FILE,
71+
default_config=cls.get_default().serialize(),
72+
in_data_folder=False,
73+
echo_in_console=True,
2474
target_class=cls
2575
)
2676

mcd_seen/constants.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
11
import os
2-
from mcdreforged.api.types import ServerInterface
3-
4-
# Command prefixes
5-
SEEN_PREFIX = '!!seen'
6-
SEEN_TOP_PREFIX = '!!seen-top'
7-
LIVER_TOP_PREFIX = '!!liver-top'
8-
DEBUG_PREFIX = '!!liver'
92

103

114
def ensure(folder: str):
@@ -18,11 +11,7 @@ def ensure(folder: str):
1811
DATA_FOLDER = ensure('config/seen')
1912
CONFIG_FILE = os.path.join(DATA_FOLDER, 'config.json')
2013
SEENS_FILE = os.path.join(DATA_FOLDER, 'seen.json')
21-
LOG_FILE = os.path.join(DATA_FOLDER, 'player_seens.log')
14+
LOG_FILE = os.path.join(DATA_FOLDER, 'logs', 'seen.log')
2215
SEENS_PATH_OLD = ['seen.json', 'config/seen.json']
23-
24-
# Plugin Metadata
25-
META = ServerInterface.get_instance().get_plugin_metadata('mcd_seen')
26-
27-
# Debug mode
28-
DEBUG_MODE = False
16+
OLD_LOG_FILE = os.path.join(DATA_FOLDER, 'player_seens.log')
17+
NEW_LOG_PATH = os.path.join(DATA_FOLDER, 'logs', 'old_seens.log')

mcd_seen/interface.py

Lines changed: 59 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
import re
1+
from typing import Callable, Any, List, Union, Optional
22

3-
from mcdreforged.api.types import CommandSource, PluginServerInterface
43
from mcdreforged.api.command import *
5-
from mcdreforged.api.utils import Serializable
64
from mcdreforged.api.rtext import *
7-
from typing import Callable, Any, List, Union, Optional
5+
from mcdreforged.api.types import CommandSource, PluginServerInterface
6+
from mcdreforged.api.utils import Serializable
87

9-
from mcd_seen.storage import storage, PlayerSeen
10-
from mcd_seen.constants import *
118
from mcd_seen.config import config
12-
from mcd_seen.utils import tr, delta_time, formatted_time, bot_name
9+
from mcd_seen.storage import storage, PlayerSeen
10+
from mcd_seen.utils import tr, delta_time, bot_name, psi, ntr, htr, fmt_time_tr
1311

1412
TOP_OPTIONS = {
1513
'-bot': 'bot',
@@ -36,7 +34,7 @@ def parse(cls, arg_string: Optional[str], liver: bool = False):
3634
data[mode] = True
3735
args.remove(arg)
3836
data = cls.deserialize(data)
39-
# Confict check
37+
# Conflict check
4038
if [data.all, data.merge, data.bot].count(True) > 1 or (data.full and liver) or (len(args) != 0):
4139
raise IllegalArgument(f'Illegal argument: {arg_string}', 1)
4240
if liver and not data.get_all:
@@ -55,7 +53,12 @@ def text(self):
5553
ret.append(tr(f'text.top_{o}'))
5654
if len(ret) == 0:
5755
ret.append(tr('text.top_normal'))
58-
return '/'.join(ret).strip('/')
56+
return RTextBase.join('/', ret)
57+
58+
59+
def reload_self(source: CommandSource):
60+
psi.reload_plugin(psi.get_self_metadata().id)
61+
source.reply(tr('text.reloaded'))
5962

6063

6164
def register_command(server: PluginServerInterface):
@@ -66,25 +69,31 @@ def exe(func: Union[Callable[[CommandSource, str], Any], Callable[[CommandSource
6669

6770
# !!seen
6871
server.register_command(
69-
Literal(SEEN_PREFIX).on_child_error(CommandError, cmd_error, handled=True).runs(show_help).then(
72+
Literal(config.seen_prefix).on_child_error(
73+
CommandError, cmd_error, handled=True).runs(show_help).then(
74+
Literal('reload').runs(reload_self)
75+
).then(
7076
QuotableText('player').runs(exe(seen))
7177
)
7278
)
7379
# !!seen-top
7480
server.register_command(
75-
Literal(SEEN_TOP_PREFIX).on_child_error(CommandError, cmd_error, handled=True).runs(exe(seen_top, True)).then(
81+
Literal(config.seen_top_prefix).on_child_error(
82+
CommandError, cmd_error, handled=True).runs(exe(seen_top, True)).then(
7683
GreedyText('exarg').runs(exe(seen_top))
7784
)
7885
)
7986
# !!liver
8087
server.register_command(
81-
Literal(LIVER_TOP_PREFIX).on_child_error(CommandError, cmd_error, handled=True).runs(exe(liver_top, True)).then(
88+
Literal(config.liver_top_prefix).on_child_error(
89+
CommandError, cmd_error, handled=True).runs(exe(liver_top, True)).then(
8290
QuotableText('exarg').runs(exe(liver_top))
8391
)
8492
)
85-
if DEBUG_MODE:
93+
if config.debug:
8694
server.register_command(
87-
Literal(DEBUG_PREFIX).requires(lambda src: src.has_permission(4), lambda: 'Permission denied').then(
95+
Literal(config.debug_prefix).requires(
96+
lambda src: src.has_permission(4), lambda: 'Permission denied').then(
8897
Literal('remove').then(
8998
GreedyText('players').runs(exe(__remove_player_data))
9099
)
@@ -93,49 +102,51 @@ def exe(func: Union[Callable[[CommandSource, str], Any], Callable[[CommandSource
93102

94103

95104
def show_help(source: CommandSource):
96-
help_message = tr(
97-
'help_msg', SEEN_PREFIX, SEEN_TOP_PREFIX, LIVER_TOP_PREFIX, META.name, str(META.version)
98-
).strip().splitlines()
99-
help_msg_rtext = ''
100-
for line in help_message:
101-
if help_msg_rtext != '':
102-
help_msg_rtext += '\n'
103-
for PREFIX in [SEEN_PREFIX, SEEN_TOP_PREFIX, LIVER_TOP_PREFIX]:
104-
result = re.search(r'(?<=§7){}[\S ]*?(?=§)'.format(PREFIX), line)
105-
if result is not None:
106-
break
107-
if result is not None:
108-
cmd = result.group().strip() + ' '
109-
help_msg_rtext += RText(line).c(RAction.suggest_command, cmd).h(
110-
tr("hover.help_msg_suggest", cmd.strip()))
111-
else:
112-
help_msg_rtext += line
113-
source.reply(help_msg_rtext)
105+
meta = psi.get_self_metadata()
106+
msg = htr(
107+
'help_msg',
108+
config.seen_prefix[0],
109+
config.seen_top_prefix[0],
110+
config.liver_top_prefix[0],
111+
meta.name,
112+
str(meta.version)
113+
)
114+
source.reply(msg)
114115

115116

116117
# Text layout
117118
def top(top_players: List[PlayerSeen], prefix: Union[RTextBase, str]):
118-
ret, num = RTextList(prefix), 1
119+
ret, num = [prefix], 1
119120
for p in top_players:
120-
ret.append(f'\n{num}. ', seen_format(p))
121+
ret.append(RTextList(f'{num}. ', seen_format(p)))
121122
num += 1
122-
return ret
123+
return RTextBase.join('\n', ret)
123124

124125

125126
def seen_format(player: PlayerSeen):
126-
ret = ''
127+
return tr('text', player=player).set_translator(seen_fmt_tr)
128+
129+
130+
def seen_fmt_tr(translation_key: str, player: PlayerSeen, language: Optional[str] = None, allow_failure: bool = True):
131+
def ttr(key: str, *args, **kwargs):
132+
return ntr(f'{translation_key}.{key}', *args, language=language, allow_failure=allow_failure, **kwargs)
133+
ret = []
127134
# Bot/Player
128-
ret += {}{}§e'.format('5' if player.is_bot else 'd',
129-
tr(f'text.{"bot" if player.is_bot else "player"}').capitalize())
135+
color = '§5' if player.is_bot else '§d'
136+
ret.append(f"{color}{ttr('bot' if player.is_bot else 'player').capitalize()}§r")
130137
# <player_name>
131-
ret += f' §e{player.actual_name}§r '
138+
ret.append(f'§e{player.actual_name}§r')
132139
# has been online/offline for
133-
ret += tr(f'text.{"bot_liver" if player.is_bot else "player_liver"}') if player.online else tr('text.seen')
140+
ret.append(ttr('bot_liver' if player.is_bot else 'player_liver') if player.online else ttr('seen'))
134141
# sec min hrs day
135-
ret += formatted_time(delta_time(player.target))
136-
return RText(ret).h(tr('hover.query_player', player.actual_name)).c(
137-
RAction.run_command, '{} {}'.format(SEEN_PREFIX, player.actual_name)
142+
ret.append(fmt_time_tr(
143+
'mcd_seen.fmt.time_seen', t=delta_time(player.target), language=language, allow_failure=allow_failure))
144+
145+
ret = ' '.join(ret)
146+
ret = RText(ret).h(tr('hover.query_player', player.actual_name)).c(
147+
RAction.run_command, '{} {}'.format(config.seen_prefix[0], player.actual_name)
138148
)
149+
return ret
139150

140151

141152
def seen(source: CommandSource, player: str):
@@ -163,7 +174,7 @@ def seen_top(source: CommandSource, exarg: str = None, liver: bool = False):
163174
# -full
164175
sorted_list = sorted_list if args.full else sorted_list[:config.seen_top_max]
165176
# get prefix
166-
prefix = tr(f'fmt.seen_top{"_full" if args.full else ""}', config.seen_top_max, args.text)
177+
prefix = tr(f'fmt.seen_top{"_full" if args.full else ""}', num=config.seen_top_max, arg=args.text)
167178
if liver:
168179
prefix = tr('fmt.liver_top', args.text)
169180

@@ -176,10 +187,8 @@ def liver_top(source: CommandSource, exarg: str = None):
176187

177188
def cmd_error(source: CommandSource):
178189
source.reply(
179-
RText(
180-
tr('mcd_seen.error.cmd_error'), color=RColor.red
181-
).c(
182-
RAction.run_command, SEEN_PREFIX
190+
tr('mcd_seen.error.cmd_error').set_color(color=RColor.red).c(
191+
RAction.run_command, config.seen_prefix[0]
183192
).h(
184193
tr('mcd_seen.hover.show_help')
185194
)
@@ -188,10 +197,8 @@ def cmd_error(source: CommandSource):
188197

189198
def player_data_not_found(source: CommandSource):
190199
source.reply(
191-
RText(
192-
tr('mcd_seen.error.player_data_not_found'), color=RColor.red
193-
).c(
194-
RAction.run_command, SEEN_PREFIX
200+
tr('mcd_seen.error.player_data_not_found').set_color(color=RColor.red).c(
201+
RAction.run_command, config.seen_prefix[0]
195202
).h(
196203
tr('mcd_seen.hover.show_help')
197204
)

0 commit comments

Comments
 (0)