Skip to content

Commit

Permalink
experimental role-based matchmaking
Browse files Browse the repository at this point in the history
  • Loading branch information
spookybear0 committed May 26, 2024
1 parent 606e686 commit a0dcf8d
Show file tree
Hide file tree
Showing 7 changed files with 330 additions and 51 deletions.
18 changes: 18 additions & 0 deletions assets/html/matchmaking.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

currentMode = "{{ mode }}"; // sm5 or laserall
numTeams = 2;
matchmakeRoles = false;
all_players = {{ all_players|tojson }};
</script>

Expand Down Expand Up @@ -140,6 +141,16 @@
color: lightgray;
}

.role-cell-hidden {
padding: 0;
display: none;
}

.role-cell {
padding: 0;
padding-top: 0.15rem;
}

@media screen and (max-width: 991px) {
#content {
width: 100%;
Expand Down Expand Up @@ -196,6 +207,7 @@
<button onclick="matchmakePlayers()" class="btn"><h3>Matchmake Players</h3></button>
<button onclick="addUnratedPlayer()" class="btn"><h3>Add Unrated Player</h3></button>
<button onclick="switchMode()" class="btn" id="modeBtn"><h3>Switch Mode to Laserball</h3></button>
<button onclick="switchMatchmakingRoles()" class="btn" id="matchmakeRolesBtn"><h3>Matchmake Roles/Players</h3></button>
</div>
</div>
<div class="sub-container">
Expand All @@ -204,11 +216,13 @@ <h2>Players</h2>
<table>
<tbody>
<tr>
<th class="role-cell-hidden"></th> <!--empty cell for role-->
<th>Player</th>
<th>Rating</th>
</tr>
{% for player in players %}
<tr draggable="true" ondragend="dragEnd(event)">
<td class="role-cell-hidden"></td>
<td>{{ player.codename }}</td>
<td>{{ player.sm5_ordinal|round(2) }}</td>
</tr>
Expand All @@ -224,6 +238,7 @@ <h2>Team 1</h2>
<table>
<tbody>
<tr>
<th class="role-cell-hidden"></th> <!--empty cell for role-->
<th>Player</th>
<th>Rating</th>
</tr>
Expand All @@ -235,6 +250,7 @@ <h2>Team 2</h2>
<table>
<tbody>
<tr>
<th class="role-cell-hidden"></th> <!--empty cell for role-->
<th>Player</th>
<th>Rating</th>
</tr>
Expand All @@ -246,6 +262,7 @@ <h2>Team 3</h2>
<table>
<tbody>
<tr>
<th class="role-cell-hidden"></th> <!--empty cell for role-->
<th>Player</th>
<th>Rating</th>
</tr>
Expand All @@ -257,6 +274,7 @@ <h2>Team 4</h2>
<table>
<tbody>
<tr>
<th class="role-cell-hidden"></th> <!--empty cell for role-->
<th>Player</th>
<th>Rating</th>
</tr>
Expand Down
128 changes: 100 additions & 28 deletions assets/js/matchmaking.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

const roleImgs = ["assets/sm5/roles/commander.png", "assets/sm5/roles/heavy.png", "assets/sm5/roles/scout.png", "assets/sm5/roles/ammo.png", "assets/sm5/roles/medic.png"];

function addTeam() {
if (numTeams < 4) {
Expand Down Expand Up @@ -152,25 +153,25 @@ function formatTeamLists() {
if (i != 1) {
team1 += ', ';
}
team1 += '"' + team1Table.children[i].children[0].innerHTML + '"';
team1 += '"' + team1Table.children[i].children[1].innerHTML + '"';
}
for (let i = 1; i < team2Table.children.length; i++) {
if (i != 1) {
team2 += ', ';
}
team2 += '"' + team2Table.children[i].children[0].innerHTML + '"';
team2 += '"' + team2Table.children[i].children[1].innerHTML + '"';
}
for (let i = 1; i < team3Table.children.length; i++) {
if (i != 1) {
team3 += ', ';
}
team3 += '"' + team3Table.children[i].children[0].innerHTML + '"';
team3 += '"' + team3Table.children[i].children[1].innerHTML + '"';
}
for (let i = 1; i < team4Table.children.length; i++) {
if (i != 1) {
team4 += ', ';
}
team4 += '"' + team4Table.children[i].children[0].innerHTML + '"';
team4 += '"' + team4Table.children[i].children[1].innerHTML + '"';
}

team1 += "]";
Expand Down Expand Up @@ -238,8 +239,6 @@ function updateWinChances() {
}

if (numTeams == 3) {
console.log(winChances);

let team1VsTeam2WinChance = Math.round(winChances[0][0] * 100 * 100) / 100;
let team2VsTeam1WinChance = Math.round(winChances[0][1] * 100 * 100) / 100;
let team1VsTeam3WinChance = Math.round(winChances[1][0] * 100 * 100) / 100;
Expand Down Expand Up @@ -283,25 +282,25 @@ function updateWinChances() {

for (let i = 1; i < team1Table.children.length; i++) {
try {
team1Table.children[i].children[1].innerHTML = Math.round(all_players[team1Table.children[i].children[0].innerHTML][mode_index] * 100) / 100;
team1Table.children[i].children[2].innerHTML = Math.round(all_players[team1Table.children[i].children[1].innerHTML][mode_index] * 100) / 100;
}
catch (e) {}
}
for (let i = 1; i < team2Table.children.length; i++) {
try {
team2Table.children[i].children[1].innerHTML = Math.round(all_players[team2Table.children[i].children[0].innerHTML][mode_index] * 100) / 100;
team2Table.children[i].children[2].innerHTML = Math.round(all_players[team2Table.children[i].children[1].innerHTML][mode_index] * 100) / 100;
}
catch (e) {}
}
for (let i = 1; i < team3Table.children.length; i++) {
try {
team3Table.children[i].children[1].innerHTML = Math.round(all_players[team3Table.children[i].children[0].innerHTML][mode_index] * 100) / 100;
team3Table.children[i].children[2].innerHTML = Math.round(all_players[team3Table.children[i].children[1].innerHTML][mode_index] * 100) / 100;
}
catch (e) {}
}
for (let i = 1; i < team4Table.children.length; i++) {
try {
team4Table.children[i].children[1].innerHTML = Math.round(all_players[team4Table.children[i].children[0].innerHTML][mode_index] * 100) / 100;
team4Table.children[i].children[2].innerHTML = Math.round(all_players[team4Table.children[i].children[1].innerHTML][mode_index] * 100) / 100;
}
catch (e) {}
}
Expand All @@ -326,21 +325,30 @@ function matchmakePlayers() {

let xhr = new XMLHttpRequest();
let url = "/api/internal/matchmake/" + currentMode;
let params = "team1=" + team1 + "&team2=" + team2 + "&team3=" + team3 + "&team4=" + team4 + "&num_teams=" + numTeams;
let params = "team1=" + team1 + "&team2=" + team2 + "&team3=" + team3 + "&team4=" + team4 + "&num_teams=" + numTeams + "&matchmake_roles=" + matchmakeRoles;
xhr.open("GET", url + "?" + params, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
let matchmadeTeams = JSON.parse(xhr.responseText);
let jsonData = JSON.parse(xhr.responseText);

let matchmadeTeams = jsonData["teams"];
let matchmadeRoles = jsonData["roles"];

let className = "role-cell-hidden";
if (matchmakeRoles) {
className = "role-cell";
}

let team1Table = document.getElementById("team1-div").querySelector("table").querySelector("tbody");
let team2Table = document.getElementById("team2-div").querySelector("table").querySelector("tbody");
let team3Table = document.getElementById("team3-div").querySelector("table").querySelector("tbody");
let team4Table = document.getElementById("team4-div").querySelector("table").querySelector("tbody");

team1Table.innerHTML = "<tr><th>Player</th><th>Rating</th></tr>";
team2Table.innerHTML = "<tr><th>Player</th><th>Rating</th></tr>";
team3Table.innerHTML = "<tr><th>Player</th><th>Rating</th></tr>";
team4Table.innerHTML = "<tr><th>Player</th><th>Rating</th></tr>";
team1Table.innerHTML = `<tr><th class="${className}"></th><th>Player</th><th>Rating</th></tr>`;
team2Table.innerHTML = `<tr><th class="${className}"></th><th>Player</th><th>Rating</th></tr>`;
team3Table.innerHTML = `<tr><th class="${className}"></th><th>Player</th><th>Rating</th></tr>`;
team4Table.innerHTML = `<tr><th class="${className}"></th><th>Player</th><th>Rating</th></tr>`;

let mode_index;

Expand All @@ -351,19 +359,43 @@ function matchmakePlayers() {
mode_index = 1;
}

console.log(matchmadeTeams);
// this could easily be a for loop, but I'm too lazy to change it

let i = 0;
for (var key in matchmadeTeams[0]) {
team1Table.innerHTML += "<tr draggable='true' ondragend='dragEnd(event)'><td>" + key + "</td><td>" + Math.round(matchmadeTeams[0][key][mode_index] * 100) / 100 + "</td></tr>";
roleImg = "";
if (matchmakeRoles) {
roleImg = `<img src="${roleImgs[matchmadeRoles[0][i]-1]}" width="25" height="25">`;
}
team1Table.innerHTML += `<tr draggable='true' ondragend='dragEnd(event)'><td class="${className}">${roleImg}</td><td>${key}</td><td>${Math.round(matchmadeTeams[0][key][mode_index] * 100) / 100}</td></tr>`;
i++;
}
i = 0;
for (var key in matchmadeTeams[1]) {
team2Table.innerHTML += "<tr draggable='true' ondragend='dragEnd(event)'><td>" + key + "</td><td>" + Math.round(matchmadeTeams[1][key][mode_index] * 100) / 100 + "</td></tr>";
roleImg = "";
if (matchmakeRoles) {
roleImg = `<img src="${roleImgs[matchmadeRoles[1][i]-1]}" width="25" height="25">`
}
team2Table.innerHTML += `<tr draggable='true' ondragend='dragEnd(event)'><td class="${className}">${roleImg}</td><td>${key}</td><td>${Math.round(matchmadeTeams[1][key][mode_index] * 100) / 100}</td></tr>`;
i++
}
i = 0;
for (var key in matchmadeTeams[2]) {
team3Table.innerHTML += "<tr draggable='true' ondragend='dragEnd(event)'><td>" + key + "</td><td>" + Math.round(matchmadeTeams[2][key][mode_index] * 100) / 100 + "</td></tr>";
roleImg = "";
if (matchmakeRoles) {
roleImg = `<img src="${roleImgs[matchmadeRoles[2][i]-1]}" width="25" height="25">`
}
team3Table.innerHTML += `<tr draggable='true' ondragend='dragEnd(event)'><td class="${className}">${roleImg}</td><td>${key}</td><td>${Math.round(matchmadeTeams[2][key][mode_index] * 100) / 100}</td></tr>`;
i++
}
i = 0;
for (var key in matchmadeTeams[3]) {
team4Table.innerHTML += "<tr draggable='true' ondragend='dragEnd(event)'><td>" + key + "</td><td>" + Math.round(matchmadeTeams[3][key][mode_index] * 100) / 100 + "</td></tr>";
roleImg = "";
if (matchmakeRoles) {
roleImg = `<img src="${roleImgs[matchmadeRoles[3][i]-1]}" width="25" height="25">`
}
team4Table.innerHTML += `<tr draggable='true' ondragend='dragEnd(event)'><td class="${className}">${roleImg}</td><td>${key}</td><td>${Math.round(matchmadeTeams[3][key][mode_index] * 100) / 100}</td></tr>`;
i++
}

updateWinChances();
Expand All @@ -377,7 +409,7 @@ function addUnratedPlayer() {
let rating = 0;

let team1Table = document.getElementById("team1-div").querySelector("table").querySelector("tbody");
team1Table.innerHTML += "<tr draggable='true' ondragend='dragEnd(event)'><td>" + codename + "</td><td>" + rating + "</td></tr>";
team1Table.innerHTML += "<tr draggable='true' ondragend='dragEnd(event)'><td class=\"role-cell-hidden\"></td><td>" + codename + "</td><td>" + rating + "</td></tr>";

all_players[codename] = [0, 0];

Expand Down Expand Up @@ -410,14 +442,56 @@ function switchMode() {
updateWinChances();
}

function switchMatchmakingRoles() {
var newClass = "role-cell-hidden";

if (matchmakeRoles) {
matchmakeRoles = false;
document.getElementById("matchmakeRolesBtn").innerHTML = "<h3>Matchmake Roles/Players</h3>";
}
else {
matchmakeRoles = true;
document.getElementById("matchmakeRolesBtn").innerHTML = "<h3>Matchmake Players Only</h3>";
newClass = "role-cell";
}

// show/hide role cells

let playersTable = document.getElementById("players-div").querySelector("table").querySelector("tbody");

for (let i = 0; i < playersTable.children.length; i++) {
playersTable.children[i].children[0].className = newClass;
}

let team1Table = document.getElementById("team1-div").querySelector("table").querySelector("tbody");
let team2Table = document.getElementById("team2-div").querySelector("table").querySelector("tbody");
let team3Table = document.getElementById("team3-div").querySelector("table").querySelector("tbody");
let team4Table = document.getElementById("team4-div").querySelector("table").querySelector("tbody");

for (let i = 0; i < team1Table.children.length; i++) {
team1Table.children[i].children[0].className = newClass;
}
for (let i = 0; i < team2Table.children.length; i++) {
team2Table.children[i].children[0].className = newClass;
}
for (let i = 0; i < team3Table.children.length; i++) {
team3Table.children[i].children[0].className = newClass;
}
for (let i = 0; i < team4Table.children.length; i++) {
team4Table.children[i].children[0].className = newClass;
}

updateWinChances();
}

// url args from game page when hitting rematchmake
function interpretUrlArgs() {
if (team1 || team2) {
let team1Table = document.getElementById("team1-div").querySelector("table").querySelector("tbody");
let team2Table = document.getElementById("team2-div").querySelector("table").querySelector("tbody");

team1Table.innerHTML = "<tr><th>Player</th><th>Rating</th></tr>";
team2Table.innerHTML = "<tr><th>Player</th><th>Rating</th></tr>";
team1Table.innerHTML = "<tr><th class=\"role-cell-hidden\"></th><th>Player</th><th>Rating</th></tr>";
team2Table.innerHTML = "<tr><th class=\"role-cell-hidden\"></th><th>Player</th><th>Rating</th></tr>";

let mode_index;

Expand All @@ -430,11 +504,11 @@ function interpretUrlArgs() {

for (let i = 0; i < team1.length; i++) {
let player = team1[i];
team1Table.innerHTML += "<tr draggable='true' ondragend='dragEnd(event)'><td>" + player[0] + "</td><td>" + Math.round(player[mode_index+1] * 100) / 100 + "</td></tr>";
team1Table.innerHTML += "<tr draggable='true' ondragend='dragEnd(event)'><td class=\"role-cell-hidden\"></td><td>" + player[0] + "</td><td>" + Math.round(player[mode_index+1] * 100) / 100 + "</td></tr>";
}
for (let i = 0; i < team2.length; i++) {
let player = team2[i];
team2Table.innerHTML += "<tr draggable='true' ondragend='dragEnd(event)'><td>" + player[0] + "</td><td>" + Math.round(player[mode_index+1] * 100) / 100 + "</td></tr>";
team2Table.innerHTML += "<tr draggable='true' ondragend='dragEnd(event)'><td class=\"role-cell-hidden\"></td><td>" + player[0] + "</td><td>" + Math.round(player[mode_index+1] * 100) / 100 + "</td></tr>";
}
}
}
Expand All @@ -443,9 +517,7 @@ window.onload = function() {
interpretUrlArgs();

// default mode is sm5, if urlargs say it's laserball, switch to laserball
console.log(currentMode);
if (currentMode == "laserball") {
console.log("switching to laserball");
switchModeToLaserball();
}

Expand Down
41 changes: 41 additions & 0 deletions db/migrations/models/3_20240526004544_role_specific_ratings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from tortoise import BaseDBAsyncClient


async def upgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE `laserballgame` MODIFY COLUMN `winner` VARCHAR(5) NOT NULL COMMENT 'Fire Team: red\nEarth Team: green\nIce Team: blue';
ALTER TABLE `legacylaserballgame` MODIFY COLUMN `winner` VARCHAR(5) NOT NULL COMMENT 'Fire Team: red\nEarth Team: green\nIce Team: blue';
ALTER TABLE `legacylaserballgameplayer` MODIFY COLUMN `team` VARCHAR(5) NOT NULL COMMENT 'Fire Team: red\nEarth Team: green\nIce Team: blue';
ALTER TABLE `legacysm5game` MODIFY COLUMN `winner` VARCHAR(5) NOT NULL COMMENT 'Fire Team: red\nEarth Team: green\nIce Team: blue';
ALTER TABLE `legacysm5gameplayer` MODIFY COLUMN `team` VARCHAR(5) NOT NULL COMMENT 'Fire Team: red\nEarth Team: green\nIce Team: blue';
ALTER TABLE `player` ADD `ammo_mu` DOUBLE NOT NULL DEFAULT 25;
ALTER TABLE `player` ADD `scout_sigma` DOUBLE NOT NULL DEFAULT 8.333;
ALTER TABLE `player` ADD `scout_mu` DOUBLE NOT NULL DEFAULT 25;
ALTER TABLE `player` ADD `commander_sigma` DOUBLE NOT NULL DEFAULT 8.333;
ALTER TABLE `player` ADD `medic_mu` DOUBLE NOT NULL DEFAULT 25;
ALTER TABLE `player` ADD `ammo_sigma` DOUBLE NOT NULL DEFAULT 8.333;
ALTER TABLE `player` ADD `medic_sigma` DOUBLE NOT NULL DEFAULT 8.333;
ALTER TABLE `player` ADD `heavy_sigma` DOUBLE NOT NULL DEFAULT 8.333;
ALTER TABLE `player` ADD `heavy_mu` DOUBLE NOT NULL DEFAULT 25;
ALTER TABLE `player` ADD `commander_mu` DOUBLE NOT NULL DEFAULT 25;
ALTER TABLE `sm5game` MODIFY COLUMN `winner` VARCHAR(5) COMMENT 'Fire Team: red\nEarth Team: green\nIce Team: blue';"""


async def downgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE `player` DROP COLUMN `ammo_mu`;
ALTER TABLE `player` DROP COLUMN `scout_sigma`;
ALTER TABLE `player` DROP COLUMN `scout_mu`;
ALTER TABLE `player` DROP COLUMN `commander_sigma`;
ALTER TABLE `player` DROP COLUMN `medic_mu`;
ALTER TABLE `player` DROP COLUMN `ammo_sigma`;
ALTER TABLE `player` DROP COLUMN `medic_sigma`;
ALTER TABLE `player` DROP COLUMN `heavy_sigma`;
ALTER TABLE `player` DROP COLUMN `heavy_mu`;
ALTER TABLE `player` DROP COLUMN `commander_mu`;
ALTER TABLE `sm5game` MODIFY COLUMN `winner` VARCHAR(5) COMMENT 'RED: red\nGREEN: green\nBLUE: blue';
ALTER TABLE `laserballgame` MODIFY COLUMN `winner` VARCHAR(5) NOT NULL COMMENT 'RED: red\nGREEN: green\nBLUE: blue';
ALTER TABLE `legacysm5game` MODIFY COLUMN `winner` VARCHAR(5) NOT NULL COMMENT 'RED: red\nGREEN: green\nBLUE: blue';
ALTER TABLE `legacylaserballgame` MODIFY COLUMN `winner` VARCHAR(5) NOT NULL COMMENT 'RED: red\nGREEN: green\nBLUE: blue';
ALTER TABLE `legacysm5gameplayer` MODIFY COLUMN `team` VARCHAR(5) NOT NULL COMMENT 'RED: red\nGREEN: green\nBLUE: blue';
ALTER TABLE `legacylaserballgameplayer` MODIFY COLUMN `team` VARCHAR(5) NOT NULL COMMENT 'RED: red\nGREEN: green\nBLUE: blue';"""
Loading

0 comments on commit a0dcf8d

Please sign in to comment.