Advertisement
Guest User

Test

a guest
May 30th, 2025
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.64 KB | None | 0 0
  1. """
  2. main server script for running agar.io server
  3.  
  4. can handle multiple/infinite connections on the same
  5. local network
  6. """
  7. import socket
  8. from _thread import *
  9. import _pickle as pickle
  10. import time
  11. import random
  12. import math
  13.  
  14. # setup sockets
  15. S = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  16. S.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  17.  
  18. # Set constants
  19. PORT = 5555
  20. START_RADIUS = 15
  21. BIG_RADIUS = 35
  22. BIGGER_RADIUS = 45
  23. ROUND_TIME = 120
  24. MASS_LOSS_TIME = 7
  25. episodes_count = 5000
  26. LOGGING = True
  27. W, H = 300, 300
  28.  
  29. HOST_NAME = socket.gethostname()
  30. SERVER_IP = socket.gethostbyname(HOST_NAME)
  31.  
  32. # try to connect to server
  33. try:
  34. S.bind((SERVER_IP, PORT))
  35. except socket.error as e:
  36. print(str(e))
  37. print("[SERVER] Server could not start")
  38. quit()
  39.  
  40. S.listen() # listen for connections
  41. print(f"[SERVER] Server Started with local ip {SERVER_IP}")
  42.  
  43. # dynamic variables
  44. players = {}
  45. balls = []
  46. traps = []
  47. connections = 0
  48.  
  49. _id = 0
  50. colors = [(255,0,0), (255, 128, 0), (255,255,0), (128,255,0),(0,255,0),(0,255,128),(0,255,255),(0, 128, 255), (0,0,255), (0,0,255), (128,0,255),(255,0,255), (255,0,128),(128,128,128)]
  51. start = False
  52. game_time = 0
  53. nxt = 1
  54.  
  55.  
  56.  
  57. def reset_game():
  58. global players, balls, traps, start, start_time, game_time, nxt, episodes_count, ROUND_TIME
  59. print(f"[GAME] Resetting game. Starting episode {episodes_count + 1}")
  60.  
  61. # Reset all players
  62. for pid in players:
  63. print(f"PLAYER BEFORE RESET {players[pid]['x']} {players[pid]['y']}")
  64. players[pid]["score"] = 0
  65. players[pid]["reward"] = 0
  66. players[pid]["x"], players[pid]["y"] = get_start_location(players)
  67. players[pid]["alive"] = True
  68. print(f"PLAYER {pid} reset new coordinates {players[pid]['x']} {players[pid]['y']}")
  69.  
  70. # Clear and recreate balls and traps
  71. balls.clear()
  72. traps.clear()
  73. create_balls(balls, 200)
  74. create_traps(traps, 15)
  75.  
  76. # Reset time and flags
  77. start = True
  78. start_time = time.time()
  79. game_time = 0
  80. nxt = 1
  81. episodes_count -= 1
  82. if episodes_count % 2 == 0:
  83. ROUND_TIME = 120
  84. elif episodes_count % 3 == 0:
  85. ROUND_TIME = 60
  86. elif episodes_count % 5 == 0:
  87. ROUND_TIME = 20
  88.  
  89.  
  90. # FUNCTIONS
  91. def check_collision_balls(players, balls):
  92. """
  93. checks if any of the player have collided with any of the balls or traps
  94.  
  95. :param players: a dictonary of players
  96. :param balls: a list of balls
  97. :return: None
  98. """
  99. for player in players:
  100. p = players[player]
  101. x = p["x"]
  102. y = p["y"]
  103. for ball in balls:
  104.  
  105. # ball coordinates
  106. bx = ball[0]
  107. by = ball[1]
  108.  
  109. dis_ball = math.sqrt((x - bx)**2 + (y-by)**2)
  110.  
  111. if dis_ball <= START_RADIUS:
  112. p["score"] = p["score"] + 1
  113. p["reward"] += 1
  114. balls.remove(ball)
  115.  
  116.  
  117. def check_collision_traps(players, traps):
  118. """
  119. checks if any of the player have collided with any of the balls or traps
  120.  
  121. :param players: a dictonary of players
  122. :param traps: a list of traps
  123. :return: None
  124. """
  125. for player in players:
  126. p = players[player]
  127. x = p["x"]
  128. y = p["y"]
  129. for trap in traps:
  130.  
  131. # trap coordinates
  132. tx = trap[0]
  133. ty = trap[1]
  134.  
  135. dis_trap = math.sqrt((x - tx)**2 + (y-ty)**2)
  136.  
  137. if dis_trap <= BIGGER_RADIUS:
  138. players[player]["reward"] += -0.01
  139.  
  140. if dis_trap <= BIG_RADIUS:
  141. players[player]["reward"] += -0.1
  142.  
  143. if dis_trap <= START_RADIUS:
  144. players[player]["score"] = 0
  145. players[player]["reward"] = -150
  146. players[player]["x"], players[player]["y"] = get_start_location(players)
  147. players[player]["alive"] = False
  148. continue
  149.  
  150. def walls_collision(players):
  151. """
  152. checks if any of the player have encountered walls
  153.  
  154. :param players: a dictonary of players
  155. :return: None
  156. """
  157. for player in players:
  158. is_at_left_wall = True if players[player]['x'] == 0 else False
  159. is_at_right_wall = True if players[player]['x'] == W else False
  160. is_at_top_wall = True if players[player]['y'] == 0 else False
  161. is_at_bottom_wall = True if players[player]['y'] == H else False
  162. if is_at_left_wall or is_at_right_wall or is_at_top_wall or is_at_bottom_wall:
  163. players[player]["reward"] += -0.001
  164.  
  165.  
  166. def player_collision(players):
  167. """
  168. checks for player collision and handles that collision
  169.  
  170. :param players: dict
  171. :return: None
  172. """
  173. sort_players = sorted(players, key=lambda x: players[x]["score"])
  174. for x, player1 in enumerate(sort_players):
  175. for player2 in sort_players[x+1:]:
  176. p1x = players[player1]["x"]
  177. p1y = players[player1]["y"]
  178.  
  179. p2x = players[player2]["x"]
  180. p2y = players[player2]["y"]
  181.  
  182. dis = math.sqrt((p1x - p2x)**2 + (p1y-p2y)**2)
  183.  
  184. if dis < START_RADIUS:
  185. if players[player2]["score"] > players[player1]["score"]:
  186. players[player2]["score"] = players[player2]["score"] + players[player1]["score"]
  187. players[player2]["reward"] += 20
  188. players[player1]["score"] = 0
  189. players[player1]["reward"] = -2000
  190. players[player1]["alive"] = False
  191. players[player1]["x"], players[player1]["y"] = get_start_location(players)
  192. print(f"[GAME] " + players[player2]["name"] + " ATE " + players[player1]["name"])
  193. elif players[player1]["score"] > players[player2]["score"]:
  194. players[player2]["score"] = players[player1]["score"] + players[player2]["score"]
  195. players[player1]["reward"] += 20
  196. players[player2]["score"] = 0
  197. players[player2]["reward"] = -2000
  198. players[player2]["alive"] = False
  199. players[player2]["x"], players[player2]["y"] = get_start_location(players)
  200. print(f"[GAME] " + players[player2]["name"] + " ATE " + players[player1]["name"])
  201.  
  202.  
  203. def create_balls(balls, n):
  204. """
  205. creates orbs/balls on the screen
  206.  
  207. :param balls: a list to add balls/orbs to
  208. :param n: the amount of balls to make
  209. :return: None
  210. """
  211. for i in range(n):
  212. while True:
  213. stop = True
  214. x = random.randrange(0,W-5)
  215. y = random.randrange(0,H-5)
  216. for player in players:
  217. p = players[player]
  218. dis = math.sqrt((x - p["x"])**2 + (y-p["y"])**2)
  219. if dis <= START_RADIUS:
  220. stop = False
  221. if stop:
  222. break
  223.  
  224. balls.append((x,y, random.choice(colors)))
  225.  
  226.  
  227. def create_traps(traps, n):
  228. """
  229. creates traps on the screen
  230.  
  231. :param traps: a list to add traps to
  232. :param n: the amount of traps to make
  233. :return: None
  234. """
  235. for i in range(n):
  236. while True:
  237. stop = True
  238.  
  239. x = random.randrange(0,W)
  240. y = random.randrange(0,H)
  241.  
  242. for player in players:
  243. p = players[player]
  244. dis = math.sqrt((x - p["x"])**2 + (y-p["y"])**2)
  245. if dis <= START_RADIUS :
  246. stop = False
  247. if stop:
  248. break
  249.  
  250. traps.append((x,y, (0,0,0)))
  251.  
  252.  
  253. def get_start_location(players):
  254. """
  255. picks a start location for a player based on other player
  256. locations. It wiill ensure it does not spawn inside another player
  257.  
  258. :param players: dict
  259. :return: tuple (x,y)
  260. """
  261. while True:
  262. stop = True
  263. x = random.randrange(0, W)
  264. y = random.randrange(0, H)
  265. for player in players:
  266. p = players[player]
  267. dis = math.sqrt((x - p["x"])**2 + (y-p["y"])**2)
  268. if dis <= START_RADIUS + p["score"]:
  269. stop = False
  270. break
  271. if stop:
  272. break
  273. return (x,y)
  274.  
  275.  
  276. def threaded_client(conn, _id):
  277. """
  278. runs in a new thread for each player connected to the server
  279.  
  280. :param con: ip address of connection
  281. :param _id: int
  282. :return: None
  283. """
  284. global connections, players, balls, traps, game_time, nxt, start, episodes_count
  285.  
  286. current_id = _id
  287.  
  288. # recieve a name from the client
  289. data = conn.recv(16)
  290. name = data.decode("utf-8")
  291. print("[LOG]", name, "connected to the server.")
  292.  
  293. # Setup properties for each new player
  294. color = colors[current_id]
  295. x, y = get_start_location(players)
  296. players[current_id] = {"x":x, "y":y,"color":color,"score":0,"name":name, "alive": True, "episode": episodes_count, "reward": 0}
  297.  
  298. # pickle data and send initial info to clients
  299. conn.send(str.encode(str(current_id)))
  300.  
  301. # server will recieve basic commands from client
  302. # it will send back all of the other clients info
  303. '''
  304. commands start with:
  305. move
  306. jump
  307. get
  308. id - returns id of client
  309. '''
  310. while True:
  311.  
  312. if start:
  313. game_time = round(time.time()-start_time)
  314. # checks whether all players are dead
  315. all_dead = all(not players[pid]["alive"] for pid in players)
  316. if all_dead:
  317. reset_game()
  318. try:
  319. # Recieve data from client
  320. data = conn.recv(32)
  321.  
  322. if not data:
  323. break
  324.  
  325. data = data.decode("utf-8")
  326. #print("[DATA] Recieved", data, "from client id:", current_id)
  327.  
  328. # look for specific commands from recieved data
  329. if data.split(" ")[0] == "move":
  330. split_data = data.split(" ")
  331. x = int(split_data[1])
  332. y = int(split_data[2])
  333. players[current_id]["x"] = x
  334. players[current_id]["y"] = y
  335. players[current_id]["reward"] = 0
  336.  
  337. # only check for collison if the game has started
  338. if start:
  339. check_collision_balls(players, balls)
  340. check_collision_traps(players, traps)
  341. player_collision(players)
  342. walls_collision(players)
  343. if game_time >= ROUND_TIME:
  344. for player in players:
  345. players[player]["alive"] = False
  346.  
  347. # if the amount of balls is less than 150 create more
  348. if len(balls) < 150:
  349. create_balls(balls, random.randrange(100,150))
  350. print("[GAME] Generating more orbs")
  351.  
  352. send_data = pickle.dumps((balls,traps,players, game_time, episodes_count))
  353.  
  354. elif data.split(" ")[0] == "id":
  355. send_data = str.encode(str(current_id)) # if user requests id then send it
  356.  
  357. elif data.split(" ")[0] == "jump":
  358. send_data = pickle.dumps((balls,traps,players, game_time, episodes_count))
  359. else:
  360. # any other command just send back list of players
  361. send_data = pickle.dumps((balls,traps,players, game_time, episodes_count))
  362.  
  363. # send data back to clients
  364. conn.send(send_data)
  365.  
  366. except Exception as e:
  367. print(e)
  368. break # if an exception has been reached disconnect client
  369.  
  370. time.sleep(0.001)
  371.  
  372. # When user disconnects
  373. print("[DISCONNECT] Name:", name, ", Client Id:", current_id, "disconnected")
  374.  
  375. connections -= 1
  376. del players[current_id] # remove client information from players list
  377. conn.close() # close connection
  378.  
  379.  
  380. # MAINLOOP
  381.  
  382. # setup level with balls
  383. create_balls(balls, random.randrange(200,250))
  384. create_traps(traps, 15)
  385.  
  386. print("[GAME] Setting up level")
  387. print("[SERVER] Waiting for connections")
  388.  
  389. # Keep looping to accept new connections
  390. while LOGGING:
  391. host, addr = S.accept()
  392. print("[CONNECTION] Connected to:", addr)
  393.  
  394. # start game when a client on the server computer connects
  395. if addr[0] == SERVER_IP and not(start):
  396. start = True
  397. start_time = time.time()
  398. print("[STARTED] Game Started")
  399.  
  400. # increment connections start new thread then increment ids
  401. connections += 1
  402. start_new_thread(threaded_client,(host,_id))
  403. _id += 1
  404.  
  405. # when program ends
  406. print("[SERVER] Server offline")
  407.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement