Skip to content

Commit

Permalink
Merge pull request #112 from IUrreta/main
Browse files Browse the repository at this point in the history
Update 1.6
  • Loading branch information
IUrreta authored Sep 28, 2023
2 parents 162c9ea + ef70880 commit 3536f04
Show file tree
Hide file tree
Showing 19 changed files with 2,466 additions and 315 deletions.
32 changes: 18 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# Database Editor for F1 Manager 23 #
Friendly to use tool for editing your save files from F1 Manager 23. Supports driver transfers, calendar customization, staff stat editing and car eprfromance editing, but the tool is still in constant development!

**PLEASE KEEP IN MIND**: This are the first few iterations and will only get better with time. It will get regular updates to support more functionallity.
Friendly to use tool for editing your save files from F1 Manager 23. Supports driver transfers, calendar customization, staff stat editing and car eprfromance editing, and from 1.6 onwards data visualization! (An area in which the game fails miserably)

If you have any issues, I recommend first look at the Troubleshoot guide for the most common error: https://github.com/IUrreta/DatabaseEditor/wiki/Troubleshoot-guide. If this doesn't fix the error, you can open an Issue on GitHub

Expand All @@ -12,14 +10,17 @@ It's developed by the same guy (me, u/ignaciourreta on Reddit) who developed mul

When I developed those scripts, more specifically the driver transfers script for the Script Manager for F1M22 I always had in mind to devlop a tool like this to make it easier to the user to take advantage of my scripts

### What can I actually edit with the Database Editor? ###
### What can I actually do with the Database Editor? ###

