Compare commits
15 Commits
903ac37639
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
4d32ff6f5a
|
|||
| dee653ca31 | |||
| 32aa61533c | |||
| 214edfbe3a | |||
| 1b84249f47 | |||
| 89241c2939 | |||
| 77406db737 | |||
| f324848c19 | |||
| 48bd8126a5 | |||
| 1cbf9ef2af | |||
| bf3392236a | |||
| 70e0bce024 | |||
| e8d160da51 | |||
| ba7eb78048 | |||
| d7666a6100 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -174,3 +174,6 @@ cython_debug/
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
# ---> Other
|
||||
/test.py
|
||||
/.vscode/
|
||||
130
__main__.py
Normal file
130
__main__.py
Normal file
@ -0,0 +1,130 @@
|
||||
import importlib.util
|
||||
import argparse
|
||||
import logging
|
||||
import tomllib
|
||||
import pygame
|
||||
import attr
|
||||
import sys
|
||||
import os
|
||||
|
||||
# TODO: Add Discord rich presence
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
log = logging.getLogger('PainJamLauncher')
|
||||
|
||||
# Store the current working directory
|
||||
# This is used to revert the cd change
|
||||
originalCWD = os.getcwd()
|
||||
|
||||
# Parse command line arguments
|
||||
parser = argparse.ArgumentParser(prog='Pain Jam launcher')
|
||||
parser.add_argument('-sw', '--width', type=int, default=1280)
|
||||
parser.add_argument('-sh', '--height', type=int, default=720)
|
||||
parser.add_argument('-fps', '--fpsCap', type=int, default=60)
|
||||
parser.add_argument('-f', '--fullscreen', action='store_true')
|
||||
parser.add_argument('gameID', nargs='?', type=str, default=None)
|
||||
args = parser.parse_args()
|
||||
|
||||
@attr.s
|
||||
class Game:
|
||||
id: str = attr.ib()
|
||||
name: str = attr.ib()
|
||||
description: str = attr.ib()
|
||||
path: str = attr.ib()
|
||||
|
||||
games = {}
|
||||
|
||||
# Scan for games
|
||||
for path in os.listdir('../'):
|
||||
gamePath = os.path.join('../', path)
|
||||
# Skip anything that isn't a directory
|
||||
if not os.path.isdir(gamePath): continue
|
||||
# Get the games toml path
|
||||
tomlPath = os.path.join(gamePath, 'game.toml')
|
||||
# Skip all directories that don't have a game.toml file
|
||||
if not os.path.isfile(tomlPath): continue
|
||||
|
||||
with open(tomlPath, 'r') as f:
|
||||
toml = tomllib.loads(f.read())
|
||||
|
||||
gameID = toml['id']
|
||||
game = Game(gameID, toml['name'], toml['description'], gamePath)
|
||||
games.update({gameID: game})
|
||||
|
||||
log.debug(f'Loaded game {gameID}')
|
||||
|
||||
pygame.init()
|
||||
|
||||
# I'm sorry, I prefer object-oriented programming. So sue me.
|
||||
class Launcher:
|
||||
def __init__(self):
|
||||
# The primary display.
|
||||
self.screen = pygame.display.set_mode((args.width, args.height))
|
||||
# The surface that the games render to.
|
||||
self.gameSurface = pygame.Surface(self.screen.size)
|
||||
# The current Game object. None means no game is running
|
||||
self.currentGame = None
|
||||
self.clock = pygame.time.Clock()
|
||||
# Is the launcher running (including if a game is running).
|
||||
self.running = True
|
||||
|
||||
pygame.display.set_caption('Pain Jam Launcher')
|
||||
|
||||
def loadGame(self, game):
|
||||
# Set the current working directory
|
||||
# to the base path of the game.
|
||||
os.chdir(game.path)
|
||||
# Load the games game.py file.
|
||||
spec = importlib.util.spec_from_file_location(game.id, os.path.join(game.path, 'game.py'))
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
# Initialise the games Game class, then set the
|
||||
# current game to that.
|
||||
self.currentGame = module.Game(self.gameSurface)
|
||||
# Set the window title to the games name
|
||||
pygame.display.set_caption(game.name)
|
||||
|
||||
def update(self):
|
||||
for event in pygame.event.get():
|
||||
if self.gameRunning:
|
||||
self.currentGame._onEvent(event)
|
||||
|
||||
# CTRL+ESC
|
||||
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE and event.mod == 64):
|
||||
# Close the game.
|
||||
# TODO: Fade out game?
|
||||
self.currentGame.close()
|
||||
self.currentGame = None
|
||||
os.chdir(originalCWD)
|
||||
pygame.display.set_caption('Pain Jam Launcher')
|
||||
# If we launched directly into a game
|
||||
if args.gameID is not None:
|
||||
# Exit the launcher when we exit the game
|
||||
self.running = False
|
||||
else:
|
||||
if event.type == pygame.QUIT:
|
||||
# Exit the launcher.
|
||||
self.running = False
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_1:
|
||||
self.loadGame(games['russianRoulette'])
|
||||
|
||||
if self.gameRunning:
|
||||
self.currentGame._update()
|
||||
self.screen.blit(self.currentGame._surf, (0, 0))
|
||||
else:
|
||||
self.screen.fill((0, 0, 0))
|
||||
|
||||
pygame.display.update()
|
||||
|
||||
self.clock.tick(args.fpsCap)
|
||||
|
||||
@property
|
||||
def gameRunning(self):
|
||||
return self.currentGame is not None
|
||||
|
||||
launcher = Launcher()
|
||||
if args.gameID is not None:
|
||||
launcher.loadGame(games[args.gameID])
|
||||
while launcher.running:
|
||||
launcher.update()
|
||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@ -0,0 +1,3 @@
|
||||
pygame-ce
|
||||
pishock
|
||||
attrs
|
||||
77
setup.py
Normal file
77
setup.py
Normal file
@ -0,0 +1,77 @@
|
||||
"""
|
||||
Initalises the launchers virtual environment,
|
||||
and installs all dependancies.
|
||||
"""
|
||||
|
||||
import subprocess as sp
|
||||
import platform
|
||||
import shutil
|
||||
import sys
|
||||
import os
|
||||
|
||||
def getVenvExec():
|
||||
"""
|
||||
Gets the path of the virtual environment
|
||||
based on the current opperating system.
|
||||
"""
|
||||
plat = platform.system()
|
||||
if plat == 'Linux':
|
||||
return f'./.venv/bin/python3'
|
||||
elif plat == 'Windows':
|
||||
return f'./.venv/Scripts/python.exe'
|
||||
else:
|
||||
print(f'WARNING: Playform type "{plat}" is not recognised. Exiting...')
|
||||
exit(1)
|
||||
|
||||
def inputYN(prompt: str, default=None):
|
||||
"""
|
||||
A simply yes/no prompt.
|
||||
"""
|
||||
while True:
|
||||
i = input(prompt)
|
||||
|
||||
if i.lower() in ['y', 'yes', '1', 'true']: return True
|
||||
elif i.lower() in ['n', 'no', '0', 'false']: return False
|
||||
elif i == '' and default != None: return default
|
||||
|
||||
def installRequirements(requirementsPath: str):
|
||||
"""
|
||||
Installs a requirements.txt file to the current venv.
|
||||
"""
|
||||
print(f'---------- Installing {requirementsPath} ----------')
|
||||
sp.run([getVenvExec(), '-m', 'pip', 'install', '-r', requirementsPath])
|
||||
|
||||
# Check for a pre-existing venv
|
||||
if os.path.isdir('./.venv/'):
|
||||
# If one exists, ask the user if they want to delete it
|
||||
replace = inputYN(f'Virtual environment already exists, would you like to replace it? (y/n) > ')
|
||||
if replace:
|
||||
# If so, remove the .venv directory
|
||||
print(f'---------- Removing old virtual environment ----------')
|
||||
shutil.rmtree('./.venv/')
|
||||
|
||||
# Initailise a venv, creating one if it doesn't exist
|
||||
print(f'---------- Initalising virtual environment ----------')
|
||||
sp.run([sys.executable, '-m', 'venv', './.venv/'])
|
||||
|
||||
# Upgrade pip
|
||||
print(f'---------- Upgrading pip ----------')
|
||||
sp.run([getVenvExec(), '-m', 'pip', 'install', '-U', 'pip'])
|
||||
|
||||
# Install all requirements.txt files
|
||||
for path in os.listdir('../'):
|
||||
requirementsPath = os.path.join('../', path, 'requirements.txt')
|
||||
if not os.path.isfile(requirementsPath):
|
||||
print(f'{path} does not have a requirements.txt, skipping...')
|
||||
continue
|
||||
|
||||
installRequirements(requirementsPath)
|
||||
|
||||
if os.path.isfile('../players.json'):
|
||||
newPlayerJSON = inputYN(f'player.json already exists, would you like to overwrite it? (y/n) > ')
|
||||
else:
|
||||
newPlayerJSON = True
|
||||
|
||||
if newPlayerJSON:
|
||||
print(f'---------- Copying example players.json ----------')
|
||||
shutil.copyfile('../NoPELib/players.json', '../players.json')
|
||||
Reference in New Issue
Block a user