diff --git a/exts/imports/guid.py b/exts/imports/guid.py index 6ae2136..bf6ecd0 100644 --- a/exts/imports/guid.py +++ b/exts/imports/guid.py @@ -1,13 +1,43 @@ +""" +Implementation of C# System.Guid + +References: + https://referencesource.microsoft.com/#mscorlib/system/guid.cs + + # TODO Add License +""" + from struct import Struct, pack from math import log -# 16 bytes, 11 arguments +# Constants for masking bytes MAXINT64 = 0xFFFFFFFFFFFFFFFF +MAXINT16 = 0xFFFF MAXINT8 = 0xFF class Guid: + """ + A Global Unique Identifier (Guid) based on the one provided in C#'s System package + + The Guid is stored as a tuple of length 11 for easy processing and comparisons + + Attributes: + guid (tuple): A tuple containing the guid + """ def __init__(self, *args): + """ + Initialize the Guid + + Arguments: + Union[int, str, bytes, short(int will be masked to short)]: + The arguments can be in any of the following formats: + (bytes(len 16)) + (int(len <= 4), short, short, bytes(len 8)) + (int(len <= 8), int(len <= 8)) + (int(len <= 16)) + (str) - str must be formatted 00000000-0000-0000-0000-000000000000 + """ # Guid will be stored as a tuple len 11 if bool(args): self.get_guid(args) @@ -24,13 +54,9 @@ class Guid: *b[8:16] ) self.guid = s.unpack(guid) - elif len(args) == 11 and all(isinstance(arg, int) for arg in args[0:3]) \ - and all(isinstance(arg, bytes) for arg in args[3:]) and all(len(arg) == 1 for arg in args[3:]): - guid = s.pack(*args) - self.guid = s.unpack(guid) elif len(args) == 4 and all(isinstance(arg, int) for arg in args[0:3]) \ and isinstance(args[3], bytes) and len(args[3]) == 8: - guid = s.pack(args[0], args[1], args[2], *args[3]) + guid = s.pack(args[0], args[1] & MAXINT16, args[2] & MAXINT16, *args[3]) self.guid = s.unpack(guid) elif len(args) == 2 and all(isinstance(arg, int) for arg in args): if all((self.bytes_needed(arg) <= 4) for arg in args): diff --git a/exts/imports/process_files.py b/exts/imports/process_files.py index b59d1ef..04db36c 100644 --- a/exts/imports/process_files.py +++ b/exts/imports/process_files.py @@ -4,6 +4,7 @@ import json from configparser import ConfigParser from .guid import Guid from shutil import rmtree +from hashlib import md5 config_dir = 'config/' bot_config_file = 'bot_config.json' @@ -47,7 +48,9 @@ def rename_section(cfg, sec, sec_new): def get_server_guid(server_file): server_file = server_file.encode() - + m = md5(server_file).hexdigest().encode() + guid = Guid(int(m.hex())) + return guid def process_file(in_file, file_type) -> ConfigParser: @@ -87,9 +90,10 @@ def process_file(in_file, file_type) -> ConfigParser: return config -def process_files(z) -> (ConfigParser, ConfigParser, list): +def process_files(z) -> (ConfigParser, ConfigParser, list, Guid): dino_data = dict() game_config = ConfigParser() + server_guid = Guid() mods = list() path = 'submissions_temp/tmp/' z.extractall(path=path) @@ -144,7 +148,7 @@ def process_files(z) -> (ConfigParser, ConfigParser, list): rmtree('submissions_temp/tmp') if not mods: mods = check_for_modded_dinos(dino_data, mods) - return game_config, dino_data, mods + return game_config, dino_data, mods, server_guid def generate_game_ini(game_config, mods, directory): @@ -164,12 +168,12 @@ def generate_dino_files(dino_data, directory): dino.write(f, space_around_delimiters=False) -def generate_files(storage_dir, ctx, filename, game_ini, dinos_data, mods): +def generate_files(storage_dir, ctx, dirname, game_ini, dinos_data, mods): if not os.path.isdir(f'{storage_dir}/{ctx.author.id}'): os.mkdir(f'{storage_dir}/{ctx.author.id}') - directory = f'{storage_dir}/{ctx.author.id}/{filename.replace(".zip", "")}_' \ - f'{ctx.message.created_at.strftime("%Y%m%dT%H%M%S")}' - os.mkdir(directory) + directory = f'{storage_dir}/{ctx.author.id}/{dirname}' + if not os.path.isdir(directory): + os.mkdir(directory) generate_game_ini(game_ini, mods, directory) generate_dino_files(dinos_data, directory) return 1 diff --git a/exts/uploader.py b/exts/uploader.py index ee853a9..10404b9 100644 --- a/exts/uploader.py +++ b/exts/uploader.py @@ -5,6 +5,7 @@ from io import BytesIO from .imports import process_files, utils from configparser import ConfigParser import os +from .imports.guid import Guid storage_dir = '../ASB_dino_submissions' owner_id = 351794468870946827 @@ -29,7 +30,7 @@ class Uploader: with BytesIO() as file: await attachment.save(file) unzipped = process_files.load_zip(file) - game_ini, dinos_data, mods = process_files.process_files(unzipped) + game_ini, dinos_data, mods, server_guid = process_files.process_files(unzipped) if not game_ini and not dinos_data and not mods: await msg.edit(content='There was an encoding error with one of the files provided ' 'and they cannot be processed') @@ -72,6 +73,7 @@ class Uploader: await msg.edit(content="You chose to process as official.") await asyncio.sleep(4.0) official = 'official' + server_guid = Guid(b'officialserver00') elif str(reaction.emoji) == self.bot.unicode_emojis["y"]: await msg.edit(content="You chose to provide the Game.ini file.\n" "I will wait for 5 minutes for you to send a message " @@ -98,6 +100,8 @@ class Uploader: with BytesIO() as f: game_msg.attachments[0].save(f) game_ini = process_files.process_file(f, 'game.ini') + f.seek(0) + server_guid = process_files.get_server_guid(f.read()) elif str(reaction.emoji) == self.bot.unicode_emojis['x']: await msg.edit(content='Your request has been canceled.') return @@ -133,10 +137,12 @@ class Uploader: await msg.edit(content="You selected SinglePlayer.") await asyncio.sleep(4.0) singleplayer = True + server_guid = Guid(b'officialsinglepl') elif str(reaction.emoji) == self.bot.unicode_emojis["x"]: await msg.edit(content="You selected Server.") await asyncio.sleep(4.0) singleplayer = False + server_guid = Guid(b'officialserver00') if singleplayer: game_ini.add_section('/script/shootergame.shootergamemode') @@ -154,7 +160,7 @@ class Uploader: pull_status = await utils.git_pull(self.bot.loop, storage_dir) if pull_status == 'Completed': await msg.edit(content='Processing... Sync complete... Generating new files') - process_files.generate_files(storage_dir, ctx, attachment.filename, + process_files.generate_files(storage_dir, ctx, server_guid, game_ini, dinos_data, mods) await msg.edit(content='Processing... Files generated... Committing changes') await utils.git_add(self.bot.loop, storage_dir, '*') @@ -180,7 +186,7 @@ class Uploader: else: await self.bot.get_user(owner_id).send(f'There was an error with git pull\n' f'{pull_status}') - process_files.generate_files('submissions_temp', ctx, attachment.filename, + process_files.generate_files('submissions_temp', ctx, server_guid, game_ini, dinos_data, mods) await msg.edit(content='Could not sync with GitHub.\n' 'Dusty.P has been notified and your files are stored in a '