From 32f8aa66f5a4a06914cce93f49cadd6e354c5e55 Mon Sep 17 00:00:00 2001 From: HIM049 <67405384+HIM049@users.noreply.github.com> Date: Mon, 13 Feb 2023 23:04:11 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=9F=BA=E6=9C=AC=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hibernate_r/__init__.py | 196 ++++++++++++++++++ .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 11178 bytes .../__pycache__/byte_utils.cpython-311.pyc | Bin 0 -> 2801 bytes hibernate_r/byte_utils.py | 57 +++++ mcdreforged.plugin.json | 18 ++ 5 files changed, 271 insertions(+) create mode 100644 hibernate_r/__init__.py create mode 100644 hibernate_r/__pycache__/__init__.cpython-311.pyc create mode 100644 hibernate_r/__pycache__/byte_utils.cpython-311.pyc create mode 100644 hibernate_r/byte_utils.py create mode 100644 mcdreforged.plugin.json diff --git a/hibernate_r/__init__.py b/hibernate_r/__init__.py new file mode 100644 index 0000000..c0e8e4b --- /dev/null +++ b/hibernate_r/__init__.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import time +import socket +import json +import threading +import uuid +import os.path +import base64 + +from mcdreforged.api.all import * +from .byte_utils import * +import online_player_api as lib_online_player + + +# def on_load(server: PluginServerInterface, old_module): +# server.logger.info("插件已加载") + + +# 服务器启动事件 +@new_thread +def on_server_startup(server: PluginServerInterface): + server.logger.info("事件:服务器启动") + time.sleep(5) + check_player_num(server) + +# 玩家加入事件 +@new_thread +def on_player_left(server: PluginServerInterface, player): + server.logger.info("事件:玩家退出") + time.sleep(5) + check_player_num(server) + +# 倒数并关闭服务器 +@spam_proof +def check_player_num(server: PluginServerInterface): + if len(lib_online_player.get_player_list()) == 0: + + check_config_fire(server) + with open("config/HibernateR.json", "r") as file: + config = json.load(file) + wait_min = config["wait_min"] + + time.sleep(wait_min *60) + if len(lib_online_player.get_player_list()) == 0: + server.logger.info("倒计时结束,关闭服务器") + server.stop() + time.sleep(10) + fake_server(server) + else: + server.logger.info("服务器内仍有玩家") + else: return + +# FakeServer部分 +@spam_proof +def fake_server(server: PluginServerInterface): + + check_config_fire(server) + with open("config/HibernateR.json", "r") as file: + config = json.load(file) + fs_ip = config["ip"] + fs_port = config["port"] + fs_samples = config["samples"] + fs_motd = config["motd"]["1"] + "\n" + config["motd"]["2"] + fs_icon = None + fs_kick_message = "" + + for message in config["kick_message"]: + fs_kick_message += message + "\n" + + if not os.path.exists(config["server_icon"]): + server.logger.warning("未找到服务器图标,设置为None") + else: + with open(config["server_icon"], 'rb') as image: + fs_icon = "data:image/png;base64," + base64.b64encode(image.read()).decode() + + while True: + try: + server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) + server_socket.bind((fs_ip, fs_port)) + server_socket.settimeout(5000) + except: + server.logger.error("伪装服务端启动失败") + server_socket.close() + time.sleep(1) + else: + server.logger.info("伪装服务端已启动") + break + + server_socket.listen(5) + server.logger.info("开始监听端口") + try: + while True: + server.logger.info("等待连接") + client_socket, client_address = server_socket.accept() + try: + recv_data = client_socket.recv(1024) + client_ip = client_address[0] + (length, i) = read_varint(recv_data, 0) + (packetID, i) = read_varint(recv_data, i) + + if packetID == 0: + (version, i) = read_varint(recv_data, i) + (ip, i) = read_utf(recv_data, i) + + ip = ip.replace('\x00', '').replace("\r", "\\r").replace("\t", "\\t").replace("\n", "\\n") + is_using_fml = False + if ip.endswith("FML"): + is_using_fml = True + ip = ip[:-3] + (port, i) = read_ushort(recv_data, i) + (state, i) = read_varint(recv_data, i) + if state == 1: + server.logger.info("伪装服务器收到了一次ping: %s" % (recv_data)) + motd = {} + motd["version"] = {} + motd["version"]["name"] = "Sleeping" + motd["version"]["protocol"] = 2 + motd["players"] = {} + motd["players"]["max"] = 10 + motd["players"]["online"] = 10 + motd["players"]["sample"] = [] + + for sample in fs_samples: + motd["players"]["sample"].append( + {"name": sample, "id": str(uuid.uuid4())}) + + motd["description"] = {"text": fs_motd} + if fs_icon and len(fs_icon) > 0: + motd["favicon"] = fs_icon + write_response(client_socket, json.dumps(motd)) + + elif state == 2: + server.logger.info("伪装服务器收到了一次连接请求: %s" % (recv_data)) + + # TM判断写一大堆,数据发过来一瞅总是少一截,离大谱。 + # 找这个原因最起码花了我四五个小时 + # 直接全部删掉,不是ping直接返回、 + write_response(client_socket, json.dumps({"text": fs_kick_message})) + start_server(server) + return + elif packetID == 1: + (long, i) = read_long(recv_data, i) + response = bytearray() + write_varint(response, 9) + write_varint(response, 1) + bytearray.append(long) + client_socket.sendall(bytearray) + server.logger.info("Responded with pong packet.") + else: + server.logger.warning("收到了意外的数据包") + + except (TypeError, IndexError): # 错误处理(类型错误或索引错误) + server.logger.warning("[%s:%s]收到了无效数据(%s)" % (client_ip, client_address[1], recv_data)) + except Exception as e: + server.logger.error(e) + except: + server.logger.info("关闭套接字") + server_socket.close() + +# 启动服务器 +def start_server(server: PluginServerInterface): + server.logger.info("启动服务器") + server.start() + +@new_thread +def check_config_fire(server: PluginServerInterface): + if os.path.exists("config/HibernateR.json"): + pass + else: + server.logger.warning("未找到配置文件!正在以默认值创建") + crative_config_fire() + return + +def crative_config_fire(): + config = {} + config["wait_min"] = 10 + config["ip"] = "0.0.0.0" + config["port"] = 25565 + config["protocol"] = 2 + config["motd"] = {} + config["motd"]["1"] = "§4Maintenance!" + config["motd"]["2"] = "§aCheck example.com for more information!" + config["version_text"] = "§4Maintenance" + config["kick_message"] = ["§bSorry", "", "§aThis server is offline!"] + config["server_icon"] = "server_icon.png" + config["samples"] = ["§bexample.com", "", "§4Maintenance"] + config["show_ip_if_hostname_available"] = True + config["player_max"] = 0 + config["player_online"] = 0 + + with open("config/HibernateR.json","w") as file: + json.dump(config, file, sort_keys=True, indent=4, ensure_ascii=False) + return diff --git a/hibernate_r/__pycache__/__init__.cpython-311.pyc b/hibernate_r/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f51be9aaf66468c39f62d5b5aab655815a8c20da GIT binary patch literal 11178 zcmd5?e^49Oo!^yK(h9Bk{bL0Ji(s&YL4ZxLjU6Z082_l!N%$OCH$L7c4nXJ)!?s)8Jjfg4ig$H5X2mi!-78Zv+3m zL>P_GF=LFm@U-??@Dqu<|nZRP5V(HGu`zB(VB z`)Txr`MW5kcMXbh%s(>1ath(~4f_>B@Q$;JfgfYp2_=8%6gza$(ov;1HF6q^mTL{IeGj@N9#e)Sx?V_zP`hKCnv@NBVHeW za=&+w<$NB2?K^oYPP)01ZnxLx72Iyu#CfH_?{jOl>gELxCj=(Ad`PGirPvPMG6oBdw1cfuZ*C{gC_>Oi1)y3=lN+Ur@&owzx8EN-v<6ht0ogf*g1}{4O@|_RgSh@1i z?dyNP@`E4!{>E(d(m&n3@`t3`%uD`f)^?7ZKIjxF*jP)r6W8Oix z-#6y8?Ly~r ziS3nvkZ{@kihHJORS!HhK=r;vB7Z<$lD8Ih@7}$&*f)!8p?bNfc7}|S)NIb&wou>Y zof7GgNry-}mMyuz&2z|k%~IZGId8LM*&#dw~7Yp%)H4-!t1Y)3Z$F&mNrPp6{LQo#|bs%0fnoS|?NM#Q1YFRmpaVYL}^Y zG5$ny@@MM!La4~kh?0(4{b#jAhtu>~0}g(gjYEy5+BnpZ={7FA@26Tl28WqC+cvE^ zr~eIXlRh~pr}P=NihyrJO1J^OjmdAultPmipuid7=43buoq|=|l!?iiB0T5t|aD$aEjJMbd0g4 z#{qlpO>LEQ{Y-9F3*|6*LQzuRXu`$@a~{Nsrl%f8gFnlq+g-Ir(R%o=n2XGq851g! zibs)EP@Pa7r=YHL<8&G~Vdc}yK4l47!f1_^<&%;M$3DN*&pUj zOE{%I<8si)^g&`cYb^`XXt|Q*n1b}01-+?#0j-#_98;JX$9J#>&E%;u(TXz5F-4g% zAzx)#V!%jmOPE7jl2W6Ij?5Hi>Knj(dTo6%y8^mXS}hr$DankLmh-jCT$&jN^_2&R zSC$zMa+T7Uul_%^-N(XZpTYA4# zQ^=nxNS6v0tRYo6RS+y>Y}z_fPQA|FP2D|gnC0$B;6bpNjv4Xj4 z)<@|BwMQA$S{YLuTi5^31N6e0VD1H&7t(WzV_s~E_F_SrS&!CxOf904IcDlq?uHER zM#NQPIo0rb2zRE$+O#IO0dYrATB)*)h#NG(4A(hj%M45E3_k>7SuSW3_9dCZfh0Xz z8>iDpReJdu*VQaLIlGr>3L3pQ|-Vw@ppf;cTGj&L|d zo=QU-HpWAO8KXD7$Klu#aR^v}VTfm8Z4m+AFSyvto_cV8Y3iT>V{=9@eeLxW z?jyDLBtD60v-O;Q_MNOX#M-slo~iXg*AOW6{#bg>9ladNG>29niq1Qs5EFh*P)xjM zd}55{6=K{kFbdwH;5iDuS-}+Qv=?x?ahB&jBdlVHfoNXXRtC_hUb*^{mFGW=&MYK% z!LNV15`GRg%y&Ng^!6to-n#a2uiwWiI&SbnDdQ15?cQ=h|NX<(>4xpv;?GK)hetPN7zx;6JyKi|hh@v3_ICdYmUeKN7?&D^73GnxI zDf+IS?z?~b^Pm45sLMzjaL$!iK7ume`uN+ou1&AJ|Hg#ZH`4B??h3UKuAgAm( zL9s9_Kg4+_1f<_I>^ZA8g6l74PAl)7pZ;>?XV0Qc-bLuag^E6wpYZz_mT^pag;Nfo zM;sHLq0_A3QfoU=#FdLLMc@4X?bj}@d~adp#Sf#im+s?F-N)Mls1JQ3DRw2i^1T^N zX5)R_89*BY4K#_qbp>iX`oR@v3s(hP4y}AR2l5csqUik4@g_XNDaFX112}|N0S?79 z>EV2+3XNJvQOtvFt*mdz&j32Yu^vV-GOYS#x$3_ze1caf70Qmm zK8jgQZ48gl||dN|H=UZJ$8u^gFrNX0WYrkIbMpJ4Z@CCfPgo#32CoA;hWg@F#{ ztW;4XZar!ww5(7J!@L{pg$Z7&$;bgBZZ!~7H5`aQ-BQT|BF%D`;wHqPj(^1(hvT)D zvkr}US)bsJHDqq=)59=OY91AC=&T!=55*h{g1i_3UK@eB#Jw=I)UJD=liP}NyaDBy z^78Hg4;{!oJU+%DYXzqd0-O_Y^+@JX!~kRsDhyf*4F;%MoaGU=jZm_$bsBtDgLEKo z8~k}3fP`u6k4DT;IyWp4l`>H&5|ztltC(9iub0dXvbh0JEko@Bk%^HR5FQru03$OX zj4YLx3{6rRMwTT77}Z?sZ1?ouNG_aI%=)JHMGDG7X1U;@>4Py=s9(;l4tGkq8|T{= z>fYaVtw!FoOUm5^qPd0OmD1CP5!B|Ai<~Gum+H-!B2-0aa=!T0rzNU!=J3qnsKq+F z^`%`e>YU3+C!Vm2%;R`C`fH zlC4O+c>rIijg-26Q7X4|{Hpdh^`F;&*6`~FspYWTa(Job=wi!JspYuba$G7sKC=&@ ziUYV7P4f}3IDjK$F`b_(lS;<`#x;eFl%a4{XE7Hp+aJ2x^FiJFu21UZ_HN1EBijKb zj8L{EYW*U${;i{OZQCbCdE22cj!0CWO!bLWpBjo##;_qgDXwdhsAidJ7OCb$v@i(Q z%T&Ec)vr>RwI~ToCK1I5Rd8?BsyCO%s&U;SK#-0{Bx;vT?GmY7sxrissA?H%n5x#W z%QG5~IRn{5B`iWEv15k9C4ycg=um+~RLDeyNK`~pkGeKVM1xE;h(yDxZVzs#TGc&j z-jD*AhM>V+GUXB}SEOP4Qp0154Ub6;yX6MJQJphApR_?kS;yT z2j-51T9&ID<_E6fQgypr-G2Gt+>@b>NSQs1zkFftLWHimYF(o17wLL&Q@?oZo6;ta zL=VdJphyo!)>VgyNPRtGn_Y=>ZsAV1U^m3jJ0s4fU+|x_-e~{loi}z$ zTldRb_lu4L@O-JqD-WTe1U?Lzq;JHU+ZHB8*Q1c^Hzayfq~ak6x3#^+&u@Jr_-1gy zv$$caxM6F=^>C;&Y3t%-4~Uz#s&Msd<)QMl zT6#)!pOQ9tC3;k*M@4${k2#oaLrh8C7foWv390QVx$P;5J}J{DMf&72y*_+Yq8nto zL8Kc%SI8K#RfnH=tuj=(yuNYXd#ylPze8TX<5hF0ICN&Yrs0hpZ|(?@DBkh;Gf;Cf z-6GO0+27Sm^u|ScBN!>#CDSeuYMicJq8k_K#t$Ha+hls1NN-Ea{eFo)Akzm#^|`6F zK9Uz*ha|dNrn^PD``*21apey#h(+~KdDgS2iW7b$zw{OBQhx1Xeyx~a`^5qD6OXat z@Q8ful&C$Uyr?~Of|MVS^8;f1SuV08WgC)SOkd4neoeST%CD32>%^=F48=V#sMZbe z{&EV3p?`1nF`dp(6(MtHtxIJ2B3Uk0G)QElOg4&SV}vYOA}bcj3W=N4{}4wyzrdO?3yce}n$tD>fh3 zWB-wRpy+5Z_MbJoo8k4lA{=WLV**Y((Yig$rSI8sb${j5^=d0#byt$u4LS8GhjnQ6!3i9~ z(Y1RH+DhUSd~?Wq69u5P$uyQ`qc=)~Qzo1u;RN<`-OqME(|fUZTK#38q9@870!47b z1b*C&!Wp0D)-G4(oe>VswAIsBq*HZaB2J~g*SJHHazeajZRxdrXrLMNB=(SZFTDsm z#+C0sr`{@gX61t)N3YJ`y8hPP>!CXzz8Rgq5uJHGdi`Ukk=qZ^ID~w02a%_qhaLh- zDH`HDg7+-zPB}`=s&I7=g1mY7^IhPflTY)-$>*Ma_Gz&+cI>%|84P(5lA0lIYJ;J2 z5xRTT;}ZFVOgMr7_v%>u{GHYw5A4KPpT{@ER&$#m zG=Rp}=kIv-p!-J-_ME!eb`AN*9m9UkG4AJB2fD4qjYBu``>HtvjQtUf*mPwI72D~% z(cavt51^L*{GGvmKgXTt(55_qw)T+FkyBpYp>1{?K>3G<(M^DAt_gxK6iC4*@1gs!%E6xtny8WxY#?lMIy=~I2`~ zC88wa+C1GQTIwYNmMSis>OXf|oc@s>ehF*MLScc06X4tc= zpI^Ul=2roc?2*VGnd|`qCQcC11T`OR-+IyVDTALXlS-r6_iKdVKH7AbcB8;qzB^C< zc^?mT6kDYXD`jwK$)jN0n>IKCEFtWH|fHl;+ zbn3k@z)vPT<8HvY{KMJ>lNwN=PHr0VgSy4Lm})51$?rb7bKK7a#@Jol4LKi6xf%*vwzymctg-)+Ts~ePR&HL!;GOgm`VhBH)prWVt399DQ&`6!9a*;MO-42U5JTmJF{z0 zEJrm}E3Hu^90?R3TFJdo5SRWbHnPNOrJQ<7PnNiG>U-;t*hx!!=&a|rv-9z0=J($G z#=m(y9RyNj;?E_gosd89qmhJq;q4hHY!R8rG)8U_S@@CMqOuK8kQty&wgWO*1hmTz zKv9+e9WuQ^0?r*Y6IyCm!!HKe2KlWH0G8>x0NLgw8IqwssH>%QmVtTF9zxb>M#wOk zr70m9m@f@$O@oDWAG8TjBd(xL!n-u+(MYo6Iefip*8D)hhJ-d`X$9veoPk|>SGYko zrUK3o$3@QX;DDX)5gZ6Z0O{Uqk);(y8;Yt!S|TwNOT_OD?_{ARKuyQRtFxRZc))J5 zJ8PO^(x@qNMNP#t(~cFY>A=@wG_JzJ$q=S@*JjR!{SOm-CG7WKxfq)La&G$EeE6IB z>B&ox2azim=jN`?g_E(=Js1_f5WS=Dctlg?!pn`~A`e?uQ(82p9#5{BF0Mr6#Rm}{ zjcdFcCPGfsBtVuJp3dw!!|ln=Rt1NB(D3%>SD%jQ4nuP4*K?vy4XHDKx-h>vRZP8D z{dKMEohVBax@fq%^Cusl)z5BweWigDW$$>!J6>{+8}8n`oC_7S*Dim_Cb`rSIrO!Lup+Ar$Y-o0*?7f*bR(g)1^31BgwSg z-Rm}MY%P4CjBXAHp|m}v-3^`z2o^=AC@V_|SqU(XCxN>FOfja!?`g}X5KXGcA^MAV zVT)u@3wWOJ1DxQS6e`#wW#~xQ6E=E;c zRg;!ld@0vMX3|1z$ue zuJPYLEV)jX*y;B$a0#sa9}LuYZ42#4U=en`%8?R&2%vpePRrSN)cG(p4q}I+0RLf6 zsgi55#3uJ|2Whh$dLIf~1SF5j0!k9d7>XT)6~sN2SzVy)83E+3CUc|+WA>+v&>r^` zZL$^XG;u*DAa0)o#LzrP?co?vmYX?lAJj{XB$G;94%B>X+8;z>DaB;T2-n)_a6jZx z5V5+xjKb&<$m%tKEJ0QA8eM&PEtk=mA$jt{IhSrn`ItueFx=hwncQW4#*o}kT#sG( znX=@oNWPNfYw6RY&!T>K_w&{~2nCpKuYPFAXgz_J0Gqp_-yZ(RP0?be(ZBJ24uw~Z z4>Ci(Jpdjd#TLuWMzWvrjf2Q@fQCRvkQvhk5@L!<9JPh}p{C9+KZ33FPCK>E8nvh^ zA47W(vWoEzy285ieb3awsm=7$beWA**hqnFFzN=r+8J%<0>q|;1&GHzYE6lTkyTH4q3-3pRjl^dwzb)|X?Wu{E&Yop zNs%@Bw!SmA_Hp3zf9kpKe2zW)P$wXXL%+5w>v1S5JG1+sUbk-c-=*Uk(7tAWEJb3?u!}g&tb>@UwR9-%f4e3-?1_aR#>pa zf(Gk(!+fuquP|C>!xc7MV#B+2$IC2GVS!TPXGKdu;sdY>>zcH#J4@LuDQsZ_SNoD! z1FS3Zo%Gpv2{{#0ruZZ@L2MEA5defDr3Ue2t*0t>(7`Hc!T_T^Rnmk`fu5<7CUgk& d6n@sBL!#a)X+pn^!U1SPhl3uilKo&U@h`?=JiY(` literal 0 HcmV?d00001 diff --git a/hibernate_r/byte_utils.py b/hibernate_r/byte_utils.py new file mode 100644 index 0000000..de657bc --- /dev/null +++ b/hibernate_r/byte_utils.py @@ -0,0 +1,57 @@ +import struct + + +def read_varint(byte, i): + result = 0 + bytes = 0 + while True: + byte_in = byte[i] + i += 1 + result |= (byte_in & 0x7F) << (bytes * 7) + if bytes > 32: + raise IOError("Packet is too long!") + if (byte_in & 0x80) != 0x80: + return result, i + + +def read_utf(byte, i): + (length, i) = read_varint(byte, i) + ip = byte[i:(i + length)].decode('utf-8') + i += length + return ip, i + + +def read_ushort(byte, i): + new_i = i + 2 + return struct.unpack(">H", byte[i:new_i])[0], new_i + + +def read_long(byte, i): + new_i = i + 8 + return struct.unpack(">q", byte[i:new_i]), new_i + + +def write_varint(byte, value): + while True: + part = value & 0x7F + value >>= 7 + if value != 0: + part |= 0x80 + byte.append(part) + if value == 0: + break + + +def write_utf(byte, value): + write_varint(byte, len(value)) + for b in value.encode(): + byte.append(b) + +def write_response(client_socket, response): + response_array = bytearray() + write_varint(response_array, 0) + write_utf(response_array, response) + length = bytearray() + write_varint(length, len(response_array)) + client_socket.sendall(length) + client_socket.sendall(response_array) diff --git a/mcdreforged.plugin.json b/mcdreforged.plugin.json new file mode 100644 index 0000000..0eed2a0 --- /dev/null +++ b/mcdreforged.plugin.json @@ -0,0 +1,18 @@ +{ + "id": "hibernate_r", + "version": "0.1.0", + "name": "HibernateR", + "description": "一个MCDReforged插件,可以根据服务器内玩家情况自动开启或关闭服务器", + "author": [ + "HIM049", + "sout_Nantang" + ], + "link": "https://github.com/HIM049/MCDR_HibernateR", + "dependencies": { + "online_player_api": "*", + "mcdreforged": ">=2.0.0-beta.3" + }, + "resources": [ + "LICENSE" + ] +} \ No newline at end of file