You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
314 lines
12 KiB
Python
314 lines
12 KiB
Python
# 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) |