-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathServerConnection.py
176 lines (127 loc) · 5.56 KB
/
ServerConnection.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import socket
import struct
import json
from Constants import Action
jsonDict = dict[str, any] # alias
class ServerConnection:
serverAddress = "wgforge-srv.wargaming.net"
serverPort = 443
def __init__(self):
'''
Opens a socket to the server.
'''
self.__Socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.__Socket.connect((self.serverAddress, self.serverPort))
def __sendRequest(self, actionCode : int, data : jsonDict = None) -> jsonDict:
'''
Sends a request to the server and returns the response.
:param actionCode: The code of the action.
:param data: The request data dictionary.
:return: The response of the request.
'''
# Convert the data to a JSON string and get its length
if data:
dataJson = json.dumps(data)
dataLen = len(dataJson)
else: # No data
dataJson = ""
dataLen = 0
# Construct the message
msg = struct.pack("<II", actionCode, dataLen) + dataJson.encode("utf-8")
# Send the message to the server
self.__Socket.sendall(msg)
# Receive the response from the server
response = self.__Socket.recv(8)
# Unpack the response
resultCode, dataLen = struct.unpack("<II", response)
# Receive the response dictionary (if there's one)
data = ""
while dataLen > 0:
newData = self.__Socket.recv(dataLen) # receive
newData = newData.decode("utf-8") # decode
dataLen -= len(newData)
data += newData
if data:
data = json.loads(data) # turn into dictionary
# Return the response as a json dictionary
return {"resultCode": resultCode, "data": data}
def login(self, data : jsonDict) -> jsonDict:
'''
Logs in the player to the server.\n
:param data: The login request data dictionary.
The server expects to receive the following required values:
name - player's name.
The following values are not required:
password - player's password used to verify the connection. If the player tries to connect with another password, the login will be rejected. Default: "".
game - game's name (use it to connect to an existing game). Default: null.
num_turns - number of game turns to be played. Default: null. (If num_turns is null, the default game length will be used.)
num_players - number of players in the game. Default: 1.
is_observer - defines if a player joins a server just to watch. Default: false.
:return: The response of the request.
'''
return self.__sendRequest(Action.LOGIN.value, data)
def logout(self) -> jsonDict:
'''
Logs out the player and removes the player's record from the server storage.
:return: The response of the request.
'''
return self.__sendRequest(Action.LOGOUT.value)
def map(self) -> jsonDict:
'''
Gets the map, which represents static information about the game.
:return: The response of the request.
'''
return self.__sendRequest(Action.MAP.value)
def game_state(self) -> jsonDict:
'''
Gets the game state, which represents dynamic information about the game.
:return: The response of the request.
'''
return self.__sendRequest(Action.GAME_STATE.value)
def game_actions(self) -> jsonDict:
'''
Gets a list of game actions that happened in the previous turn, representing changes between turns.
:return: The response of the request.
'''
return self.__sendRequest(Action.GAME_ACTIONS.value)
def turn(self) -> jsonDict:
'''
Sends a TURN action, which forces the next turn of the game. This allows players to play faster and not wait for the game's time slice.
The game's time slice is 10 seconds for test battles and 1 second for final battles. All players and observers must send the TURN action before the next turn can happen.
:return: The response of the request.
'''
return self.__sendRequest(Action.TURN.value)
def chat(self, data : jsonDict) -> jsonDict:
'''
Does nothing. Just for testing and fun.
:param data: The chat request data dictionary.
The server expects to receive the following required values:
message - string message
:return: The response of the request.
'''
return self.__sendRequest(Action.CHAT.value, data)
def move(self, data : jsonDict) -> jsonDict:
'''
Changes vehicle position.
:param data: The move request data dictionary.
The server expects to receive the following required values:
vehicle_id - id of vehicle.
target - coordinates of hex.
:return: The response of the request.
'''
return self.__sendRequest(Action.MOVE.value, data)
def shoot(self, data : jsonDict) -> jsonDict:
'''
Shoots to target position.
:param data: The shoot request data dictionary.
The server expects to receive following required values:
vehicle_id - id of vehicle.
target - coordinates of hex.
:return: The response of the request.
'''
return self.__sendRequest(Action.SHOOT.value, data)
def close(self) -> None:
'''
Closes the socket to the server.
'''
self.__Socket.close()