|
4 | 4 | import time |
5 | 5 | import json |
6 | 6 | import re |
| 7 | +import math |
7 | 8 |
|
8 | 9 | __all__ = ['CmdReposter'] |
9 | 10 |
|
@@ -44,17 +45,18 @@ def __init__(self, logger, core, config_file): |
44 | 45 | # available commands |
45 | 46 | self.cmd_available = { |
46 | 47 | 'tp': self.tp_request, |
47 | | - # TODO: tphere |
48 | 48 | 'tps': self.ask_tps, |
49 | 49 | 'time': self.ask_time, |
50 | | - 'restart': self.restart_request, |
| 50 | + # 'restart': self.restart_request, |
| 51 | + 'here': self.broadcast_pos, |
51 | 52 | } |
52 | 53 |
|
53 | 54 | self.tp_log = {} |
54 | 55 |
|
55 | 56 | # queue |
56 | 57 | self.repost_remained = [] |
57 | 58 | self.repost_receiver = [] |
| 59 | + self.player_pos_map = {} |
58 | 60 |
|
59 | 61 | self.timer = QTimer(self) |
60 | 62 |
|
@@ -84,11 +86,43 @@ def check_repost(self, line): |
84 | 86 | del self.repost_receiver[0] |
85 | 87 | self.check_repost(line) |
86 | 88 |
|
| 89 | + def check_player_nbt(self, line): |
| 90 | + match_obj_1 = re.match(r'[^<>]*?\[Server thread/INFO\].*?: (.*)$', line) |
| 91 | + text = match_obj_1.group(1) if match_obj_1 else '' |
| 92 | + match_obj_2 = re.match(r'^(\w+) has the following entity data: (.*)$', text) |
| 93 | + if match_obj_2: |
| 94 | + # got player entity data |
| 95 | + player = match_obj_2.group(1) |
| 96 | + if player not in self.player_pos_map: |
| 97 | + return |
| 98 | + match_obj_pos = re.match(r'\[(.*?)d, (.*?)d, (.*?)d\]', match_obj_2.group(2)) |
| 99 | + match_obj_dim = re.match(r'"(minecraft:\w+)"', match_obj_2.group(2)) |
| 100 | + player_nbt = self.player_pos_map[player] |
| 101 | + if match_obj_pos: |
| 102 | + player_nbt['pos'] = ( |
| 103 | + math.floor(float(match_obj_pos.group(1)) + 0.5), # x |
| 104 | + math.ceil(float(match_obj_pos.group(2))), # y |
| 105 | + math.floor(float(match_obj_pos.group(3)) + 0.5), # z |
| 106 | + ) |
| 107 | + self.logger.debug('CmdReposter parsed player Pos data: {}'.format(player_nbt['pos'])) |
| 108 | + if match_obj_dim: |
| 109 | + player_nbt['dim'] = match_obj_dim.group(1) |
| 110 | + self.logger.debug('CmdReposter parsed player Dimension data: {}'.format(player_nbt['dim'])) |
| 111 | + if player_nbt['pos'] is not None and player_nbt['dim'] is not None: |
| 112 | + x, y, z = player_nbt['pos'] |
| 113 | + dim = player_nbt['dim'] |
| 114 | + output_string = f'[x:{x}, y:{y}, z:{z}, dim:{dim}]' |
| 115 | + cmd = f'execute as {player} run say {output_string}' |
| 116 | + self.logger.debug('CmdReposter generated position broadcast: {}'.format(output_string)) |
| 117 | + self.core.write_server(cmd) |
| 118 | + del self.player_pos_map[player] |
| 119 | + |
87 | 120 | @QtCore.pyqtSlot(list) |
88 | 121 | def on_server_output(self, lines): |
89 | 122 | for line in lines: |
90 | 123 | self.check_tp(line) |
91 | 124 | self.check_repost(line) |
| 125 | + self.check_player_nbt(line) |
92 | 126 |
|
93 | 127 | @QtCore.pyqtSlot(tuple) |
94 | 128 | def on_player_input(self, pair): |
@@ -166,5 +200,10 @@ def ask_time(self, player, text_list): |
166 | 200 | else: |
167 | 201 | self.utils.tell(player, 'Command not acceptable. Please check again.') |
168 | 202 |
|
169 | | - def restart_request(self, player, text_list): |
170 | | - pass |
| 203 | + def broadcast_pos(self, player, text_list): |
| 204 | + self.logger.debug('CmdReposter.broadcast_pos called') |
| 205 | + self.player_pos_map[player] = { 'pos': None, 'dim': None } |
| 206 | + # Reference (CN): https://zh.minecraft.wiki/w/%E5%91%BD%E4%BB%A4/data |
| 207 | + self.core.write_server(f'data get entity {player} Pos') |
| 208 | + self.core.write_server(f'data get entity {player} Dimension') |
| 209 | + # Wait for `check_player_nbt` |
0 commit comments