# Imports from engineio.payload import Payload from AesEverywhere import aes256 import flask_socketio import threading import requests import random import pygame import flask import time import math import os from dotenv import load_dotenv load_dotenv() # Config Payload.max_decode_packets = 500 webserver_address = "http://localhost:3000" cryptography_password = os.environ.get("CRYPTOGRAPHY_PASSWORD") clock = pygame.time.Clock() tile_map = [[8, 80, 80, 160, 160], [1, 160, 80, 240, 160], [1, 240, 80, 320, 160], [1, 320, 80, 400, 160], [1, 400, 80, 480, 160], [1, 480, 80, 560, 160], [1, 560, 80, 640, 160], [1, 640, 80, 720, 160], [1, 720, 80, 800, 160], [1, 800, 80, 880, 160], [1, 880, 80, 960, 160], [1, 960, 80, 1040, 160], [1, 1040, 80, 1120, 160], [1, 1120, 80, 1200, 160], [1, 1200, 80, 1280, 160], [1, 1280, 80, 1360, 160], [1, 1360, 80, 1440, 160], [1, 1440, 80, 1520, 160], [1, 1520, 80, 1600, 160], [1, 1600, 80, 1680, 160], [1, 1680, 80, 1760, 160], [1, 1760, 80, 1840, 160], [1, 1840, 80, 1920, 160], [1, 1920, 80, 2000, 160], [1, 2000, 80, 2080, 160], [2, 2080, 80, 2160, 160], [7, 80, 160, 160, 240], [3, 2080, 160, 2160, 240], [7, 80, 240, 160, 320], [3, 2080, 240, 2160, 320], [7, 80, 320, 160, 400], [3, 2080, 320, 2160, 400], [7, 80, 400, 160, 480], [3, 2080, 400, 2160, 480], [7, 80, 480, 160, 560], [5, 160, 480, 240, 560], [5, 240, 480, 320, 560], [5, 320, 480, 400, 560], [5, 400, 480, 480, 560], [5, 480, 480, 560, 560], [3, 2080, 480, 2160, 560], [7, 80, 560, 160, 640], [5, 880, 560, 960, 640], [5, 1520, 560, 1600, 640], [5, 1600, 560, 1680, 640], [5, 1680, 560, 1760, 640], [5, 1760, 560, 1840, 640], [3, 2080, 560, 2160, 640], [7, 80, 640, 160, 720], [3, 2080, 640, 2160, 720], [7, 80, 720, 160, 800], [5, 800, 720, 880, 800], [5, 1200, 720, 1280, 800], [3, 2080, 720, 2160, 800], [7, 80, 800, 160, 880], [3, 2080, 800, 2160, 880], [7, 80, 880, 160, 960], [3, 560, 880, 640, 960], [5, 1040, 880, 1120, 960], [5, 1360, 880, 1440, 960], [3, 2080, 880, 2160, 960], [7, 80, 960, 160, 1040], [3, 560, 960, 640, 1040], [5, 1280, 960, 1360, 1040], [5, 1440, 960, 1520, 1040], [5, 1520, 960, 1600, 1040], [5, 1600, 960, 1680, 1040], [5, 1680, 960, 1760, 1040], [3, 2080, 960, 2160, 1040], [7, 80, 1040, 160, 1120], [5, 480, 1040, 560, 1120], [5, 1760, 1040, 1840, 1120], [3, 2080, 1040, 2160, 1120], [7, 80, 1120, 160, 1200], [5, 1120, 1120, 1200, 1200], [3, 2080, 1120, 2160, 1200], [6, 80, 1200, 160, 1280], [5, 160, 1200, 240, 1280], [5, 240, 1200, 320, 1280], [5, 320, 1200, 400, 1280], [5, 400, 1200, 480, 1280], [5, 480, 1200, 560, 1280], [5, 560, 1200, 640, 1280], [5, 640, 1200, 720, 1280], [5, 720, 1200, 800, 1280], [5, 800, 1200, 880, 1280], [5, 880, 1200, 960, 1280], [5, 960, 1200, 1040, 1280], [5, 1040, 1200, 1120, 1280], [5, 1120, 1200, 1200, 1280], [5, 1200, 1200, 1280, 1280], [5, 1280, 1200, 1360, 1280], [5, 1360, 1200, 1440, 1280], [5, 1440, 1200, 1520, 1280], [5, 1520, 1200, 1600, 1280], [5, 1600, 1200, 1680, 1280], [5, 1680, 1200, 1760, 1280], [5, 1760, 1200, 1840, 1280], [5, 1840, 1200, 1920, 1280], [5, 1920, 1200, 2000, 1280], [5, 2000, 1200, 2080, 1280], [4, 2080, 1200, 2160, 1280]] users = [] user_positions = [0, 0, 0, 0, 0, 0] tiles = [] bullets = [] health = [] directions = [] # Cryptography class Cryptography (): # Encrypt @staticmethod def encrypt ( data, password ): return aes256.encrypt(data, password) # Decrypt @staticmethod def decrypt ( data, password ): return aes256.decrypt(data, password) # Register Server requests.post(webserver_address + "/api/registerServer", data = Cryptography.encrypt(f"{requests.get('https://api.ipify.org').text},6", cryptography_password)) # Get Bullet Vector def getBulletVector ( playerX, playerY, clickX, clickY ): return [ clickX - playerX, clickY - playerY ] # Get Bullet Normalisation Value def getBulletNormalisationValue ( distanceX, distanceY ): return 1 / math.sqrt((distanceX ** 2) + (distanceY ** 2)) # Get Normalised Bullet Vector def getNormalisedBulletVector ( bulletVector, bulletNormalisationValue ): return [ bulletVector[0] * bulletNormalisationValue, bulletVector[1] * bulletNormalisationValue ] # Creates Tiles for tile in tile_map: tiles.append(pygame.Rect(tile[1], tile[2],80, 80)) # User class User (): # Constructor def __init__ ( self, socketId, user, gameRank, elo, kills, deaths, player ): self.socketId = socketId self.user = user self.gameRank = gameRank self.elo = elo self.kills = kills self.deaths = deaths self.new_kills = 0; self.new_deaths = 0; self.angle = 0; self.inputs = [] self.player = player # Player class Player(object): # Constructor def __init__ ( self ): self.reset(random.randint(160, 1760), 160) self.game_over = False self.image_index = 0 # Update def update( self, inputs, tiles, dt ): # Move dx = 0 dy = 0 # Jump self.landed = False if self.jl == True: self.jl = False if inputs[0] and self.jumped == False and self.in_air == False: self.vel_y = -22 self.jumped = True self.jl = True self.touchfloor = False elif inputs[0] == False: self.jumped = False # Left if inputs[1]: dx -= 7 * dt self.direction = "left" # Right if inputs[3]: dx += 7 *dt self.direction = "right" # Collisions self.in_air = True # Direction if dx < 0: self.dir = -1 elif dx > 0: self.dir = 1 # Gravity self.vel_y += 1 * dt if self.vel_y > 10: self.vel_y = 10 *dt dy += self.vel_y for tile in tiles: # Vertical Collisions if tile.colliderect(self.rect.x, self.rect.y + dy, self.width, self.height): if self.vel_y >= 0: dy = tile.top - self.rect.bottom self.in_air = False if self.touchfloor == False: self.touchfloor = True self.landed = True elif self.vel_y < 0: dy = tile.bottom - self.rect.top self.vel_y = 0 self.rect.y += dy for tile in tiles: # X and Y if tile.colliderect(self.rect.x + dx, self.rect.y + 1, self.width, self.height - 2): print("true") if dx >= 0: dx = tile.left - self.rect.right elif dx < 0: dx = tile.right - self.rect.left self.rect.x += dx # Update Cords self.ht = dy # Return Cords return self.rect.x, self.rect.y # Reset def reset(self, x,y): self.width = 80 self.height = 80 self.rect = pygame.Rect(x,y,80,80) self.direction = 0 self.vel_y = 0 self.jumped = False self.in_air = True self.health = 8 self.dir = 1 self.touchfloor = False self.jl = False self.landed = False self.ht = 0 # App app = flask.Flask(__name__) socketio = flask_socketio.SocketIO(app, cors_allowed_origins = webserver_address) # Socketio Authentication @socketio.on("authentication") def authentication(code): code = str(Cryptography.decrypt(code.split("ShootyArenaGame=")[1], cryptography_password))[2:-1] code = code.split(",") for user in users: if user.user == code[0]: socketio.emit("disc", to = flask.request.sid) return users.append(User(flask.request.sid, code[0], code[1], int(code[2]), int(code[3]), int(code[4]), Player())) socketio.emit("map", tile_map) socketio.emit("player", code[0], to = flask.request.sid) # Move @socketio.on("move") def move(movement): for user in users: if flask.request.sid == user.socketId: user.inputs = movement # MMove @socketio.on("mmove") def mmove(angle): for user in users: if flask.request.sid == user.socketId: try: user.angle = int(angle["angle"]) except: user.angle = 0 # Click @socketio.on("click") def cli(inputs): for user in users: if flask.request.sid == user.socketId: vec = [inputs["dx"], inputs["dy"]] nvec = getBulletNormalisationValue(vec[0], vec[1]) fvec = getNormalisedBulletVector(vec, nvec) inputs["px"] += fvec[0] * 72 inputs["py"] += fvec[1] * 72 hit = False for tile in tile_map: if (inputs["px"] + 5 > tile[1] and inputs["px"] + 5 < tile[3]) and (inputs["py"] + 5 > tile[2] and inputs["py"] + 5 < tile[4]): hit = True if hit == False: bullets.append([user.user, inputs["px"], inputs["py"], fvec[0], fvec[1]]) # Game Loop last_time = time.time() def game (last_time): while True: dt = time.time() - last_time dt *= 60 last_time = time.time() health = [] # Bullets for bulletnum, bullet in enumerate(bullets): bullet[1] += bullet[3] * 12 * dt bullet[2] += bullet[4] * 12 * dt for tile in tile_map: if (bullet[1] + 5 > tile[1] and bullet[1] + 5 < tile[3]) and (bullet[2] + 5 > tile[2] and bullet[2] + 5 < tile[4]): del bullets[bulletnum] # Users for user in users: if (bullet[1] + 5 > user.player.rect.x and bullet[1] +5 < user.player.rect.x + 80) and (bullet[2] +5 > user.player.rect.y and bullet[2] +5 < user.player.rect.y + 80): if bullet[0] != user.user: del bullets[bulletnum] user.player.health -= 1 if user.player.health == 0: user.new_deaths += 1 socketio.emit("die", to = user.socketId) user.player.reset(random.randint(160, 1760), 160) for user2 in users: if bullet[0] == user2.user: user2.new_kills += 1 directions = [] angles = [] # Users for usernum, user in enumerate(users): if len(user.inputs) != 0: user_positions[usernum] = [user.user, user.player.update(user.inputs, tiles, dt)] if user.player.jl == True: socketio.emit("ju", to = user.socketId) if user.player.landed == True: socketio.emit("la", to = user.socketId) directions.append([user.user, user.player.dir]) health.append([user.user, user.player.health]) angles.append([user.user, user.angle]) socketio.emit("users", user_positions) socketio.emit("directions", directions) socketio.emit("health", health) socketio.emit("bullets", bullets) socketio.emit("ang", angles) clock.tick(60) # Run Game Loop thread = threading.Thread(target=game, args = (last_time,)) thread.start() # Factorial def factorial ( number ): if number == 0: return 1 else: return number * factorial(number - 1) # Calculate Elo Change def calculateEloChange ( kills, deaths ): sc = kills - deaths if sc >= 2: return factorial(sc) // factorial(sc - 2) else: return ( kills - deaths ) * 10 # Calculate Rank def calculateRank ( elo ): if elo < 0: return "Unranked" elif elo < 1000: return "Shitty Shooty" elif elo < 2000: return "Cutey Shooty" elif elo < 3000: return "Beauty Shooty" else: return "Snooty Shooty" # Dissconnect @socketio.on("disconnect") def dissconnect (): for usernum, user in enumerate(users): if flask.request.sid == user.socketId: data = aes256.encrypt(f"{user.user},{user.elo+calculateEloChange(user.new_kills, user.new_deaths)},{calculateRank(user.elo + calculateEloChange(user.new_kills, user.new_deaths))},{user.kills + user.new_kills},{user.deaths + user.new_deaths}" , cryptography_password) requests.post(f"{webserver_address}/api/updateStats", data = data) del users[usernum] user_positions[usernum] = 0 # Run Socketio if __name__ == "__main__": socketio.run(app, debug = False)