1. Driver transfers
2. Editing driver contracts
3. Editing all staff (including drivers') stats
4. Customize your calendar (run **ONLY** before the first race of the season)
5. Buff or nerf any car part of any car
6. Edit the performance and durability of any of the 4 engines suppliers
3. Edit driver numbers
4. Editing all staff (including drivers') stats
5. Customize your calendar (can **ONLY BE DONE** before the first race of the season)
6. Buff or nerf any car part of any car
7. Edit the performance and durability of any of the 4 engines suppliers
8. Keep track of past seasons with a wikipedia-style table
9. Compare drivers and their stats from their past seasons

## How can I install the Database Editor? ##
You'll need to downlaod two things: [NodeJS](https://nodejs.org/en/download) and [Python](https://www.python.org/downloads/)
Expand All @@ -37,18 +38,21 @@ You can try to look at them at the [Troubleshoot Guide](https://github.com/IUrre

### Screenshots ###

![image](https://github.com/IUrreta/DatabaseEditor/assets/95303008/8ca241d1-16da-4a7b-a28a-912b50e9b61b)
![image](https://github.com/IUrreta/DatabaseEditor/assets/95303008/f8eb8172-5b27-41d6-b68f-15c63837948c)

![image](https://github.com/IUrreta/DatabaseEditor/assets/95303008/804f32c4-fcde-4d8f-86b9-50e14660af9a)

![image](https://github.com/IUrreta/DatabaseEditor/assets/95303008/66706691-1627-4a14-9f3f-5403e09e8d86)

![image](https://github.com/IUrreta/DatabaseEditor/assets/95303008/fc5a404d-b75e-4981-8e18-d6834dd6fc97)
![image](https://github.com/IUrreta/DatabaseEditor/assets/95303008/d413ffdd-f696-45b8-8516-133e45c7935f)

![image](https://github.com/IUrreta/DatabaseEditor/assets/95303008/3d35612c-1993-456f-a5b5-78464ee5137f)
![image](https://github.com/IUrreta/DatabaseEditor/assets/95303008/b681f63e-b740-4a3b-a047-2aa77a4e2a83)

![image](https://github.com/IUrreta/DatabaseEditor/assets/95303008/44f7820a-01be-4297-a0f8-2aecf59ed600)

![image](https://github.com/IUrreta/DatabaseEditor/assets/95303008/e072756c-4d78-471e-84db-7d79fe0af4cc)


### Special thanks ###
xAranaktu for the save repacker: https://github.com/xAranaktu/F1-Manager-2022-SaveFile-Repacker

Rolfeee for his design contribution: https://www.racedepartment.com/members/rolfeee.1369146/

F1 Manager Mods discord for the help during testing
Binary file added assets/images/Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/logo2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
169 changes: 164 additions & 5 deletions back/back.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from scripts.custom_calendar_23 import run_script as run_editCalendar
from scripts.car_performance_23 import run_script as run_editPerformance
from scripts.engine_performance_23 import run_script as run_editEngine
from scripts.head2head_23 import fetch_Head2Head as fetch_Head2Head

client = None
path = None
Expand Down Expand Up @@ -62,6 +63,11 @@ async def handle_command(message):
data_json_calendar = json.dumps(allowCalendar)
await send_message_to_client(data_json_calendar)
create_backup(path, save)
year = cursor.execute("SELECT CurrentSeason FROM Player_State").fetchone()[0]
year = ["Year fetched", year]
data_json_year = json.dumps(year)
await send_message_to_client(data_json_year)



elif type =="hire":
Expand Down Expand Up @@ -121,16 +127,21 @@ async def handle_command(message):
elif type=="requestDriver":
contractDetails = fetch_driverContract(message["driverID"])
contractMsg = [contractDetails]
contractMsg.append(fetchDriverNumberDetails(message["driverID"]))
contractMsg.insert(0, "Contract fetched")
data_json_contract = json.dumps(contractMsg)
await send_message_to_client(data_json_contract)
nums = fetch_driverNumebrs()
nums.insert(0, "Numbers fetched")
data_json_numbers = json.dumps(nums)
await send_message_to_client(data_json_numbers)

elif type=="editContract":
argument = "editContract " + message["salary"] + " " + message["year"] + " " + message["signBonus"] + " " + message["raceBonus"] + " " + message["raceBonusPos"] + " " + str(message["driverID"])
argument = "editContract " + message["salary"] + " " + message["year"] + " " + message["signBonus"] + " " + message["raceBonus"] + " " + message["raceBonusPos"] + " " + str(message["driverID"] + " " + str(message["driverNumber"] + " " + str(message["wantsN1"])))
run_trasnsfer(argument)
process_repack("../result", path)
info = []
info.insert(0, "Succesfully edited " + message["driver"] + "'s contract")
info.insert(0, "Succesfully edited " + message["driver"] + "'s details")
info_json = json.dumps(info)
await send_message_to_client(info_json)

Expand All @@ -153,6 +164,33 @@ async def handle_command(message):
info_json = json.dumps(info)
await send_message_to_client(info_json)

elif type=="yearSelected":
results = fetch_seasonResults(message["year"])
results.insert(0, fetch_events_from(message["year"]))
results.insert(0, "Results fetched")
data_json_results = json.dumps(results)
#argument = json.dumps(message)
await send_message_to_client(data_json_results)

elif type=="yearSelectedH2H":
drivers = fetch_drivers_per_year(message["year"])
drivers.insert(0, "DriversH2H fetched")
data_json_drivers = json.dumps(drivers)
await send_message_to_client(data_json_drivers)

elif type=="H2HConfigured":
h2hRes = fetch_Head2Head((message["d1"],), (message["d2"],), (message["year"],), cursor)
h2h = ["H2H fetched", h2hRes]
data_json_h2h = json.dumps(h2h)
await send_message_to_client(data_json_h2h)
d1Res = fetch_oneDriver_seasonResults((message["d1"],), (message["year"],))
d2Res = fetch_oneDriver_seasonResults((message["d2"],), (message["year"],))
h2hDrivers = [d1Res, d2Res]
h2hDrivers.insert(0, fetch_events_from(message["year"]))
h2hDrivers.insert(0, "H2HDriver fetched")
data_json_h2hdrivers = json.dumps(h2hDrivers)
await send_message_to_client(data_json_h2hdrivers)


log.write("[" + str(datetime.now()) + "] INFO: Command executed: " + argument + "\n")
log.flush()
Expand Down Expand Up @@ -197,6 +235,20 @@ def create_backup(originalFIle, saveFile):
new_file = backup_path + "/" + saveFile
shutil.copy(originalFIle, new_file)

def fetch_driverNumebrs():
numbers = cursor.execute("SELECT Number FROM Staff_DriverNumbers WHERE CurrentHolder IS NULL").fetchall()
numList = []
for num in numbers:
if num[0] != 1 and num[0] != 0:
numList.append(num[0])
return numList


def fetchDriverNumberDetails(driverID):
num = cursor.execute("SELECT Number FROM Staff_DriverNumbers WHERE CurrentHolder =" + str(driverID)).fetchone()
wants1 = cursor.execute("SELECT WantsChampionDriverNumber FROM Staff_DriverData WHERE StaffID =" + str(driverID)).fetchone()

return[num[0], wants1[0]]

def fetch_engines():
engines_ids = [1,10,4,7]
Expand Down Expand Up @@ -225,11 +277,10 @@ async def main():

def fetch_driverContract(id):
details = cursor.execute("SELECT Salary, EndSeason, StartingBonus, RaceBonus, RaceBonusTargetPos FROM Staff_Contracts WHERE ContractType = 0 AND StaffID = " + str(id)).fetchone()

return details

def fetch_staff():
staff = cursor.execute("SELECT bas.FirstName, bas.LastName, bas.StaffID, con.TeamID, gam.StaffType FROM Staff_GameData gam JOIN Staff_BasicData bas ON gam.StaffID = bas.StaffID LEFT JOIN Staff_Contracts con ON bas.StaffiD = con.StaffID WHERE gam.StaffType != 0 AND (con.ContractType = 0 OR con.ContractType IS NULL)").fetchall()
staff = cursor.execute("SELECT DISTINCT bas.FirstName, bas.LastName, bas.StaffID, con.TeamID, gam.StaffType FROM Staff_GameData gam JOIN Staff_BasicData bas ON gam.StaffID = bas.StaffID LEFT JOIN Staff_Contracts con ON bas.StaffiD = con.StaffID WHERE gam.StaffType != 0 AND (con.ContractType = 0 OR con.ContractType IS NULL OR con.ContractType = 3)").fetchall()

formatted_tuples = []

Expand All @@ -239,6 +290,87 @@ def fetch_staff():

return formatted_tuples

def fetch_seasonResults(yearSelected):
year = (yearSelected, )
drivers = cursor.execute("SELECT DriverID FROM Races_DriverStandings WHERE RaceFormula = 1 AND SeasonID = " + str(year[0])).fetchall()
seasonResults = []
for driver in drivers:
driverRes = fetch_oneDriver_seasonResults(driver, year)
if(driverRes):
seasonResults.append(driverRes)
return seasonResults

def fetch_oneDriver_seasonResults(driver, year):
results = cursor.execute("SELECT DriverID, TeamID, FinishingPos, Points FROM Races_Results WHERE Season = " + str(year[0]) + " AND DriverID = " + str(driver[0])).fetchall()
if results:
sprintResults = cursor.execute("SELECT RaceID, FinishingPos, ChampionshipPoints FROM Races_SprintResults WHERE SeasonID = " + str(year[0]) + " AND DriverID = " + str(driver[0])).fetchall()
teamID = results[0][1]
driverName = cursor.execute("SELECT FirstName, LastName FROM Staff_BasicData WHERE StaffID = " + str(driver[0])).fetchone()
return format_seasonResults(results, driverName, teamID, driver, year, sprintResults)


def fetch_events_from(year):
season_events = cursor.execute("SELECT TrackID FROM Races WHERE SeasonID = " + str(year)).fetchall()
tuple_numbers = {num for tpl in season_events for num in tpl}

season_ids = cursor.execute("SELECT RaceID FROM Races WHERE SeasonID = " + str(year)).fetchall()
events_ids =[]
for i in range(len(season_ids)):
events_ids.append((season_ids[i][0], season_events[i][0]))

return events_ids

def format_seasonResults(results, driverName, teamID, driverID, year, sprints):
nombre_pattern = r'StaffName_Forename_(Male|Female)_(\w+)'
apellido_pattern = r'StaffName_Surname_(\w+)'

nombre_match = re.search(nombre_pattern, driverName[0])
apellido_match = re.search(apellido_pattern, driverName[1])

nombre = remove_number(nombre_match.group(2))
apellido = remove_number(apellido_match.group(1))
name_formatted = f"{nombre} {apellido}"

races_participated = cursor.execute("SELECT RaceID FROM Races_Results WHERE DriverID = " + str(driverID[0]) + " AND Season = " + str(year[0])).fetchall()
formatred_results = [(result[-2], result[-1]) for result in results]
for i in range(len(races_participated)):
driver_with_fastest_lap = cursor.execute("SELECT DriverID FROM Races_Results WHERE FastestLap > 0 AND RaceID = "+ str(races_participated[i][0]) + " AND Season = " + str(year[0]) + " ORDER BY FastestLap LIMIT 1; ").fetchone()
dnfd = cursor.execute("SELECT DNF FROM Races_Results WHERE DriverID = " + str(driverID[0]) + " AND Season = " + str(year[0]) + " AND RaceID = " + str(races_participated[i][0])).fetchone()
formatred_results[i] = (races_participated[i][0],) + formatred_results[i]
if dnfd[0] == 1:
results_list = list(formatred_results[i])
results_list[-1] = -1
results_list[-2] = -1
formatred_results[i] = tuple(results_list)
if driver_with_fastest_lap[0] == driverID[0]:
results_list = list(formatred_results[i])
results_list.append(1)
formatred_results[i] = tuple(results_list)
else:
results_list = list(formatred_results[i])
results_list.append(0)
formatred_results[i] = tuple(results_list)

for tupla1 in sprints:
for i, tupla2 in enumerate(formatred_results):
if tupla1[0] == tupla2[0]:
formatred_results[i] = tupla2 + (tupla1[2], tupla1[1])

position = cursor.execute("SELECT Position FROM Races_Driverstandings WHERE RaceFormula = 1 AND SeasonID = " + str(year[0]) + " AND DriverID = " + str(driverID[0])).fetchone()

formatred_results.insert(0, position[0])
formatred_results.insert(0, teamID)
formatred_results.insert(0, name_formatted)
return formatred_results

def fetch_drivers_per_year(year):
drivers = cursor.execute('SELECT bas.FirstName, bas.LastName, res.DriverID, res.TeamID FROM Staff_BasicData bas JOIN Races_Results res ON bas.StaffID = res.DriverID WHERE Season = ' + str(year) + " GROUP BY bas.FirstName, bas.LastName, bas.StaffID, res.TeamID").fetchall()
formatted_tuples = []
for tupla in drivers:
result = format_names_simple(tupla)
formatted_tuples.append(result)
return formatted_tuples

def fetch_info():

drivers = cursor.execute('SELECT bas.FirstName, bas.LastName, bas.StaffID, con.TeamID, con.PosInTeam, MIN(con.ContractType) AS MinContractType FROM Staff_BasicData bas JOIN Staff_DriverData dri ON bas.StaffID = dri.StaffID LEFT JOIN Staff_Contracts con ON dri.StaffID = con.StaffID GROUP BY bas.FirstName, bas.LastName, bas.StaffID, con.TeamID;').fetchall()
Expand All @@ -254,14 +386,41 @@ def check_claendar():
day_season = cursor.execute("SELECT Day, CurrentSeason FROM Player_State").fetchone()
season_events = cursor.execute("SELECT TrackID FROM Races WHERE SeasonID = " + str(day_season[1])).fetchall()
tuple_numbers = {num for tpl in season_events for num in tpl}
first_race = cursor.execute("SELECT MIN(Day) FROM Races WHERE SeasonID = " + str(day_season[1])).fetchone()
last_race_last_season = cursor.execute("SELECT MAX(RaceID) FROM Races WHERE SeasonID = " + str(day_season[1]-1)).fetchone()
first_race_curr_season = cursor.execute("SELECT MIN(RaceID) FROM Races WHERE SeasonID = " + str(day_season[1])).fetchone()


season_ids = cursor.execute("SELECT RaceID FROM Races WHERE SeasonID = " + str(day_season[1])).fetchall()
events_ids =[]
for i in range(len(season_ids)):
events_ids.append((season_ids[i][0], season_events[i][0]))

are_all_numbers_present = all(num in tuple_numbers for num in default_tracks)
has_first_race_done = day_season[0] < first_race[0]
has_been_edited = last_race_last_season[0] + 1 == first_race_curr_season[0]

# Definir la variable resultante
resultCalendar = "1" if are_all_numbers_present else "0"
resultCalendar = "1" if (are_all_numbers_present and has_first_race_done and has_been_edited) else "0"

return resultCalendar

def format_names_simple(name):
nombre_pattern = r'StaffName_Forename_(Male|Female)_(\w+)'
apellido_pattern = r'StaffName_Surname_(\w+)'


nombre_match = re.search(nombre_pattern, name[0])
apellido_match = re.search(apellido_pattern, name[1])


nombre = remove_number(nombre_match.group(2))
apellido = remove_number(apellido_match.group(1))
name_formatted = f"{nombre} {apellido}"
team_id = name[3] if name[3] is not None else 0

resultado = (name_formatted, name[2], team_id)
return resultado

def format_names_get_stats(name, type):
nombre_pattern = r'StaffName_Forename_(Male|Female)_(\w+)'
Expand Down
Loading

0 comments on commit 3536f04

Please sign in to comment.