super basic server impl
This commit is contained in:
parent
3cee338ca5
commit
f513801132
1 changed files with 71 additions and 21 deletions
|
@ -2,7 +2,8 @@ import asyncio
|
|||
import logging
|
||||
import uuid
|
||||
|
||||
from asyncio import Task, StreamReader, StreamWriter, Server
|
||||
from asyncio import Task, StreamReader, StreamWriter
|
||||
from asyncio.base_events import Server # just for typing
|
||||
from enum import Enum
|
||||
|
||||
from typing import Dict, List, Callable, Type, Optional, Tuple, AsyncIterator
|
||||
|
@ -13,7 +14,7 @@ from .mc.token import Token, AuthException
|
|||
from .mc.definitions import Dimension, Difficulty, Gamemode, ConnectionState
|
||||
from .mc.proto.handshaking.serverbound import PacketSetProtocol
|
||||
from .mc.proto.play.serverbound import PacketKeepAlive as PacketKeepAliveResponse
|
||||
from .mc.proto.play.clientbound import PacketKeepAlive, PacketSetCompression, PacketKickDisconnect
|
||||
from .mc.proto.play.clientbound import PacketKeepAlive, PacketSetCompression, PacketKickDisconnect, PacketPosition, PacketLogin
|
||||
from .mc.proto.login.serverbound import PacketLoginStart, PacketEncryptionBegin as PacketEncryptionResponse
|
||||
from .mc.proto.login.clientbound import (
|
||||
PacketCompress, PacketDisconnect, PacketEncryptionBegin, PacketLoginPluginRequest, PacketSuccess
|
||||
|
@ -22,7 +23,7 @@ from .util import encryption
|
|||
|
||||
LOGGER = logging.getLogger(__name__)
|
||||
|
||||
class Server:
|
||||
class MinecraftServer:
|
||||
host:str
|
||||
port:int
|
||||
options:dict
|
||||
|
@ -45,6 +46,7 @@ class Server:
|
|||
self.port = port
|
||||
|
||||
self.options = options or {
|
||||
"poll-timeout" : 1,
|
||||
"online-mode" : False,
|
||||
}
|
||||
|
||||
|
@ -63,11 +65,11 @@ class Server:
|
|||
loop.run_until_complete(self.start())
|
||||
|
||||
async def idle():
|
||||
while self._processing: # TODO don't busywait even if it doesn't matter much
|
||||
while True: # TODO don't busywait even if it doesn't matter much
|
||||
await asyncio.sleep(self.options["poll-timeout"])
|
||||
|
||||
try:
|
||||
loop.run_forever(idle())
|
||||
loop.run_until_complete(idle())
|
||||
except KeyboardInterrupt:
|
||||
self._logger.info("Received SIGINT, stopping...")
|
||||
try:
|
||||
|
@ -76,26 +78,19 @@ class Server:
|
|||
self._logger.info("Received SIGINT, stopping for real")
|
||||
loop.run_until_complete(self.stop(wait_tasks=False))
|
||||
|
||||
async def start(self, block=False):
|
||||
async def start(self):
|
||||
self._server = await asyncio.start_server(
|
||||
self._server_worker, self.host, self.port
|
||||
)
|
||||
|
||||
addrs = ', '.join(str(sock.getsockname()) for sock in server.sockets)
|
||||
print(f'Serving on {addrs}')
|
||||
|
||||
self._processing = True
|
||||
async with self._server:
|
||||
self._logger.info("Minecraft server started")
|
||||
if block:
|
||||
await self._server.serve_forever()
|
||||
else:
|
||||
await self._server.start_serving()
|
||||
self._logger.info("Minecraft server started")
|
||||
|
||||
async def stop(self, block=True, wait_tasks=True):
|
||||
self._processing = False
|
||||
if self.dispatcher.connected:
|
||||
await self.dispatcher.disconnect(block=block)
|
||||
# if self.dispatcher.connected:
|
||||
# await self.dispatcher.disconnect(block=block)
|
||||
self._server.close()
|
||||
if block:
|
||||
await self._server.wait_closed()
|
||||
|
@ -109,7 +104,16 @@ class Server:
|
|||
await dispatcher.write(PacketKickDisconnect(dispatcher.proto, reason="Connection terminated"))
|
||||
|
||||
async def _server_worker(self, reader:StreamReader, writer:StreamWriter):
|
||||
dispatcher = Dispatcher()
|
||||
if not self._processing:
|
||||
if not writer.is_closing() and writer.can_write_eof():
|
||||
try:
|
||||
writer.write_eof()
|
||||
except OSError as e:
|
||||
self._logger.error("Failed to write EOF to connecting client : %s", str(e))
|
||||
writer.close()
|
||||
return await writer.wait_closed()
|
||||
|
||||
dispatcher = Dispatcher(server=True)
|
||||
|
||||
self._logger.debug("Starting dispatcher for client")
|
||||
await dispatcher.connect(
|
||||
|
@ -131,23 +135,29 @@ class Server:
|
|||
await dispatcher.disconnect()
|
||||
|
||||
async def _handshake(self, dispatcher:Dispatcher) -> bool: # TODO make this fancier! poll for version and status first
|
||||
self._logger.info("Awaiting handshake")
|
||||
async for packet in dispatcher.packets():
|
||||
if isinstance(packet, PacketSetProtocol):
|
||||
self._logger.info("Received set protocol packet")
|
||||
dispatcher.proto = packet.protocolVersion
|
||||
if packet.nextState == ConnectionState.STATUS:
|
||||
if packet.nextState == 1:
|
||||
self._logger.debug("Changing state to STATUS")
|
||||
dispatcher.state = ConnectionState.STATUS
|
||||
return True
|
||||
elif packet.nextState == ConnectionState.LOGIN:
|
||||
elif packet.nextState == 2:
|
||||
self._logger.debug("Changing state to LOGIN")
|
||||
dispatcher.state = ConnectionState.LOGIN
|
||||
return True
|
||||
return False
|
||||
|
||||
async def _status(self, dispatcher:Dispatcher) -> bool:
|
||||
self._logger.info("Answering ping")
|
||||
async for packet in dispatcher.packets():
|
||||
pass # TODO handle status!
|
||||
return False
|
||||
|
||||
async def _login(self, dispatcher:Dispatcher) -> bool:
|
||||
self._logger.info("Logging in player")
|
||||
async for packet in dispatcher.packets():
|
||||
if isinstance(packet, PacketLoginStart):
|
||||
if self.options["online-mode"]:
|
||||
|
@ -164,7 +174,7 @@ class Server:
|
|||
await dispatcher.write(
|
||||
PacketSuccess(
|
||||
dispatcher.proto,
|
||||
uuid=packet.username,
|
||||
uuid=str(uuid.uuid4()),
|
||||
username=packet.username,
|
||||
)
|
||||
)
|
||||
|
@ -177,7 +187,47 @@ class Server:
|
|||
return False
|
||||
|
||||
async def _play(self, dispatcher:Dispatcher) -> bool:
|
||||
self._logger.info("Player connected")
|
||||
|
||||
await dispatcher.write(
|
||||
PacketLogin(
|
||||
dispatcher.proto,
|
||||
gameMode=3,
|
||||
isFlat=False,
|
||||
worldNames=b'',
|
||||
worldName='aiocraft',
|
||||
previousGameMode=3,
|
||||
entityId=1,
|
||||
isHardcore=False,
|
||||
difficulty=0,
|
||||
isDebug=True,
|
||||
enableRespawnScreen=False,
|
||||
maxPlayers=1,
|
||||
dimension=1,
|
||||
levelType='aiocraft',
|
||||
reducedDebugInfo=False,
|
||||
hashedSeed=1234,
|
||||
viewDistance=4
|
||||
)
|
||||
)
|
||||
|
||||
await dispatcher.write(
|
||||
PacketPosition(
|
||||
dispatcher.proto,
|
||||
dismountVehicle=True,
|
||||
x=0,
|
||||
y=120,
|
||||
flags=0,
|
||||
yaw=0.0,
|
||||
onGround=False,
|
||||
teleportId=1,
|
||||
pitch=0.0,
|
||||
z=0,
|
||||
)
|
||||
)
|
||||
|
||||
async for packet in dispatcher.packets():
|
||||
pass # TODO handle play
|
||||
|
||||
return False
|
||||
|
||||
|
|
Loading…
Reference in a new issue