initial commit
@ -0,0 +1,5 @@
|
|||||||
|
.DS_STORE
|
||||||
|
.env
|
||||||
|
venv/
|
||||||
|
.next/
|
||||||
|
node_modules/
|
@ -0,0 +1,314 @@
|
|||||||
|
# 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)
|
@ -0,0 +1,32 @@
|
|||||||
|
# Tiles
|
||||||
|
tiles = [
|
||||||
|
[ 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2 ],
|
||||||
|
[ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 ],
|
||||||
|
[ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 ],
|
||||||
|
[ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 ],
|
||||||
|
[ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 ],
|
||||||
|
[ 7, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 ],
|
||||||
|
[ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 5, 5, 5, 5, 0, 0, 0, 3 ],
|
||||||
|
[ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 ],
|
||||||
|
[ 7, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 ],
|
||||||
|
[ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 ],
|
||||||
|
[ 7, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 3 ],
|
||||||
|
[ 7, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 5, 5, 5, 0, 0, 0, 0, 3 ],
|
||||||
|
[ 7, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 3 ],
|
||||||
|
[ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 ],
|
||||||
|
[ 6 ,5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4 ]
|
||||||
|
]
|
||||||
|
|
||||||
|
# Genrate Tile Map
|
||||||
|
tile_map = []
|
||||||
|
y_count = 0
|
||||||
|
for y in tiles:
|
||||||
|
y_count += 1
|
||||||
|
x_count = 0
|
||||||
|
for x in tiles[y_count - 1]:
|
||||||
|
x_count += 1
|
||||||
|
if tiles[y_count - 1][x_count - 1]:
|
||||||
|
tile_map.append([x, x_count * 80, y_count * 80, ( x_count * 80 ) + 80, ( y_count * 80 ) + 80 ])
|
||||||
|
|
||||||
|
# Display Tile Map
|
||||||
|
print(tile_map)
|
@ -0,0 +1,24 @@
|
|||||||
|
aes-everywhere==1.2.10
|
||||||
|
bidict==0.22.1
|
||||||
|
certifi==2022.12.7
|
||||||
|
charset-normalizer==3.1.0
|
||||||
|
click==8.1.3
|
||||||
|
Flask==2.2.3
|
||||||
|
Flask-SocketIO==5.3.3
|
||||||
|
h11==0.14.0
|
||||||
|
idna==3.4
|
||||||
|
importlib-metadata==6.6.0
|
||||||
|
itsdangerous==2.1.2
|
||||||
|
Jinja2==3.1.2
|
||||||
|
MarkupSafe==2.1.2
|
||||||
|
pycryptodomex==3.17
|
||||||
|
pygame==2.3.0
|
||||||
|
python-dotenv==1.0.0
|
||||||
|
python-engineio==4.4.1
|
||||||
|
python-socketio==5.8.0
|
||||||
|
requests==2.28.2
|
||||||
|
simple-websocket==0.10.0
|
||||||
|
urllib3==1.26.15
|
||||||
|
Werkzeug==2.2.3
|
||||||
|
wsproto==1.2.0
|
||||||
|
zipp==3.15.0
|
@ -0,0 +1,15 @@
|
|||||||
|
# Imports
|
||||||
|
import random
|
||||||
|
|
||||||
|
# Key
|
||||||
|
key = ""
|
||||||
|
|
||||||
|
# Characters
|
||||||
|
characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||||
|
|
||||||
|
# Generate Key
|
||||||
|
for i in range(32):
|
||||||
|
key += characters[ random.randint(0, 61) ]
|
||||||
|
|
||||||
|
# Display Key
|
||||||
|
print(key)
|
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import requests
|
||||||
|
import base64
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
|
||||||
|
MODE = AES.MODE_CFB
|
||||||
|
BLOCK_SIZE = 16
|
||||||
|
SEGMENT_SIZE = 128
|
||||||
|
|
||||||
|
def _pad_string(value):
|
||||||
|
length = len(value)
|
||||||
|
pad_size = BLOCK_SIZE - (length % BLOCK_SIZE)
|
||||||
|
return value.ljust(length + pad_size, '\x00')
|
||||||
|
|
||||||
|
def encrypt(key, iv, plaintext):
|
||||||
|
aes = AES.new(key, MODE, iv, segment_size=SEGMENT_SIZE)
|
||||||
|
plaintext = _pad_string(plaintext)
|
||||||
|
encrypted_text = aes.encrypt(plaintext)
|
||||||
|
return encrypted_text
|
||||||
|
|
||||||
|
|
||||||
|
key = 'TfvY7I358yospfWKcoviZizOShpm5hyH'
|
||||||
|
iv = 'mb13KcoviZizvYhp'
|
||||||
|
original_message = 'hi'
|
||||||
|
|
||||||
|
encryptedpayload = base64.b64encode(encrypt(key, iv, original_message))
|
||||||
|
|
||||||
|
request = requests.post("http://localhost:8080/hello", encryptedpayload)
|
||||||
|
|
||||||
|
|
||||||
|
print(request.content)
|
@ -0,0 +1,51 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import cookie from "./cookie/cookie.js";
|
||||||
|
import jsonwebtoken from "./jsonwebtoken/jsonwebtoken.js";
|
||||||
|
|
||||||
|
// Key
|
||||||
|
const JsonwebtokenKey = process.env.JSON_WEB_TOKEN_KEY;
|
||||||
|
|
||||||
|
// Set User
|
||||||
|
async function setUser ( req, res, data ) {
|
||||||
|
cookie.set(req, res, "ShootyArenaUser", jsonwebtoken.set(data, JsonwebtokenKey), true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get User
|
||||||
|
async function getUser ( req, res ) {
|
||||||
|
return new Promise (async (resolve) => {
|
||||||
|
try {
|
||||||
|
const userCookie = cookie.get(req, res, "ShootyArenaUser");
|
||||||
|
if (userCookie === undefined) {
|
||||||
|
setUser(req, res, "");
|
||||||
|
resolve("");
|
||||||
|
} else {
|
||||||
|
const user = await jsonwebtoken.get(userCookie, JsonwebtokenKey);
|
||||||
|
if (user === false || user.data === "") {
|
||||||
|
setUser(req, res, "");
|
||||||
|
resolve("");
|
||||||
|
} else {
|
||||||
|
setUser(req, res, user.data);
|
||||||
|
resolve(user.data);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
resolve("")
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set Game
|
||||||
|
async function setGame ( req, res, data ) {
|
||||||
|
cookie.set(req, res, "ShootyArenaGame", data, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
module.exports = {
|
||||||
|
setUser,
|
||||||
|
getUser,
|
||||||
|
setGame
|
||||||
|
};
|
@ -0,0 +1,25 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import cookies from "cookies";
|
||||||
|
|
||||||
|
// Set
|
||||||
|
function set ( req, res, name, data, httpOnly ) {
|
||||||
|
new cookies(req, res).set(name, data, {
|
||||||
|
secure: false,
|
||||||
|
httpOnly: httpOnly,
|
||||||
|
sameSite: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get
|
||||||
|
function get ( req, res, name ) {
|
||||||
|
return new cookies(req, res).get(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
module.exports = {
|
||||||
|
set,
|
||||||
|
get
|
||||||
|
};
|
@ -0,0 +1,26 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import jsonwebtoken from "jsonwebtoken";
|
||||||
|
|
||||||
|
// Set
|
||||||
|
function set ( data, key ) {
|
||||||
|
return JSON.stringify(jsonwebtoken.sign({ data: data }, key, { expiresIn: "30m" }));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get
|
||||||
|
function get ( data, key ) {
|
||||||
|
return new Promise ((resolve) => {
|
||||||
|
jsonwebtoken.verify(JSON.parse(data), key, (error, data) => {
|
||||||
|
if (error) resolve(false);
|
||||||
|
resolve(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
module.exports = {
|
||||||
|
set,
|
||||||
|
get
|
||||||
|
};
|
@ -0,0 +1,14 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Styles
|
||||||
|
import styles from "./copyrightCard.module.css";
|
||||||
|
|
||||||
|
// Copyright Card
|
||||||
|
export default function CopyrightCard () {
|
||||||
|
return (
|
||||||
|
<div className = { styles.copyrightCard }>
|
||||||
|
<h6>Copyright - Shooty Arena</h6>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,17 @@
|
|||||||
|
/* Copyright Card */
|
||||||
|
.copyrightCard {
|
||||||
|
width: 100vw;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copyright Card H6 */
|
||||||
|
.copyrightCard h6 {
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 10px;
|
||||||
|
color: #f700ff;
|
||||||
|
text-shadow: 0 0 10px #f700ff, 0 0 20px #f700ff, 0 0 30px #f700ff, 0 0 40px #f700ff;
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Styles
|
||||||
|
import styles from "./footer.module.css";
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import CopyrightCard from "./copyrightCard/copyrightCard.jsx";
|
||||||
|
import LinkCard from "./linkCard/linkCard";
|
||||||
|
import RenewableCard from "./renewableCard/renewableCard.jsx";
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
export default function Footer () {
|
||||||
|
return (
|
||||||
|
<div className = { styles.footer }>
|
||||||
|
<div>
|
||||||
|
<RenewableCard/>
|
||||||
|
<LinkCard title = "Legal" links = { [["Privacy Policy", "./privacypolicy"], ["Terms and Conditions", "./termsandconditions"], ["Accessibility Statement", "./accessibilitystatement"]] }/>
|
||||||
|
<LinkCard title = "Other" links = { [["Contact", "./contact"]] }/>
|
||||||
|
</div>
|
||||||
|
<CopyrightCard/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,27 @@
|
|||||||
|
/* Footer */
|
||||||
|
.footer {
|
||||||
|
width: 100vw;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer Div First Child */
|
||||||
|
.footer div:first-child {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small Screens */
|
||||||
|
@media screen and (max-width: 779px) {
|
||||||
|
/* Footer */
|
||||||
|
.footer {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
/* Footer Div First Child */
|
||||||
|
.footer div:first-child {
|
||||||
|
width: 260px;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Styles
|
||||||
|
import styles from "./linkCard.module.css";
|
||||||
|
|
||||||
|
// Link Card
|
||||||
|
export default function LinkCard ({ title, links }) {
|
||||||
|
return (
|
||||||
|
<div className = { styles.linkCard }>
|
||||||
|
<h5>{ title }</h5>
|
||||||
|
{
|
||||||
|
links.map(link => <h5><a href = { link[1] }>{ link[0] }</a></h5>)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,43 @@
|
|||||||
|
/* Link Card */
|
||||||
|
.linkCard {
|
||||||
|
width: 200px;
|
||||||
|
height: 100px;
|
||||||
|
padding: 30px;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Link Card H5 */
|
||||||
|
.linkCard h5 {
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 12px;
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #ff9d00;
|
||||||
|
text-shadow: 0 0 10px #ff9d00, 0 0 20px #ff9d00, 0 0 30px #ff9d00, 0 0 40px #ff9d00;
|
||||||
|
transition: text-shadow 0.2s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Link Card H5 Hover */
|
||||||
|
.linkCard h5:hover {
|
||||||
|
text-shadow: 0 0 10px #ff9d00, 0 0 20px #ff9d00;
|
||||||
|
}
|
||||||
|
/* Link Card H5 First Child */
|
||||||
|
.linkCard h5:first-child {
|
||||||
|
padding-top: 0;
|
||||||
|
font-size: 18px;
|
||||||
|
color: #8c00ff;
|
||||||
|
text-shadow: 0 0 10px #8c00ff, 0 0 20px #8c00ff, 0 0 30px #8c00ff, 0 0 40px #8c00ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Link Card A */
|
||||||
|
.linkCard a {
|
||||||
|
color: #ff9d00;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small Screens */
|
||||||
|
@media screen and (max-width: 779px) {
|
||||||
|
/* Legal Card H5 */
|
||||||
|
.linkCard h5 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Styles
|
||||||
|
import styles from "./renewableCard.module.css";
|
||||||
|
|
||||||
|
// Renewable Card
|
||||||
|
export default function RenewableCard () {
|
||||||
|
return (
|
||||||
|
<div className = { styles.renewableCard }>
|
||||||
|
<h4>Powered by renewable energy.</h4>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,28 @@
|
|||||||
|
/* Renewable Card Text Flicker */
|
||||||
|
@keyframes renewableCardTextFlicker {
|
||||||
|
30%, 32%, 34%, 80% {
|
||||||
|
text-shadow: 0 0 10px #00ff2a, 0 0 20px #00ff2a, 0 0 30px #00ff2a, 0 0 40px #00ff2a;
|
||||||
|
}
|
||||||
|
0%, 31%, 33%, 35%, 81% {
|
||||||
|
text-shadow: 0 0 10px #00ff2a, 0 0 20px #00ff2a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Renewable Card */
|
||||||
|
.renewableCard {
|
||||||
|
width: 200px;
|
||||||
|
padding: 30px;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Renewable Card H4 */
|
||||||
|
.renewableCard h4 {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
text-align: center;
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 30px;
|
||||||
|
color: #00ff2a;
|
||||||
|
text-shadow: 0 0 10px #00ff2a, 0 0 20px #00ff2a, 0 0 30px #00ff2a, 0 0 40px #00ff2a;
|
||||||
|
animation: renewableCardTextFlicker 6s infinite;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Styles
|
||||||
|
import styles from "./header.module.css";
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import NavigationCard from "./navigationCard/navigationCard.jsx";
|
||||||
|
import TitleCard from "./titleCard/titleCard.jsx";
|
||||||
|
|
||||||
|
// Header
|
||||||
|
export default function Header () {
|
||||||
|
return (
|
||||||
|
<div className = { styles.header }>
|
||||||
|
<TitleCard/>
|
||||||
|
<NavigationCard/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,23 @@
|
|||||||
|
/* Header */
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header A */
|
||||||
|
.header a {
|
||||||
|
font-family: neon;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small Screens */
|
||||||
|
@media screen and (max-width: 1027px) {
|
||||||
|
/* Header */
|
||||||
|
.header {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Styles
|
||||||
|
import styles from "./navigationCard.module.css";
|
||||||
|
|
||||||
|
// Navigation Card
|
||||||
|
export default function NavigationCard () {
|
||||||
|
return (
|
||||||
|
<div className = { styles.navigationCard }>
|
||||||
|
<h5><a href = "/play">Play</a></h5>
|
||||||
|
<h5><a href = "/leaderboards/1">Leaderboards</a></h5>
|
||||||
|
<h5><a href = "/account">Account</a></h5>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,35 @@
|
|||||||
|
/* Navigation Card */
|
||||||
|
.navigationCard {
|
||||||
|
width: 40%;
|
||||||
|
padding: 30px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Navigation Card H5 A */
|
||||||
|
.navigationCard h5 a {
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #ff9d00;
|
||||||
|
text-shadow: 0 0 10px #ff9d00, 0 0 20px #ff9d00, 0 0 30px #ff9d00, 0 0 40px #ff9d00;
|
||||||
|
transition: text-shadow 0.2s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Navigation Card H5 A Hover */
|
||||||
|
.navigationCard h5 a:hover {
|
||||||
|
text-shadow: 0 0 10px #ff9d00, 0 0 20px #ff9d00;
|
||||||
|
transition: text-shadow 0.2s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small Screens */
|
||||||
|
@media screen and (max-width: 1027px) {
|
||||||
|
/* Navigation Card */
|
||||||
|
.navigationCard {
|
||||||
|
width: 200px;
|
||||||
|
padding-top: 0;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Styles
|
||||||
|
import styles from "./titleCard.module.css";
|
||||||
|
|
||||||
|
// Title Card
|
||||||
|
export default function TitleCard () {
|
||||||
|
return (
|
||||||
|
<div className = { styles.titleCard }>
|
||||||
|
<h4><a href = "/">Shooty</a></h4>
|
||||||
|
<h4><a href = "/">Arena</a></h4>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,56 @@
|
|||||||
|
/* Title Card Shooty Text Flicker */
|
||||||
|
@keyframes titleCardShootyTextFlicker {
|
||||||
|
37%, 39%, 41%, 43% {
|
||||||
|
text-shadow: 0 0 10px #0062ff, 0 0 20px #0062ff, 0 0 30px #0062ff, 0 0 40px #0062ff;
|
||||||
|
}
|
||||||
|
35%, 38%, 40%, 42% {
|
||||||
|
text-shadow: 0 0 10px #0062ff, 0 0 20px #0062ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title Card Arena Text Flicker */
|
||||||
|
@keyframes titleCardArenaTextFlicker {
|
||||||
|
38%, 40% {
|
||||||
|
text-shadow: 0 0 10px #ff3300, 0 0 20px #ff3300, 0 0 30px #ff3300, 0 0 40px #ff3300;
|
||||||
|
}
|
||||||
|
35%, 39% {
|
||||||
|
text-shadow: 0 0 10px #ff3300, 0 0 20px #ff3300;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title Card */
|
||||||
|
.titleCard {
|
||||||
|
width: 40%;
|
||||||
|
padding: 30px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title Card H4 First Child */
|
||||||
|
.titleCard h4:first-child {
|
||||||
|
text-shadow: 0 0 10px #0062ff, 0 0 20px #0062ff, 0 0 30px #0062ff, 0 0 40px #0062ff;
|
||||||
|
animation: titleCardShootyTextFlicker 4s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title Card h4 Last Child */
|
||||||
|
.titleCard h4:last-child {
|
||||||
|
text-shadow: 0 0 10px #ff3300, 0 0 20px #ff3300, 0 0 30px #ff3300, 0 0 40px #ff3300;
|
||||||
|
animation: titleCardArenaTextFlicker 6s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title Card H4 First Child A */
|
||||||
|
.titleCard h4:first-child a {
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 50px;
|
||||||
|
color: #0062ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title Card H4 Last Child A */
|
||||||
|
.titleCard h4:last-child a {
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 50px;
|
||||||
|
color: #ff3300;
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Styles
|
||||||
|
import styles from "./title.module.css";
|
||||||
|
|
||||||
|
// Title
|
||||||
|
export default function Title ( props ) {
|
||||||
|
return (
|
||||||
|
<div className = { styles.title }>
|
||||||
|
<h1>{ props.title }</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,27 @@
|
|||||||
|
/* Title Text Flicker */
|
||||||
|
@keyframes titleTextFlicker {
|
||||||
|
44%, 48%, 50% {
|
||||||
|
text-shadow: 0 0 10px #00ff2a, 0 0 20px #00ff2a, 0 0 30px #00ff2a, 0 0 40px #00ff2a;
|
||||||
|
}
|
||||||
|
42%, 46%, 49% {
|
||||||
|
text-shadow: 0 0 10px #00ff2a, 0 0 20px #00ff2a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title */
|
||||||
|
.title {
|
||||||
|
padding: 30px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title H1 */
|
||||||
|
.title h1 {
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 70px;
|
||||||
|
color: #00ff2a;
|
||||||
|
text-shadow: 0 0 10px #00ff2a, 0 0 20px #00ff2a, 0 0 30px #00ff2a, 0 0 40px #00ff2a;
|
||||||
|
animation: titleTextFlicker 4s infinite;
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import encrypt from "./encrypt/encrypt.js";
|
||||||
|
import hash from "./hash/hash.js";
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
module.exports = {
|
||||||
|
encrypt: encrypt.encrypt,
|
||||||
|
decrypt: encrypt.decrypt,
|
||||||
|
hash: hash.hash,
|
||||||
|
compareHash: hash.compareHash
|
||||||
|
};
|
@ -0,0 +1,24 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import aesEverywhere from "aes-everywhere";
|
||||||
|
|
||||||
|
// Encrypt Key
|
||||||
|
const encryptKey = process.env.CRYPTOGRAPHY_PASSWORD;
|
||||||
|
|
||||||
|
// Encrypt
|
||||||
|
async function encrypt ( data ) {
|
||||||
|
return aesEverywhere.encrypt(data, encryptKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Decrypt
|
||||||
|
async function decrypt ( data ) {
|
||||||
|
return aesEverywhere.decrypt(data, encryptKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
module.exports = {
|
||||||
|
encrypt,
|
||||||
|
decrypt
|
||||||
|
};
|
@ -0,0 +1,21 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import bcrypt from "bcrypt";
|
||||||
|
|
||||||
|
// Hash
|
||||||
|
async function hash ( data ) {
|
||||||
|
return bcrypt.hash(data, await bcrypt.genSalt(8));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Compare Hash
|
||||||
|
async function compareHash ( data, hash ) {
|
||||||
|
return bcrypt.compare(data, hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
module.exports = {
|
||||||
|
hash,
|
||||||
|
compareHash
|
||||||
|
};
|
@ -0,0 +1,368 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import mysql from "mysql";
|
||||||
|
|
||||||
|
// Connection
|
||||||
|
const connection = mysql.createConnection({
|
||||||
|
host: "127.0.0.1",
|
||||||
|
user: process.env.DATABASE_USER,
|
||||||
|
password: process.env.DATABASE_PASSWORD,
|
||||||
|
database: "shootyarena"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Connect
|
||||||
|
connection.connect(( error ) => {
|
||||||
|
console.log(error)
|
||||||
|
if (error) throw error;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create Tables
|
||||||
|
async function createTables () {
|
||||||
|
connection.query("CREATE table users ( username VARCHAR(10) NOT NULL UNIQUE PRIMARY KEY, email VARCHAR(331) NOT NULL UNIQUE, passphrase VARCHAR(60) NOT NULL, active VARCHAR(60) NOT NULL, lastLoginTime INT NOT NULL );", ( error, _ ) => {
|
||||||
|
if (error) throw error;
|
||||||
|
});
|
||||||
|
connection.query("CREATE TABLE stats ( username VARCHAR(10) NOT NULL UNIQUE PRIMARY KEY, FOREIGN KEY(username) REFERENCES users(username), gameRank VARCHAR(13) NOT NULL, elo INT NOT NULL, kills INT NOT NULL, deaths INT NOT NULL );", ( error, _ ) => {
|
||||||
|
if (error) throw error;
|
||||||
|
});
|
||||||
|
connection.query("CREATE TABLE servers ( address VARCHAR(45) UNIQUE, playerLimit INT NOT NULL, playerCount INT NOT NULL );", ( error, _ ) => {
|
||||||
|
if (error) throw error;
|
||||||
|
});
|
||||||
|
connection.query("CREATE TABLE codes ( username VARCHAR(10) NOT NULL UNIQUE PRIMARY KEY, FOREIGN KEY(username) REFERENCES users(username), code INT NOT NULL );", ( error, _ ) => {
|
||||||
|
if (error) throw error;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Drop Tables
|
||||||
|
async function dropTables () {
|
||||||
|
connection.query("DROP TABLE servers;", ( error, _ ) => {
|
||||||
|
if (error) throw error;
|
||||||
|
});
|
||||||
|
connection.query("DROP TABLE stats;", ( error, _ ) => {
|
||||||
|
if (error) throw error;
|
||||||
|
});
|
||||||
|
connection.query("DROP TABLE codes;", ( error, _ ) => {
|
||||||
|
if (error) throw error;
|
||||||
|
});
|
||||||
|
connection.query("DROP TABLE users;", ( error, _ ) => {
|
||||||
|
if (error) throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create User
|
||||||
|
async function createUser ( username, email, passphrase, active ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("INSERT INTO users ( username, email, passphrase, active, lastLoginTime ) VALUES ?;", [[[ username, email, passphrase, active, 0 ]]], ( error, _ ) => {
|
||||||
|
if (error) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create Stat
|
||||||
|
async function createStat ( username ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("INSERT INTO stats ( username, gameRank, elo, kills, deaths ) VALUES ?;", [[[ username, "Shitty Shooty", 800, 0, 0 ]]], ( error, _ ) => {
|
||||||
|
if (error) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create Server
|
||||||
|
async function createServer ( address, playerLimit ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("INSERT INTO servers ( address, playerLimit, playerCount ) VALUES ?;", [[[ address, playerLimit, 0 ]]], ( error, _ ) => {
|
||||||
|
if (error) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create Code
|
||||||
|
async function createCode ( username, code ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("INSERT INTO codes ( username, code ) VALUES ?;", [[[ username, code ]]], ( error, _ ) => {
|
||||||
|
if (error) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete Server
|
||||||
|
async function deleteServer ( address ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("DELETE FROM servers WHERE address = ?;", [[ address ]], ( error, _ ) => {
|
||||||
|
if (error) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Username Exists
|
||||||
|
async function usernameExists ( username ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("SELECT username FROM users WHERE username = ?;", [[ username ]], ( error, result ) => {
|
||||||
|
console.log(error, result)
|
||||||
|
if (error || result[0] !== undefined) {
|
||||||
|
resolve(true);
|
||||||
|
} else {
|
||||||
|
resolve(false);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Email Exists
|
||||||
|
async function emailExists ( email ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("SELECT email FROM users WHERE email = ?;", [[ email ]], ( error, result ) => {
|
||||||
|
if (error || result[0] !== undefined) {
|
||||||
|
resolve(true);
|
||||||
|
} else {
|
||||||
|
resolve(false);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Active Exists
|
||||||
|
async function activeExists ( active ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("SELECT active FROM users WHERE active = ?;", [[ active ]], ( error, result ) => {
|
||||||
|
if (error || result[0] !== undefined) {
|
||||||
|
resolve(true);
|
||||||
|
} else {
|
||||||
|
resolve(false);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Activate User
|
||||||
|
async function activateUser ( active ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("UPDATE users SET active = '' WHERE active = ?;", [[ active ]], ( error, result ) => {
|
||||||
|
if (error || result.affectedRows === 0) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Login User
|
||||||
|
async function loginUser ( email ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("SELECT passphrase FROM users WHERE email = ?;", [[ email ]], ( error, result ) => {
|
||||||
|
if (error || result[0] === undefined) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(result[0]);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get All Stats
|
||||||
|
async function getAllStats () {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("SELECT * FROM stats ORDER BY elo DESC;", ( error, result ) => {
|
||||||
|
if (error) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(result);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get Stats
|
||||||
|
async function getStats ( username ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("SELECT gameRank, elo, kills, deaths FROM stats WHERE username = ?;", [[ username ]], ( error, result ) => {
|
||||||
|
if (error || result[0] === undefined) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(result);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update Game Rank
|
||||||
|
async function updateGameRank ( username, gameRank ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("UPDATE stats SET gameRank = ? WHERE username = ?;", [[ gameRank ], [ username ]], ( error, result ) => {
|
||||||
|
if (error || result.affectedRows === 0) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update Elo
|
||||||
|
async function updateElo ( username, elo ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("UPDATE stats SET elo = ? WHERE username = ?;", [[ elo ], [ username ]], ( error, result ) => {
|
||||||
|
if (error || result.affectedRows === 0) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update Kills
|
||||||
|
async function updateKills ( username, kills ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("UPDATE stats SET kills = ? WHERE username = ?;", [[ kills ], [ username ]], ( error, result ) => {
|
||||||
|
if (error || result.affectedRows === 0) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update Deaths
|
||||||
|
async function updateDeaths ( username, deaths ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("UPDATE stats SET deaths = ? WHERE username = ?;", [[ deaths ], [ username ]], ( error, result ) => {
|
||||||
|
if (error || result.affectedRows === 0) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get Free Server
|
||||||
|
async function getFreeServer () {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("SELECT address FROM servers WHERE playerCount < playerLimit ORDER BY playerCount DESC;", ( error, result ) => {
|
||||||
|
if (error || result[0] === undefined) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(result[0]);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set Player Count
|
||||||
|
async function setPlayerCount ( address, playerCount ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("UPDATE servers SET playerCount = ? WHERE address = ?;", [[ playerCount ], [ address ]], ( error, _ ) => {
|
||||||
|
if (error || result.affectedRows === 0) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get Active
|
||||||
|
async function getActive ( email ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("SELECT active FROM users WHERE email = ?;", [[email]], ( error, result ) => {
|
||||||
|
if (error == null && result[0].active == "") {
|
||||||
|
resolve(true);
|
||||||
|
} else {
|
||||||
|
resolve(result[0].active);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get Username
|
||||||
|
async function getUsername ( email ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("SELECT username FROM users WHERE email = ?;", [[email]], ( error, result ) => {
|
||||||
|
if (error || result[0] === undefined) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(result[0].username)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Code
|
||||||
|
async function getCode ( username ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("SELECT code FROM codes WHERE username = ?;", [[ username ]], ( error, result ) => {
|
||||||
|
if (error || result[0] === undefined) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(result[0].code);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Code
|
||||||
|
async function setCode ( username, code ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
connection.query("UPDATE codes SET code = ? WHERE username = ?", [[code], [username]], ( error, result ) => {
|
||||||
|
if (error) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
module.exports = {
|
||||||
|
createTables,
|
||||||
|
dropTables,
|
||||||
|
createUser,
|
||||||
|
createStat,
|
||||||
|
createServer,
|
||||||
|
deleteServer,
|
||||||
|
usernameExists,
|
||||||
|
emailExists,
|
||||||
|
activeExists,
|
||||||
|
activateUser,
|
||||||
|
loginUser,
|
||||||
|
getAllStats,
|
||||||
|
getStats,
|
||||||
|
updateGameRank,
|
||||||
|
updateElo,
|
||||||
|
updateKills,
|
||||||
|
updateDeaths,
|
||||||
|
getFreeServer,
|
||||||
|
setPlayerCount,
|
||||||
|
getActive,
|
||||||
|
getUsername,
|
||||||
|
createCode,
|
||||||
|
getCode,
|
||||||
|
setCode,
|
||||||
|
|
||||||
|
};
|
@ -0,0 +1,12 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import validate from "./validate/validate.js"
|
||||||
|
import send from "./send/send.js";
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
module.exports = {
|
||||||
|
validateEmail: validate.validateEmail,
|
||||||
|
sendAccountActivationEmail: send.sendAccountActivationEmail
|
||||||
|
};
|
@ -0,0 +1,41 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import nodemailer from "nodemailer";
|
||||||
|
|
||||||
|
// Transport
|
||||||
|
const transport = nodemailer.createTransport({
|
||||||
|
host: process.env.MAIL_HOST,
|
||||||
|
port: 587,
|
||||||
|
secure: process.env.MAIL_SECURE != "false",
|
||||||
|
auth: {
|
||||||
|
user: process.env.MAIL_USER,
|
||||||
|
pass: process.env.MAIL_PASS
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Send Account Activation Email
|
||||||
|
async function sendAccountActivationEmail ( to, link ) {
|
||||||
|
return new Promise (async ( resolve, _ ) => {
|
||||||
|
const mailOptions = {
|
||||||
|
from: "Shooty Arena",
|
||||||
|
to: to,
|
||||||
|
subject: "Shooty Arena Account Activation",
|
||||||
|
text: "Welcome to Shooty Arena! To activate your account visit { link }".replace("{ link }", link)
|
||||||
|
};
|
||||||
|
transport.sendMail(mailOptions, ( err, _ ) => {
|
||||||
|
if (err) {
|
||||||
|
console.log("mail error")
|
||||||
|
console.log(err)
|
||||||
|
resolve(false)
|
||||||
|
};
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
module.exports = {
|
||||||
|
sendAccountActivationEmail
|
||||||
|
};
|
@ -0,0 +1,17 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
const deepEmailValidator = require("deep-email-validator");
|
||||||
|
|
||||||
|
// Validate Email
|
||||||
|
async function validateEmail ( email ) {
|
||||||
|
const check = await deepEmailValidator.validate(email);
|
||||||
|
if (check.validators.regex.valid && check.validators.mx.valid) return true;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
module.exports = {
|
||||||
|
validateEmail
|
||||||
|
};
|
@ -0,0 +1,7 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
module.exports = {
|
||||||
|
reactStrictMode: true
|
||||||
|
};
|
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "web",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "next lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"aes-everywhere": "^1.0.0",
|
||||||
|
"bcrypt": "^5.0.1",
|
||||||
|
"config": "^3.3.7",
|
||||||
|
"cookies": "^0.8.0",
|
||||||
|
"deep-email-validator": "^0.1.21",
|
||||||
|
"jsonwebtoken": "^8.5.1",
|
||||||
|
"mysql": "^2.18.1",
|
||||||
|
"next": "^12.0.10",
|
||||||
|
"nodemailer": "^6.7.2",
|
||||||
|
"react": "^17.0.2",
|
||||||
|
"react-dom": "17.0.2",
|
||||||
|
"socket.io-client": "^4.4.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "8.6.0",
|
||||||
|
"eslint-config-next": "12.0.7"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import styles from "../styles/404.module.css";
|
||||||
|
import Header from "../components/header/header.jsx";
|
||||||
|
import Title from "../components/title/title.jsx";
|
||||||
|
import Footer from "../components/footer/footer.jsx";
|
||||||
|
|
||||||
|
// Error 404
|
||||||
|
export default function Error404 () {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Header/>
|
||||||
|
<Title title = "Error"/>
|
||||||
|
<div className = { styles.error404 }>
|
||||||
|
<h2>404</h2>
|
||||||
|
</div>
|
||||||
|
<Footer/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,13 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Styles
|
||||||
|
import "../styles/reset.css"
|
||||||
|
import "../styles/fonts.css"
|
||||||
|
|
||||||
|
// My App
|
||||||
|
export default function MyApp ( { Component, pageProps } ) {
|
||||||
|
return (
|
||||||
|
<Component { ...pageProps }/>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,18 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import Header from "../components/header/header.jsx";
|
||||||
|
import Title from "../components/title/title.jsx";
|
||||||
|
import Footer from "../components/footer/footer.jsx";
|
||||||
|
|
||||||
|
// Index
|
||||||
|
export default function Index () {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Header/>
|
||||||
|
<Title title = "505 - Error"/>
|
||||||
|
<Footer/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,163 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import authentication from "../authentication/authentication.js";
|
||||||
|
import styles from "../styles/account.module.css";
|
||||||
|
import Header from "../components/header/header.jsx";
|
||||||
|
import Title from "../components/title/title.jsx";
|
||||||
|
import Footer from "../components/footer/footer.jsx";
|
||||||
|
|
||||||
|
// Get Server Side Props
|
||||||
|
export async function getServerSideProps ( ctx ) {
|
||||||
|
try {
|
||||||
|
const user = await authentication.getUser(ctx.req, ctx.res);
|
||||||
|
if (user == "") {
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
loggedIn: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
loggedIn: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
loggedIn: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Account
|
||||||
|
export default function Home( props ) {
|
||||||
|
const [ signInError, setSignInError ] = useState("");
|
||||||
|
const [ signUpError, setSignUpError ] = useState("");
|
||||||
|
useEffect(() => {
|
||||||
|
const host = "http://localhost:3000/";
|
||||||
|
try {
|
||||||
|
const signInForm = document.querySelector(".signInForm");
|
||||||
|
signInForm.addEventListener("submit", async function ( event ) {
|
||||||
|
try {
|
||||||
|
event.preventDefault();
|
||||||
|
const formData = new FormData(signInForm).entries();
|
||||||
|
const request = await fetch(host + "api/signIn", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(Object.fromEntries(formData))
|
||||||
|
});
|
||||||
|
const result = await request.json();
|
||||||
|
if (result.response.success == true && result.response.activated == true) {
|
||||||
|
window.location = host + "account";
|
||||||
|
} else if (result.response.success == true && result.response.activated == false) {
|
||||||
|
setSignInError("Account Not Activated");
|
||||||
|
} else {
|
||||||
|
setSignInError("Bad Login");
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
setSignInError("Error");
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
} catch {};
|
||||||
|
try {
|
||||||
|
const signUpForm = document.querySelector(".signUpForm");
|
||||||
|
signUpForm.addEventListener("submit", async function ( event ) {
|
||||||
|
try {
|
||||||
|
event.preventDefault();
|
||||||
|
const formData = new FormData(signUpForm).entries();
|
||||||
|
const response = await fetch(host + "api/createAccount", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(Object.fromEntries(formData))
|
||||||
|
});
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.response.error != "") {
|
||||||
|
setSignUpError(result.response.error);
|
||||||
|
} else {
|
||||||
|
setSignUpError("Check Your Email To Activate Your Account");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setSignUpError("Error");
|
||||||
|
console.log(error)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} catch {};
|
||||||
|
try {
|
||||||
|
const signOutForm = document.querySelector(".signOutForm");
|
||||||
|
signOutForm.addEventListener("submit", async function ( event ) {
|
||||||
|
try {
|
||||||
|
event.preventDefault();
|
||||||
|
const formData = new FormData(signOutForm).entries()
|
||||||
|
const response = await fetch(host + "api/signOut", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(Object.fromEntries(formData))
|
||||||
|
});
|
||||||
|
await response.json();
|
||||||
|
window.location = host + "account";
|
||||||
|
} catch {
|
||||||
|
window.location = host + "account";
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
} catch {};
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Header/>
|
||||||
|
<Title title = "Account"/>
|
||||||
|
{
|
||||||
|
props.loggedIn ?
|
||||||
|
<div className = { styles.account }>
|
||||||
|
<form className = "signOutForm">
|
||||||
|
<button type = "submit">Sign Out</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
: (
|
||||||
|
<div className = { styles.account }>
|
||||||
|
<div>
|
||||||
|
<h2>Sign In</h2>
|
||||||
|
<form className = "signInForm">
|
||||||
|
<input type = "email" placeholder = "Email" name = "Email"/>
|
||||||
|
<input type = "password" placeholder = "Password" name = "Password"/>
|
||||||
|
<button type = "submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
{
|
||||||
|
signInError ?
|
||||||
|
<h3>{ signInError }</h3>
|
||||||
|
: (
|
||||||
|
<h3> </h3>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>Sign Up</h2>
|
||||||
|
<form className = "signUpForm">
|
||||||
|
<input type = "text" placeholder = "Username" name = "Username"/>
|
||||||
|
<input type = "email" placeholder = "Email" name = "Email"/>
|
||||||
|
<input type = "password" placeholder = "Password" name = "Password"/>
|
||||||
|
<input type = "password" placeholder = "Confirm Password" name = "Confirm Password"/>
|
||||||
|
<button type = "submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
{
|
||||||
|
signUpError ?
|
||||||
|
<h3>{ signUpError }</h3>
|
||||||
|
: (
|
||||||
|
<h3> </h3>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<Footer/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,164 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import authentication from "../../authentication/authentication.js";
|
||||||
|
import database from "../../database/database.js";
|
||||||
|
import styles from "../../styles/account.module.css";
|
||||||
|
import Header from "../../components/header/header.jsx";
|
||||||
|
import Title from "../../components/title/title.jsx";
|
||||||
|
import Footer from "../../components/footer/footer.jsx";
|
||||||
|
|
||||||
|
// Get Server Side Props
|
||||||
|
export async function getServerSideProps ( ctx ) {
|
||||||
|
try {
|
||||||
|
if (await database.activateUser(ctx.query.activate)) {
|
||||||
|
await authentication.getUser(ctx.req, ctx.res);
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
message: "Account Activated"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
await authentication.getUser(ctx.req, ctx.res);
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
message: "Error Activating Account"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
await authentication.getUser(ctx.req, ctx.res);
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
message: "Error"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Account
|
||||||
|
export default function Home( props ) {
|
||||||
|
const [ signInError, setSignInError ] = useState("");
|
||||||
|
const [ signUpError, setSignUpError ] = useState("");
|
||||||
|
useEffect(() => {
|
||||||
|
const host = "http://localhost:3000/";
|
||||||
|
try {
|
||||||
|
const signInForm = document.querySelector(".signInForm");
|
||||||
|
signInForm.addEventListener("submit", async function ( event ) {
|
||||||
|
try {
|
||||||
|
event.preventDefault();
|
||||||
|
const formData = new FormData(signInForm).entries();
|
||||||
|
const request = await fetch(host + "api/signIn", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(Object.fromEntries(formData))
|
||||||
|
});
|
||||||
|
const result = await request.json();
|
||||||
|
if (result.response.success == true && result.response.activated == true) {
|
||||||
|
window.location = host + "account";
|
||||||
|
} else if (result.response.success == true && result.response.activated == false) {
|
||||||
|
setSignInError("Account Not Activated");
|
||||||
|
} else {
|
||||||
|
setSignInError("Bad Login");
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
setSignInError("Error");
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
} catch {};
|
||||||
|
try {
|
||||||
|
const signUpForm = document.querySelector(".signUpForm");
|
||||||
|
signUpForm.addEventListener("submit", async function ( event ) {
|
||||||
|
try {
|
||||||
|
event.preventDefault();
|
||||||
|
const formData = new FormData(signUpForm).entries();
|
||||||
|
const response = await fetch(host + "api/createAccount", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(Object.fromEntries(formData))
|
||||||
|
});
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.response.error != undefined) {
|
||||||
|
setSignUpError(result.response.error);
|
||||||
|
} else {
|
||||||
|
setSignUpError("Check Your Email To Activate Your Account");
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
setSignUpError("Error");
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} catch {};
|
||||||
|
try {
|
||||||
|
const signOutForm = document.querySelector(".signOutForm");
|
||||||
|
signOutForm.addEventListener("submit", async function ( event ) {
|
||||||
|
try {
|
||||||
|
event.preventDefault();
|
||||||
|
const formData = new FormData(signOutForm).entries()
|
||||||
|
const response = await fetch(host + "api/signOut", {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
body: JSON.stringify(Object.fromEntries(formData))
|
||||||
|
});
|
||||||
|
await response.json();
|
||||||
|
window.location = host + "account";
|
||||||
|
} catch {
|
||||||
|
window.location = host + "account";
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
} catch {};
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Header/>
|
||||||
|
<Title title = "Account"/>
|
||||||
|
<Title title = { props.message }/>
|
||||||
|
{
|
||||||
|
props.loggedIn ?
|
||||||
|
<div className = { styles.account }>
|
||||||
|
<form className = "signOutForm">
|
||||||
|
<button type = "submit">Sign Out</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
: (
|
||||||
|
<div className = { styles.account }>
|
||||||
|
<div>
|
||||||
|
<h2>Sign In</h2>
|
||||||
|
<form className = "signInForm">
|
||||||
|
<input type = "email" placeholder = "Email" name = "Email"/>
|
||||||
|
<input type = "password" placeholder = "Password" name = "Password"/>
|
||||||
|
<button type = "submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
{
|
||||||
|
signInError ?
|
||||||
|
<h3>{ signInError }</h3>
|
||||||
|
: (
|
||||||
|
<h3> </h3>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>Sign Up</h2>
|
||||||
|
<form className = "signUpForm">
|
||||||
|
<input type = "text" placeholder = "Username" name = "Username"/>
|
||||||
|
<input type = "email" placeholder = "Email" name = "Email"/>
|
||||||
|
<input type = "password" placeholder = "Password" name = "Password"/>
|
||||||
|
<input type = "password" placeholder = "Confirm Password" name = "Confirm Password"/>
|
||||||
|
<button type = "submit">Submit</button>
|
||||||
|
</form>
|
||||||
|
{
|
||||||
|
signUpError ?
|
||||||
|
<h3>{ signUpError }</h3>
|
||||||
|
: (
|
||||||
|
<h3> </h3>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<Footer/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,74 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import cryptography from "../../cryptography/cryptography.js";
|
||||||
|
import database from "../../database/database.js";
|
||||||
|
import mail from "../../mail/mail.js";
|
||||||
|
|
||||||
|
// Handler
|
||||||
|
export default async function handler ( req, res ) {
|
||||||
|
try {
|
||||||
|
const host = "http://localhost:3000/";
|
||||||
|
const response = {
|
||||||
|
success: false,
|
||||||
|
error: ""
|
||||||
|
};
|
||||||
|
req.body.Username = req.body.Username.toUpperCase();
|
||||||
|
if (req.body.Username.length < 1) {
|
||||||
|
response.error = "Enter A Username";
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
} else if (req.body.Username.length > 10) {
|
||||||
|
response.error = "Username Must Be 10 Characters Or Less";
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
} else if (req.body.Username.match(/^\w+$/) == null) {
|
||||||
|
response.error = "Username Must Only Contain Alphanumberic Characters";
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
} else if (await database.usernameExists(req.body.Username)) {
|
||||||
|
response.error = "Username Already In Use";
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
} else if (await mail.validateEmail(req.body.Email) == false) {
|
||||||
|
response.error = "Email Is Not Valid";
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
} else if (await database.emailExists(req.body.Email)) {
|
||||||
|
response.error = "Email Already In Use";
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
} else if (req.body.Password.length < 4) {
|
||||||
|
response.error = "Password Must Be At Least 4 Characters Long";
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
} else if (await database.createUser(req.body.Username, req.body.Email, await cryptography.hash(req.body.Password), req.body.Username)) {
|
||||||
|
response.success = true;
|
||||||
|
const t = await mail.sendAccountActivationEmail(req.body.Email, host + "activate/" + req.body.Username);
|
||||||
|
console.log(t)
|
||||||
|
await database.createStat(req.body.Username);
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
response.error = "Error Creating User";
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
response.success = false;
|
||||||
|
response.error = "Error";
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,14 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import database from "../../../database/database.js";
|
||||||
|
|
||||||
|
// Handler
|
||||||
|
export default async function handler ( req, res ) {
|
||||||
|
try {
|
||||||
|
res.send(await database.getStats(req.query.getStats)[0]);
|
||||||
|
} catch {
|
||||||
|
res.send(500);
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,21 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import database from "../../database/database.js";
|
||||||
|
|
||||||
|
// Handler
|
||||||
|
export default async function handler ( req, res ) {
|
||||||
|
try {
|
||||||
|
const aes256 = require("aes-everywhere");
|
||||||
|
const decryptedData = aes256.decrypt(req.body, process.env.CRYPTOGRAPHY_PASSWORD).split(",");
|
||||||
|
if (decryptedData.length != 2) {
|
||||||
|
res.send(500);
|
||||||
|
} else {
|
||||||
|
await database.createServer(decryptedData[0], decryptedData[1]);
|
||||||
|
res.send(200);
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
res.send(500);
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,14 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import database from "../../database/database.js";
|
||||||
|
|
||||||
|
// Handler
|
||||||
|
export default async function handler ( req, res ) {
|
||||||
|
try {
|
||||||
|
res.send(await database.getFreeServer());
|
||||||
|
} catch {
|
||||||
|
res.send(500);
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,49 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import authentication from "../../authentication/authentication.js";
|
||||||
|
import cryptography from "../../cryptography/cryptography.js";
|
||||||
|
import database from "../../database/database.js";
|
||||||
|
import mail from "../../mail/mail.js";
|
||||||
|
|
||||||
|
// Handler
|
||||||
|
export default async function handler ( req, res ) {
|
||||||
|
try {
|
||||||
|
const response = {
|
||||||
|
success: false,
|
||||||
|
activated: false
|
||||||
|
};
|
||||||
|
const password = await database.loginUser(req.body.Email);
|
||||||
|
if (password == false) {
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const active = await database.getActive(req.body.Email);
|
||||||
|
if (await cryptography.compareHash(req.body.Password, password.passphrase)) {
|
||||||
|
if (active === true) {
|
||||||
|
const user = await database.getUsername(req.body.Email);
|
||||||
|
await authentication.setUser(req, res, user);
|
||||||
|
response.success = true;
|
||||||
|
response.activated = true;
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await mail.sendAccountActivationEmail(req.body.Email, "http://localhost:3000/" + "activate/" + await database.getActive(req.body.Email));
|
||||||
|
response.success = true;
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
res.send({
|
||||||
|
response
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
res.send(500);
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,15 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import authentication from "../../authentication/authentication.js";
|
||||||
|
|
||||||
|
// Handler
|
||||||
|
export default async function handler ( req, res ) {
|
||||||
|
try {
|
||||||
|
await authentication.setUser(req, res, "");
|
||||||
|
res.send(200);
|
||||||
|
} catch {
|
||||||
|
res.send(500);
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,25 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import database from "../../database/database.js";
|
||||||
|
|
||||||
|
// Handler
|
||||||
|
export default async function handler ( req, res ) {
|
||||||
|
try {
|
||||||
|
const aes256 = require("aes-everywhere");
|
||||||
|
const data = aes256.decrypt(req.body , 'password');
|
||||||
|
const decryptedData = data.split(",");
|
||||||
|
if (decryptedData.length != 5) {
|
||||||
|
res.send(500);
|
||||||
|
} else {
|
||||||
|
await database.updateElo(decryptedData[0], decryptedData[1]);
|
||||||
|
await database.updateGameRank(decryptedData[0], decryptedData[2]);
|
||||||
|
await database.updateKills(decryptedData[0], decryptedData[3]);
|
||||||
|
await database.updateDeaths(decryptedData[0], decryptedData[4]);
|
||||||
|
res.send(200);
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
res.send(500);
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,38 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import authentication from "../authentication/authentication.js";
|
||||||
|
import styles from "../styles/index.module.css";
|
||||||
|
import Header from "../components/header/header.jsx";
|
||||||
|
import Title from "../components/title/title.jsx";
|
||||||
|
import Footer from "../components/footer/footer.jsx";
|
||||||
|
|
||||||
|
// Get Server Side Props
|
||||||
|
export async function getServerSideProps ( ctx ) {
|
||||||
|
try {
|
||||||
|
await authentication.getUser(ctx.req, ctx.res);
|
||||||
|
return {
|
||||||
|
props: {}
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
return {
|
||||||
|
props: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Index
|
||||||
|
export default function Index () {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Header/>
|
||||||
|
<Title title = "Home"/>
|
||||||
|
<div className = { styles.index }>
|
||||||
|
<h2>Shooty Arena is an online multiplayer platformer shooter! Sign in or create an account to get started.</h2>
|
||||||
|
<h3>Currently in alpha. V0.1.0</h3>
|
||||||
|
</div>
|
||||||
|
<Footer/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,172 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import authentication from "../../authentication/authentication.js";
|
||||||
|
import database from "../../database/database.js";
|
||||||
|
import styles from "../../styles/leaderboards.module.css";
|
||||||
|
import Header from "../../components/header/header.jsx";
|
||||||
|
import Title from "../../components/title/title.jsx";
|
||||||
|
import Footer from "../../components/footer/footer.jsx";
|
||||||
|
|
||||||
|
// Get Server Side Props
|
||||||
|
export async function getServerSideProps ( ctx ) {
|
||||||
|
try {
|
||||||
|
await authentication.getUser(ctx.req, ctx.res);
|
||||||
|
const stats = await database.getAllStats();
|
||||||
|
const pageStats = [];
|
||||||
|
let previousPage = false;
|
||||||
|
let nextPage = false;
|
||||||
|
if (ctx.query.page != 1) {
|
||||||
|
previousPage = Number(ctx.query.page) - 1;
|
||||||
|
};
|
||||||
|
for (let stat = ((ctx.query.page - 1) * 4); stat < stats.length; stat++) {
|
||||||
|
if (stat <= ((ctx.query.page - 1) * 4) + 3) {
|
||||||
|
pageStats.push(stats[stat]);
|
||||||
|
} else {
|
||||||
|
nextPage = Number(ctx.query.page) + 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
if (pageStats.length == 0) {
|
||||||
|
return {
|
||||||
|
redirect: {
|
||||||
|
permanent: false,
|
||||||
|
destination: "/leaderboards/1"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
pageStats: JSON.stringify(pageStats),
|
||||||
|
previousPage: previousPage,
|
||||||
|
nextPage: nextPage
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
return {
|
||||||
|
redirect: {
|
||||||
|
permanent: false,
|
||||||
|
destination: "/leaderboards/1"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Leaderboard
|
||||||
|
export default function Leaderboards ( props ) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Header/>
|
||||||
|
<Title title = "Leaderboards"/>
|
||||||
|
<div className = { styles.leaderboards }>
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Username
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Game Rank
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Elo
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Kills
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Deaths
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
{
|
||||||
|
JSON.parse(props.pageStats).map(stats => {
|
||||||
|
return (
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{ stats.username }
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{ stats.gameRank }
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{ stats.elo }
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{ stats.kills }
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{ stats.deaths }
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Rank
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
Elo
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Shitty Shooty
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
0
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Cutie Shooty
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
1000
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Beauty Shooty
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
2000
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Snooty Shooty
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
3000
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
props.previousPage != false && props.nextPage != false &&
|
||||||
|
<div>
|
||||||
|
<a href = { "/leaderboards/?".replace("?", props.previousPage) }>Previous Page</a>
|
||||||
|
<a href = { "/leaderboards/?".replace("?", props.nextPage) }>Next Page</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
props.previousPage != false && props.nextPage == false &&
|
||||||
|
<div>
|
||||||
|
<a href = { "/leaderboards/?".replace("?", props.previousPage) } style = {{"text-align": "center"}}>Previous Page</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
props.nextPage != false && props.previousPage == false &&
|
||||||
|
<div>
|
||||||
|
<a href = { "/leaderboards/?".replace("?", props.nextPage) } style = {{"text-align": "center"}}>Next Page</a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<Footer/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,574 @@
|
|||||||
|
// Strict Mode
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
import React, { useEffect, useState, useRef } from "react";
|
||||||
|
import authentication from "../authentication/authentication.js";
|
||||||
|
import database from "../database/database.js";
|
||||||
|
import styles from "../styles/play.module.css";
|
||||||
|
import Header from "../components/header/header.jsx";
|
||||||
|
import Title from "../components/title/title.jsx";
|
||||||
|
import Footer from "../components/footer/footer.jsx";
|
||||||
|
import io from "socket.io-client";
|
||||||
|
|
||||||
|
// Get Server Side Props
|
||||||
|
export async function getServerSideProps ( ctx ) {
|
||||||
|
try {
|
||||||
|
let user = ""
|
||||||
|
try {
|
||||||
|
user = await authentication.getUser(ctx.req, ctx.res)
|
||||||
|
} catch (e) {
|
||||||
|
user = ""
|
||||||
|
}
|
||||||
|
if (user=="") {
|
||||||
|
return {
|
||||||
|
redirect: {
|
||||||
|
destination: '/account',
|
||||||
|
permanent: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var AES256 = require('aes-everywhere');
|
||||||
|
const stats = await database.getStats(user)
|
||||||
|
await authentication.setGame(ctx.req, ctx.res, AES256.encrypt(`${user},${stats[0].gameRank},${stats[0].elo},${stats[0].kills},${stats[0].deaths}`, 'passphrase = encrypt("Shooty Arena")'))
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
loggedIn: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return {
|
||||||
|
redirect: {
|
||||||
|
destination: '/account',
|
||||||
|
permanent: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play
|
||||||
|
export default function Play () {
|
||||||
|
// Refs
|
||||||
|
const canvasRef = useRef(null);
|
||||||
|
let socket = null;
|
||||||
|
let menu = true;
|
||||||
|
// Use Effect
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
|
// Load Images
|
||||||
|
const image_flat = new Image();
|
||||||
|
image_flat.src = "/tiles/flat.png";
|
||||||
|
const image_corner = new Image();
|
||||||
|
image_corner.src = "/tiles/corner.png";
|
||||||
|
const image_background = new Image();
|
||||||
|
image_background.src = "/backgrounds/background.png";
|
||||||
|
const image_background_light = new Image();
|
||||||
|
image_background_light.src = "/backgrounds/backgroundLight.png";
|
||||||
|
const image_player_right = new Image();
|
||||||
|
image_player_right.src = "/players/right.png";
|
||||||
|
const image_player_left = new Image();
|
||||||
|
image_player_left.src = "/players/left.png"
|
||||||
|
const image_gun_right = new Image();
|
||||||
|
image_gun_right.src = "/players/gunRight.png";
|
||||||
|
const image_gun_left = new Image();
|
||||||
|
image_gun_left.src = "/players/gunLeft.png";
|
||||||
|
|
||||||
|
// Sounds
|
||||||
|
const shotSound1 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound2 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound3 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound4 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound5 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound6 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound7 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound8 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound9 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound10 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound11 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound12 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound13 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound14 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound15 = new Audio("/sounds/shoot.mp3");
|
||||||
|
const shotSound16 = new Audio("/sounds/shoot.mp3");
|
||||||
|
|
||||||
|
// Jump Sounds
|
||||||
|
const jumpSound1 = new Audio("/sounds/jump.mp3");
|
||||||
|
const jumpSound2 = new Audio("/sounds/jump.mp3");
|
||||||
|
const jumpSound3 = new Audio("/sounds/jump.mp3");
|
||||||
|
const jumpSound4 = new Audio("/sounds/jump.mp3");
|
||||||
|
|
||||||
|
// Jump Sounds
|
||||||
|
const landSound1 = new Audio("/sounds/land.mp3");
|
||||||
|
const landSound2 = new Audio("/sounds/land.mp3");
|
||||||
|
const landSound3 = new Audio("/sounds/land.mp3");
|
||||||
|
const landSound4 = new Audio("/sounds/land.mp3");
|
||||||
|
const landSound5 = new Audio("/sounds/land.mp3");
|
||||||
|
const landSound6 = new Audio("/sounds/land.mp3");
|
||||||
|
const landSound7 = new Audio("/sounds/land.mp3");
|
||||||
|
const landSound8 = new Audio("/sounds/land.mp3");
|
||||||
|
|
||||||
|
// Die Sound
|
||||||
|
const dieSound = new Audio("/sounds/die.mp3");
|
||||||
|
|
||||||
|
// Button
|
||||||
|
class Button {
|
||||||
|
constructor() {
|
||||||
|
this.startx = 0;
|
||||||
|
this.starty = 0;
|
||||||
|
this.x = 400;
|
||||||
|
this.y = 300;
|
||||||
|
};
|
||||||
|
click(canvas, event) {
|
||||||
|
const rect = canvas.getBoundingClientRect();
|
||||||
|
const x = event.clientX - rect.left;
|
||||||
|
const y = event.clientY - rect.top;
|
||||||
|
if (x > this.startx && x < this.x) {
|
||||||
|
if (y > this.starty && y < this.y) {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fullscreen
|
||||||
|
function openFullscreen ( c ) {
|
||||||
|
if (c.requestFullscreen) {
|
||||||
|
c.requestFullscreen();
|
||||||
|
} else if (c.webkitRequestFullscreen) {
|
||||||
|
c.webkitRequestFullscreen();
|
||||||
|
} else if (c.msRequestFullscreen) {
|
||||||
|
c.msRequestFullscreen();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Canvas
|
||||||
|
const canvas = canvasRef.current;
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
ctx.canvas.width = 1920;
|
||||||
|
ctx.canvas.height = 1080;
|
||||||
|
|
||||||
|
// Draw Images
|
||||||
|
function drawImage( ctx, image, x, y, w, h, degrees ){
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(x+w/2, y+h/2);
|
||||||
|
ctx.rotate(degrees*Math.PI/180.0);
|
||||||
|
ctx.translate(-x-w/2, -y-h/2);
|
||||||
|
ctx.drawImage(image, x, y, w, h);
|
||||||
|
ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
function drawImage2( ctx, image, x, y, w, h, degrees ){
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(x, y + 20);
|
||||||
|
ctx.rotate(degrees*Math.PI/180.0);
|
||||||
|
ctx.translate(-x, -y - 20);
|
||||||
|
ctx.drawImage(image, x, y, w, h);
|
||||||
|
ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
function drawImage3( ctx, image, x, y, w, h, degrees ){
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(x + w, y + 20);
|
||||||
|
ctx.rotate(degrees*Math.PI/180.0);
|
||||||
|
ctx.translate(-x - w, -y - 20);
|
||||||
|
ctx.drawImage(image, x, y, w, h);
|
||||||
|
ctx.restore();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Data
|
||||||
|
const playButton = new Button();
|
||||||
|
let map = [];
|
||||||
|
let player;
|
||||||
|
let players = [];
|
||||||
|
let bullets = [];
|
||||||
|
let scroll = [0, 0]
|
||||||
|
let health = [];
|
||||||
|
let directions = [];
|
||||||
|
let angles = [];
|
||||||
|
let lastClick = [0,0];
|
||||||
|
let shotnum = 1;
|
||||||
|
let jc = 1;
|
||||||
|
let lc = 1;
|
||||||
|
|
||||||
|
// Draw Timeout
|
||||||
|
setInterval(() => {
|
||||||
|
|
||||||
|
// Wipe Screen
|
||||||
|
ctx.fillStyle = "#1c1c1c";
|
||||||
|
ctx.fillRect(0, 0, 1920 , 1080);
|
||||||
|
|
||||||
|
// Scroll
|
||||||
|
let bakc1 = 160 - scroll[0];
|
||||||
|
let bakc2 = 160 - scroll[1];
|
||||||
|
let b1 = scroll[0];
|
||||||
|
let b2 = scroll[1];
|
||||||
|
|
||||||
|
// Backround
|
||||||
|
ctx.drawImage(image_background, bakc1, bakc2);
|
||||||
|
|
||||||
|
// Menu
|
||||||
|
if (menu == true) {
|
||||||
|
ctx.fillStyle = "#FF0000";
|
||||||
|
ctx.fillRect(playButton.startx, playButton.starty, playButton.x, playButton.y);
|
||||||
|
|
||||||
|
// Game
|
||||||
|
} else {
|
||||||
|
// Map
|
||||||
|
for (let i = 0; i < map.length; i++) {
|
||||||
|
ctx.fillStyle = "#FF0000";
|
||||||
|
if (map[i][0] == 1) {
|
||||||
|
ctx.drawImage(image_flat, parseInt(map[i][1] - scroll[0], 10), parseInt(map[i][2] - scroll[1], 10));
|
||||||
|
} else if (map[i][0] == 2) {
|
||||||
|
ctx.drawImage(image_corner, parseInt(map[i][1] - scroll[0], 10), parseInt(map[i][2] - scroll[1], 10));
|
||||||
|
} else if (map[i][0] == 3) {
|
||||||
|
drawImage(ctx, image_flat, parseInt(map[i][1] - scroll[0], 10), parseInt(map[i][2] - scroll[1], 10), 80, 80, 90);
|
||||||
|
} else if (map[i][0] == 4) {
|
||||||
|
drawImage(ctx, image_corner, parseInt(map[i][1] - scroll[0], 10), parseInt(map[i][2] - scroll[1], 10), 80, 80, 90);
|
||||||
|
} else if (map[i][0] == 5) {
|
||||||
|
drawImage(ctx, image_flat, parseInt(map[i][1] - scroll[0], 10), parseInt(map[i][2] - scroll[1], 10), 80, 80, 180);
|
||||||
|
} else if (map[i][0] == 6) {
|
||||||
|
drawImage(ctx, image_corner, parseInt(map[i][1] - scroll[0], 10), parseInt(map[i][2] - scroll[1], 10), 80, 80, 180);
|
||||||
|
}else if (map[i][0] == 7) {
|
||||||
|
drawImage(ctx, image_flat, parseInt(map[i][1] - scroll[0], 10), parseInt(map[i][2] - scroll[1], 10), 80, 80, 270);
|
||||||
|
} else if (map[i][0] == 8) {
|
||||||
|
drawImage(ctx, image_corner, parseInt(map[i][1] - scroll[0], 10), parseInt(map[i][2] - scroll[1], 10), 80, 80, 270);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bullets
|
||||||
|
for (let i = 0; i < bullets.length; i++ ) {
|
||||||
|
ctx.fillStyle = "FF0000";
|
||||||
|
ctx.fillRect(bullets[i][1] - scroll[0], bullets[i][2] - scroll[1], 10, 10);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Players
|
||||||
|
for (let i = 0; i < players.length; i++) {
|
||||||
|
ctx.fillStyle = "00FF00";
|
||||||
|
for (let y = 0; y < directions.length; y++) {
|
||||||
|
if (players[i][0] == directions[y][0]) {
|
||||||
|
if (directions[y][1] < 0) {
|
||||||
|
ctx.drawImage(image_player_left, players[i][1][0] - b1, players[i][1][1] - b2, 80, 80);
|
||||||
|
for (let an = 0; an < angles.length; an ++) {
|
||||||
|
if (angles[an][0] == players[i][0]) {
|
||||||
|
drawImage3(ctx, image_gun_left, players[i][1][0] - b1 - 45, players[i][1][1] - b2 + 28, 80, 32, 180 + angles[an][1]);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
ctx.drawImage(image_player_right, players[i][1][0] - b1, players[i][1][1] - b2, 80, 80);
|
||||||
|
for (let an = 0; an < angles.length; an ++) {
|
||||||
|
if (angles[an][0] == players[i][0]) {
|
||||||
|
drawImage2(ctx, image_gun_right, players[i][1][0] - b1 + 35, players[i][1][1] - b2 + 28, 80, 32, angles[an][1]);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// Scroll
|
||||||
|
if (players[i] != 0) {
|
||||||
|
if (players[i][0] == player) {
|
||||||
|
scroll[0] += (players[i][1][0] - scroll[0] - 900)/20;
|
||||||
|
scroll[1] += (players[i][1][1] - scroll[1] - 500)/20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Health
|
||||||
|
for (let x = 0; x < health.length; x ++) {
|
||||||
|
if (players[i][0] == health[x][0]) {
|
||||||
|
ctx.fillStyle = "FF0000";
|
||||||
|
ctx.fillRect(players[i][1][0] - b1, players[i][1][1] - b2 - 40, 80, 10);
|
||||||
|
ctx.fillStyle = "00FF00";
|
||||||
|
ctx.fillRect(players[i][1][0] - b1, players[i][1][1] - b2 - 40, health[x][1] * 10, 10);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Light
|
||||||
|
ctx.drawImage(image_background_light, bakc1, bakc2)
|
||||||
|
|
||||||
|
// Mouse Move
|
||||||
|
if (socket != null) {
|
||||||
|
let px, py;
|
||||||
|
for (let i = 0; i < players.length; i++) {
|
||||||
|
if (players[i][0] == player) {
|
||||||
|
px = players[i][1][0] + 40 - scroll[0];
|
||||||
|
py = players[i][1][1] + 40 - scroll[1];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
let fx = lastClick[0] - px;
|
||||||
|
let fy = lastClick[1] - py;
|
||||||
|
let angle = Math.atan(fy/fx);
|
||||||
|
let deg = (angle * 180) / Math.PI;
|
||||||
|
if (lastClick[0] < px) deg += 180;
|
||||||
|
if (deg == null || deg == undefined) deg = 0;
|
||||||
|
socket.emit("mmove", {
|
||||||
|
angle: deg
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}, 20);
|
||||||
|
|
||||||
|
// Inputs
|
||||||
|
let inputs = [false, false, false, false, [false, 0, 0]];
|
||||||
|
|
||||||
|
// Click
|
||||||
|
function clickLocation( canvas, evt ) {
|
||||||
|
var rect = canvas.getBoundingClientRect();
|
||||||
|
let scaleX = canvas.width / rect.width;
|
||||||
|
let scaleY = canvas.height / rect.height;
|
||||||
|
return {
|
||||||
|
x: (evt.clientX - rect.left) * scaleX,
|
||||||
|
y: (evt.clientY - rect.top) * scaleY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clicks
|
||||||
|
canvas.addEventListener("mousedown", (event) => {
|
||||||
|
openFullscreen(canvas)
|
||||||
|
// No
|
||||||
|
if (socket == null) {
|
||||||
|
if (playButton.click(canvas, event)) {
|
||||||
|
shotSound1.load()
|
||||||
|
shotSound2.load()
|
||||||
|
shotSound3.load()
|
||||||
|
shotSound4.load()
|
||||||
|
shotSound5.load()
|
||||||
|
shotSound6.load()
|
||||||
|
shotSound7.load()
|
||||||
|
shotSound8.load()
|
||||||
|
shotSound9.load()
|
||||||
|
shotSound10.load()
|
||||||
|
shotSound11.load()
|
||||||
|
shotSound12.load()
|
||||||
|
shotSound13.load()
|
||||||
|
shotSound14.load()
|
||||||
|
shotSound15.load()
|
||||||
|
shotSound16.load()
|
||||||
|
jumpSound1.load()
|
||||||
|
jumpSound2.load()
|
||||||
|
jumpSound3.load()
|
||||||
|
jumpSound4.load()
|
||||||
|
landSound1.load()
|
||||||
|
landSound2.load()
|
||||||
|
landSound3.load()
|
||||||
|
landSound4.load()
|
||||||
|
landSound5.load()
|
||||||
|
landSound6.load()
|
||||||
|
landSound7.load()
|
||||||
|
landSound8.load()
|
||||||
|
dieSound.load()
|
||||||
|
|
||||||
|
// Fetch Ip
|
||||||
|
fetch("http://localhost:3000/api/serverIp").then(res => {return res.json()}).then(data => {
|
||||||
|
|
||||||
|
// Game Server
|
||||||
|
socket = io( "http://localhost" + ":5000/")
|
||||||
|
menu = false;
|
||||||
|
|
||||||
|
// Mouse Move
|
||||||
|
canvas.addEventListener("mousemove", e => {
|
||||||
|
let { x,y } = clickLocation(canvas, e);
|
||||||
|
lastClick = [x,y];
|
||||||
|
let px, py;
|
||||||
|
for (let i = 0; i < players.length; i++) {
|
||||||
|
if (players[i][0] == player) {
|
||||||
|
px = players[i][1][0] + 40 - scroll[0]
|
||||||
|
py = players[i][1][1] + 40 - scroll[1]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
let fx = x - px;
|
||||||
|
let fy = y - py;
|
||||||
|
let angle = Math.atan(fy/fx);
|
||||||
|
let deg = (angle * 180) / Math.PI;
|
||||||
|
if (x < px) deg += 180;
|
||||||
|
if (deg == null || deg == undefined) deg = 0;
|
||||||
|
socket.emit("mmove", {
|
||||||
|
angle: deg
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Connect
|
||||||
|
socket.on("connect", () => {
|
||||||
|
socket.emit("authentication", document.cookie);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Map
|
||||||
|
socket.on("map", (dat) => {
|
||||||
|
map = dat;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Users
|
||||||
|
socket.on("users", (dat) => {
|
||||||
|
console.log("rec")
|
||||||
|
players = dat;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Player
|
||||||
|
socket.on("player", (dat) => {
|
||||||
|
player = dat;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bullets
|
||||||
|
socket.on("bullets", (dat) => {
|
||||||
|
bullets = dat;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Health
|
||||||
|
socket.on("health", (data) => {
|
||||||
|
health = data;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Directions
|
||||||
|
socket.on("directions", (data) => {
|
||||||
|
directions = data;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Disc
|
||||||
|
socket.on("disc", () => {
|
||||||
|
window.location.reload();
|
||||||
|
})
|
||||||
|
|
||||||
|
// Ang
|
||||||
|
socket.on("ang", (data) => {
|
||||||
|
angles = data;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Die
|
||||||
|
socket.on("die", () => {
|
||||||
|
dieSound.volume = 0.5;
|
||||||
|
dieSound.play();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ju
|
||||||
|
socket.on("ju", () => {
|
||||||
|
// Jump Sound
|
||||||
|
jumpSound1.volume = 0.025;
|
||||||
|
jumpSound2.volume = 0.025;
|
||||||
|
jumpSound3.volume = 0.025;
|
||||||
|
jumpSound4.volume = 0.025;
|
||||||
|
if (jc == 5) jc = 1;
|
||||||
|
if (jc == 1) jumpSound1.play();
|
||||||
|
if (jc == 2) jumpSound2.play();
|
||||||
|
if (jc == 3) jumpSound3.play();
|
||||||
|
if (jc == 4) jumpSound4.play();
|
||||||
|
jc += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
// La
|
||||||
|
socket.on("la", () => {
|
||||||
|
// Volume
|
||||||
|
landSound1.volume = 0.2
|
||||||
|
landSound2.volume = 0.2
|
||||||
|
landSound3.volume = 0.2
|
||||||
|
landSound4.volume = 0.2
|
||||||
|
landSound5.volume = 0.2
|
||||||
|
landSound6.volume = 0.2
|
||||||
|
landSound7.volume = 0.2
|
||||||
|
landSound8.volume = 0.2
|
||||||
|
if (lc == 1) landSound1.play();
|
||||||
|
if (lc == 2) landSound2.play();
|
||||||
|
if (lc == 3) landSound3.play();
|
||||||
|
if (lc == 4) landSound4.play();
|
||||||
|
if (lc == 5) landSound5.play();
|
||||||
|
if (lc == 6) landSound6.play();
|
||||||
|
if (lc == 7) landSound7.play();
|
||||||
|
if (lc == 8) landSound8.play();
|
||||||
|
if (lc == 9) lc = 1;
|
||||||
|
lc += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Inputs
|
||||||
|
setInterval(()=>{
|
||||||
|
socket.emit("move", inputs)
|
||||||
|
}, 2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let i = 0; i < players.length; i++) {
|
||||||
|
if (players[i] != 0) {
|
||||||
|
if (players[i][0] == player) {
|
||||||
|
let { x, y } = clickLocation(canvas, event);
|
||||||
|
let playerX = players[i][1][0] + 40 - scroll[0];
|
||||||
|
let playerY = players[i][1][1] + 40 - scroll[1];
|
||||||
|
// Shot Sounds
|
||||||
|
if (shotnum == 17) shotnum = 1;
|
||||||
|
if (shotnum == 1) shotSound1.play();
|
||||||
|
if (shotnum == 2) shotSound2.play();
|
||||||
|
if (shotnum == 3) shotSound3.play();
|
||||||
|
if (shotnum == 4) shotSound4.play();
|
||||||
|
if (shotnum == 5) shotSound5.play();
|
||||||
|
if (shotnum == 6) shotSound6.play();
|
||||||
|
if (shotnum == 7) shotSound7.play();
|
||||||
|
if (shotnum == 8) shotSound8.play();
|
||||||
|
if (shotnum == 9) shotSound9.play();
|
||||||
|
if (shotnum == 10) shotSound10.play();
|
||||||
|
if (shotnum == 11) shotSound11.play();
|
||||||
|
if (shotnum == 12) shotSound12.play();
|
||||||
|
if (shotnum == 13) shotSound13.play();
|
||||||
|
if (shotnum == 14) shotSound14.play();
|
||||||
|
if (shotnum == 15) shotSound15.play();
|
||||||
|
if (shotnum == 16) shotSound16.play();
|
||||||
|
shotnum += 1;
|
||||||
|
// Click
|
||||||
|
socket.emit("click", {
|
||||||
|
clickX: x,
|
||||||
|
clickY: y,
|
||||||
|
dx: x - playerX,
|
||||||
|
dy: y - playerY,
|
||||||
|
px: players[i][1][0] + 35,
|
||||||
|
py: players[i][1][1] + 35
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Keyboard
|
||||||
|
document.addEventListener("keydown", e => {
|
||||||
|
if (socket != null) {
|
||||||
|
if (e.key == "w") {
|
||||||
|
inputs[0] = true;
|
||||||
|
};
|
||||||
|
if (e.key == "a") {
|
||||||
|
inputs[1] = true;
|
||||||
|
};
|
||||||
|
if (e.key == "s") {
|
||||||
|
inputs[2] = true;
|
||||||
|
};
|
||||||
|
if (e.key == "d") {
|
||||||
|
inputs[3] = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
document.addEventListener("keyup", e => {
|
||||||
|
if (socket != null) {
|
||||||
|
if (e.key == "w") {
|
||||||
|
inputs[0] = false;
|
||||||
|
};
|
||||||
|
if (e.key == "a") {
|
||||||
|
inputs[1] = false;
|
||||||
|
};
|
||||||
|
if (e.key == "s") {
|
||||||
|
inputs[2] = false;
|
||||||
|
};
|
||||||
|
if (e.key == "d") {
|
||||||
|
inputs[3] = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Page
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Header/>
|
||||||
|
<Title title = "Play"/>
|
||||||
|
<div className = { styles.play }>
|
||||||
|
<canvas id="myCanvas" width="1920" height="1080" ref = {canvasRef}></canvas>
|
||||||
|
</div>
|
||||||
|
<Footer/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 5.3 KiB |
After Width: | Height: | Size: 5.3 KiB |
@ -0,0 +1,13 @@
|
|||||||
|
/* Error404 */
|
||||||
|
.error404 {
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Error404 H2 */
|
||||||
|
.error404 h2 {
|
||||||
|
text-align: center;
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 40vw;
|
||||||
|
color: #8c00ff;
|
||||||
|
text-shadow: 0 0 4vw #8c00ff, 0 0 6vw #8c00ff;
|
||||||
|
}
|
@ -0,0 +1,117 @@
|
|||||||
|
/* Account */
|
||||||
|
.account {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Account Div */
|
||||||
|
.account div {
|
||||||
|
width: 30%;
|
||||||
|
padding: 50px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Account Div H2 */
|
||||||
|
.account div h2 {
|
||||||
|
padding: 40px;
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 25px;
|
||||||
|
color: #8c00ff;
|
||||||
|
text-shadow: 0 0 10px #8c00ff, 0 0 20px #8c00ff, 0 0 30px #8c00ff, 0 0 40px #8c00ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Account Div H3 */
|
||||||
|
.account div h3 {
|
||||||
|
padding: 10px;
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 20px;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
color: #f700ff;
|
||||||
|
text-shadow: 0 0 10px #f700ff, 0 0 20px #f700ff, 0 0 30px #f700ff, 0 0 40px #f700ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Account Div Form */
|
||||||
|
.account div form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Account Div Form Input */
|
||||||
|
.account div form input {
|
||||||
|
padding: 15px;
|
||||||
|
margin: 15px;
|
||||||
|
border: 1px solid #f700ff;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 20px;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
color: #f700ff;
|
||||||
|
text-shadow: 0 0 10px #f700ff, 0 0 20px #f700ff, 0 0 30px #f700ff, 0 0 40px #f700ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Account Div Form Input Placeholder */
|
||||||
|
.account div form input::placeholder {
|
||||||
|
font-family: NeonSans;
|
||||||
|
color: #f700ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Account Div Form Button */
|
||||||
|
.account div form button {
|
||||||
|
padding: 15px;
|
||||||
|
margin: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid #ff9d00;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 20px;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
color: #ff9d00;
|
||||||
|
text-shadow: 0 0 10px #ff9d00, 0 0 20px #ff9d00, 0 0 30px #ff9d00, 0 0 40px #ff9d00;
|
||||||
|
transition: text-shadow 0.2s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Account Div Form Button Hover */
|
||||||
|
.account div form button:hover {
|
||||||
|
text-shadow: 0 0 10px #ff9d00, 0 0 20px #ff9d00;
|
||||||
|
transition: text-shadow 0.2s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Account Form Button */
|
||||||
|
.account form button {
|
||||||
|
padding: 15px;
|
||||||
|
margin: 15px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid #ff9d00;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 20px;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
color: #ff9d00;
|
||||||
|
text-shadow: 0 0 10px #ff9d00, 0 0 20px #ff9d00, 0 0 30px #ff9d00, 0 0 40px #ff9d00;
|
||||||
|
transition: text-shadow 0.2s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Account Form Button Hover */
|
||||||
|
.account form button:hover {
|
||||||
|
text-shadow: 0 0 10px #ff9d00, 0 0 20px #ff9d00;
|
||||||
|
transition: text-shadow 0.2s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small Screens */
|
||||||
|
@media screen and (max-width: 1000px) {
|
||||||
|
/* Account */
|
||||||
|
.account {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
/* Account Div */
|
||||||
|
.account div {
|
||||||
|
width: 80%;
|
||||||
|
padding-top: 20px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
/* NeonSans Font Face */
|
||||||
|
@font-face {
|
||||||
|
font-family: NeonSans;
|
||||||
|
src: url(../public/fonts/NeonSans.ttf);
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/* Index */
|
||||||
|
.index {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Index H2 */
|
||||||
|
.index h2 {
|
||||||
|
width: 80%;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 25px;
|
||||||
|
color: #8c00ff;
|
||||||
|
text-shadow: 0 0 10px #8c00ff, 0 0 20px #8c00ff, 0 0 30px #8c00ff, 0 0 40px #8c00ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Index H3 */
|
||||||
|
.index h3 {
|
||||||
|
width: 80%;
|
||||||
|
padding: 20px;
|
||||||
|
padding-bottom: 40px;
|
||||||
|
text-align: center;
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #f700ff;
|
||||||
|
text-shadow: 0 0 10px #f700ff, 0 0 20px #f700ff, 0 0 30px #f700ff, 0 0 40px #f700ff;
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
/* Leaderboards */
|
||||||
|
.leaderboards {
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leaderboards Div First Child */
|
||||||
|
.leaderboards div:first-child {
|
||||||
|
padding: 10px 40px;
|
||||||
|
padding-top: 40px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leaderboards Div First Child Table */
|
||||||
|
.leaderboards div:first-child table {
|
||||||
|
border-spacing: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leaderboards Div First Child Table First Child */
|
||||||
|
.leaderboards div:first-child table:first-child {
|
||||||
|
width: 65%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leaderboards Div First Child Table Last Child */
|
||||||
|
.leaderboards div:first-child table:last-child {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leaderboards Div First Child Table Tr */
|
||||||
|
.leaderboards div:first-child table tr {
|
||||||
|
font-family: NeonSans;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leaderboards Div First Child Table Tr Th */
|
||||||
|
.leaderboards div:first-child table tr th {
|
||||||
|
text-align: start;
|
||||||
|
font-size: 25px;
|
||||||
|
color: #8c00ff;
|
||||||
|
text-shadow: 0 0 10px #8c00ff, 0 0 20px #8c00ff, 0 0 30px #8c00ff, 0 0 40px #8c00ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leaderboards Div First Child Table Tr Td */
|
||||||
|
.leaderboards div:first-child table tr td {
|
||||||
|
font-size: 20px;
|
||||||
|
color: #f700ff;
|
||||||
|
text-shadow: 0 0 10px #f700ff, 0 0 20px #f700ff, 0 0 30px #f700ff, 0 0 40px #f700ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leaderboards Div Last Child */
|
||||||
|
.leaderboards div:last-child {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leaderboards Div Last Child A */
|
||||||
|
.leaderboards div:last-child a {
|
||||||
|
width: 160px;
|
||||||
|
padding: 30px;
|
||||||
|
padding-bottom: 40px;
|
||||||
|
font-family: NeonSans;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #ff9d00;
|
||||||
|
text-shadow: 0 0 10px #ff9d00, 0 0 20px #ff9d00, 0 0 30px #ff9d00, 0 0 40px #ff9d00;
|
||||||
|
transition: text-shadow 0.2s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Leaderboards Div Last Child A Hover */
|
||||||
|
.leaderboards div:last-child a:hover {
|
||||||
|
text-shadow: 0 0 10px #ff9d00, 0 0 20px #ff9d00;
|
||||||
|
transition: text-shadow 0.2s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small Screens */
|
||||||
|
@media screen and (max-width: 1111px) {
|
||||||
|
/* Leaderboards Div First Child */
|
||||||
|
.leaderboards div:first-child {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
/* Leaderboards Div First Child Table First Child */
|
||||||
|
.leaderboards div:first-child table:first-child {
|
||||||
|
padding-top: 50px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
/* Leaderboards Div First Child Table Last Child */
|
||||||
|
.leaderboards div:first-child table:last-child {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
/* Play Canvas */
|
||||||
|
.play canvas {
|
||||||
|
width: 100vw;
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
/* Body */
|
||||||
|
body {
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All Elements */
|
||||||
|
* {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|