diff --git a/.gitignore b/.gitignore
index 54c4ba9..0ea5c96 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,7 @@
-config.json
-public/images
-public/assets
-node_modules
-todo
\ No newline at end of file
+config.json
+public/images
+public/assets
+public/javascript/user copy.js
+node_modules
+todo
+.DS_Store
\ No newline at end of file
diff --git a/public/javascript/user.js b/public/javascript/user.js
index 8146c4d..b33a55c 100644
--- a/public/javascript/user.js
+++ b/public/javascript/user.js
@@ -93,18 +93,18 @@ async function getReleventInformation(musicData, id) {
async function getReleventInformationMap(mapData, mapid) {
let mapMatch = undefined;
- for(map of mapData) {
+ for (map of mapData) {
if (map.mapInfomation.colorId.id == mapid) {
mapMatch = map
} else continue
-
+
}
return mapMatch
}
// Ban Check lmao
-if (userdata.ban_state === 2 ||userdata.banState === 2) {
+if (userdata.ban_state === 2 || userdata.banState === 2) {
//nice
const parent = document.getElementById("User");
const wrapperDiv = document.createElement("div");
@@ -201,8 +201,6 @@ async function userPlayLogFormatter(div, loadMoreButton) {
}
// Get the user's play log data and music IDs.
- console.log(UserPlayLogData)
- const musicIds = UserPlayLogData.map(score => score.music_id);
const musicData = await musicMetadata();
let errorIncrement = 0;
@@ -215,6 +213,7 @@ async function userPlayLogFormatter(div, loadMoreButton) {
continue
}
let diffucultyData = song.difficultys.Notes[score.level] // get difficulty information
+ const tasGrid = document.createElement('div');
if (!song || !song.name) { // if a song can't be found, skip it and increment the error counter by 1.
console.log(song)
@@ -223,63 +222,128 @@ async function userPlayLogFormatter(div, loadMoreButton) {
errorIncrement++
continue;
}
- console.log(song)
- scoreDiv.innerHTML = `
+ // Song Title
+ tasGrid.innerHTML = `
-
${song.name.str} || ${new Date(score.user_play_date||score.userPlayDate)}
+ ${song.name.str}
`;
- /* Score Jacket Image */
+ // Song Jacket
const scoreJacketDiv = document.createElement('div');
let jacket = document.createElement('img');
jacket.addEventListener("error", function () {
this.src = "assets/icon/UI_Icon_000000.png";
});
- scoreJacketDiv.classList.add('score-jacket');
jacket.classList.add('score-jacket');
jacket.src = "assets/jacket/UI_Jacket_" + padNumber(Number(song.InGameID), 6) + '.png';
scoreJacketDiv.append(jacket)
scoreDiv.append(scoreJacketDiv)
/* Achivement Box */
+
const scoreAchivementDiv = document.createElement('div');
scoreAchivementDiv.classList.add('score-achivement');
- scoreAchivementDiv.innerHTML = `ACHIVEMENT
`;
- let achivementPercentage = document.createElement('h5');
+ let achivementPercentage = document.createElement('h4');
let achivementNumber = padNumber(Number(score.achievement), 7)
achivementPercentage.textContent = `${achivementNumber / 10000}%`;
scoreAchivementDiv.append(achivementPercentage)
- scoreDiv.append(scoreAchivementDiv)
+ tasGrid.append(scoreAchivementDiv)
/* Score Grade */
+
let scoreGrades = ["D", "C", "B", "BB", "BBB", "A", "AA", "AAA", "S", "S+", "SS", "SS+", "SSS", "SSS+"]
+ let SGimgarray = ["D", "C", "B", "BB", "BBB", "A", "AA", "AAA", "S", "Sp", "SS", "SSp", "SSS", "SSSp"]
const scoreGradeDiv = document.createElement('div');
scoreGradeDiv.classList.add('score-grade');
- let scoreGrade = document.createElement('h4');
- scoreGrade.textContent = `${scoreGrades[score.score_rank||score.scoreRank]}`;
- scoreGradeDiv.append(scoreGrade);
- scoreDiv.append(scoreGradeDiv);
+ if (rankImgCheck = false) {
+ let scoreGrade = document.createElement('h4');
+ scoreGrade.textContent = `${scoreGrades[score.score_rank || score.scoreRank]}`;
+ scoreGradeDiv.append(scoreGrade);
+ } else {
+ let SGimg = document.createElement('img');
+ SGimg.addEventListener("error", function () {
+ this.src = "assets/icon/UI_Icon_000000.png";
+ });
+ SGimg.classList.add('sg-image');
+ SGimg.src = "assets/uicon/UI_TTR_Rank_" + SGimgarray[score.score_rank || score.scoreRank] + '.png';
+ scoreGradeDiv.append(SGimg);
+ }
+ tasGrid.append(scoreGradeDiv);
- /* DX Score, Full Combo, Full Sync, and Multi-Placement */
+ //DX Score & Fast Late Reading
+ const rGrid = document.createElement('div');
- const scoreInfoDiv = document.createElement('div');
- scoreInfoDiv.classList.add('score-info');
- const scoreInfoGridDiv = document.createElement('div');
- scoreInfoDiv.classList.add('score-info-grid');
- // please i dont want to make a fucking nested grid
- /* DX Score */
- const scoreDXScoreDiv = document.createElement('div');
- scoreDXScoreDiv.classList.add('DX-Score');
- scoreDXScoreDiv.innerHTML = `DX Score: ${score.deluxscore}/${diffucultyData.maxNotes * 3}
`;
- scoreInfoGridDiv.append(scoreDXScoreDiv);
- scoreInfoDiv.append(scoreInfoGridDiv);
- scoreDiv.append(scoreInfoDiv);
- /* Full Combo */
- /* Full Sync */
- /* Player Placement */
+ const DXScoreDiv = document.createElement('div');
+ DXScoreDiv.classList.add('DX-Score');
+ let DXScore = document.createElement('h4');
+ DXScore.classList.add('DX-Score');
+ DXScore.innerHTML = `DXs ${score.deluxscore}/${diffucultyData.maxNotes * 3}`;
+ let FLindi = document.createElement('h4');
+ FLindi.classList.add('DX-Score');
+ FLindi.innerHTML = `F/L ${score.fastCount}/${score.lateCount}`;
+ DXScoreDiv.append(DXScore);
+ DXScoreDiv.append(FLindi);
+ rGrid.append(DXScoreDiv);
+
+ /* Full Combo & Full Sync Icons, in a table of 1 row 2 col */
+
+ const FCFSgrid = document.createElement('div');
+ FCFSgrid.setAttribute("class", "fcfs-grid");
+
+ /* Full Combo Icon */
+ let FCTypes = ["SC", "FC", "FCp", "AP", "APp"];
+ let FCimgDiv = document.createElement('div');
+ let FCimg = document.createElement('img');
+ FCimg.addEventListener("error", function () {
+ this.src = "assets/icon/UI_Icon_000000.png";
+ });
+ FCimgDiv.classList.add('fullCombo-image'); //seriously galexion make up your god damned mind
+ FCimg.classList.add('fullCombo-image');
+ FCimg.src = "assets/uicon/UI_CHR_PlayBonus_" + FCTypes[score.comboStatus] + '.png';
+
+
+ FCimgDiv.append(FCimg)
+ FCFSgrid.append(FCimgDiv)
+
+ /* Full Sync Icon */
+ let FSTypes = ["PS", "FS", "FSp"];
+ let FSimgDiv = document.createElement('div');
+ let FSimg = document.createElement('img');
+ FSimg.addEventListener("error", function () {
+ this.src = "assets/icon/UI_Icon_000000.png";
+ });
+ FSimgDiv.classList.add('fullSync-image'); //seriously galexion make up your god damned mind
+ FSimg.classList.add('fullSync-image');
+ FSimg.src = "assets/uicon/UI_CHR_PlayBonus_" + FSTypes[score.syncStatus] + '.png';
+
+
+ FSimgDiv.append(FSimg);
+ FCFSgrid.append(FSimgDiv);
+
+ /* Details shit */
+ let detailsBlock = document.createElement('details');
+ detailsBlock.classList.add('score-info-grid');
+ let summary = document.createElement('summary');
+ summary.textContent = "Details";
+ const detailsGridDiv = document.createElement('div');
+
+ /* title to table */
+ let detailsTable = document.createElement('table');
+ await createtTable(detailsTable, score)
+
+
+ detailsGridDiv.append(detailsTable);
+ detailsBlock.append(detailsGridDiv);
+ scoreDiv.append(detailsBlock);
- /* Side note: Can't Do Any of this without the Image Assets / Information, So Moving on for now */
/* setting stuff up */
+
+
+ rGrid.classList.add('rGrid');
+ tasGrid.classList.add('tasGrid');
+ rGrid.append(FCFSgrid)
+ scoreDiv.append(rGrid)
+ scoreDiv.append(tasGrid)
scoreDiv.setAttribute("class", "score-grid");
scoreIncrement++
@@ -298,6 +362,118 @@ async function userPlayLogFormatter(div, loadMoreButton) {
// If there are no more scores to load, hide the "Load More" button.
}
+function createtTable(detailsTable, score) { //thing needs to be seperated or else it will keep creating the 2nd recent score. beats me. \-(*-*)-/
+ return new Promise((resolve, reject) => {
+ let hrow = detailsTable.insertRow(0);
+ let judgementType = ["Critical Perfect", "Perfect", "Great", "Good", "Miss"];
+ let noteType = ["Tap", "Hold", "Slide", "Break", "Touch"];
+ let noteJudgement = [
+ [
+ score.tapCriticalPerfect,
+ score.tapPerfect,
+ score.tapGreat,
+ score.tapGood,
+ score.tapMiss,
+ ],
+ [
+ score.holdCriticalPerfect,
+ score.holdPerfect,
+ score.holdGreat,
+ score.holdGood,
+ score.holdMiss,
+ ],
+ [
+ score.slideCriticalPerfect,
+ score.slidePerfect,
+ score.slideGreat,
+ score.slideGood,
+ score.slideMiss,
+ ],
+ [
+ score.breakCriticalPerfect,
+ score.breakPerfect,
+ score.breakGreat,
+ score.breakGood,
+ score.breakMiss,
+ ],
+ [
+ score.touchCriticalPerfect,
+ score.touchPerfect,
+ score.touchGreat,
+ score.touchGood,
+ score.touchMiss,
+ ]
+ ]
+ if (score.isCriticalDisp == 1) { // Perform a check to see if critPerfects are required
+ let blankCell = hrow.insertCell(0);
+ blankCell.innerText = ""
+ for (i = 0; i < judgementType.length; i++) {
+ let cell = hrow.insertCell(i + 1);
+ cell.innerText = judgementType[i];
+ }
+
+ if (score.isTouch == 1) { // Check if Touch Notes are Needed.
+ let judgementCount = (judgementType.length - 1) + score.isCriticalDisp;
+ for (i = 0; i < noteType.length; i++) {
+ let row = detailsTable.insertRow(i);
+ let blankCell = row.insertCell(0);
+ blankCell.innerText = noteType[i]
+ for (ii = 0; ii < judgementCount; ii++) {
+ let cell = row.insertCell(ii + 1);
+ cell.innerText = noteJudgement[i][ii]
+ }
+ }
+ } else {
+ let judgementCount = (judgementType.length - 1) + score.isCriticalDisp;
+ for (i = 0; i < noteType.length - 1; i++) {
+ let row = detailsTable.insertRow(i);
+ let blankCell = row.insertCell(0);
+ blankCell.innerText = noteType[i]
+ for (ii = 0; ii < judgementCount; ii++) {
+ let cell = row.insertCell(ii + 1);
+ cell.innerText = noteJudgement[i][ii]
+ }
+ }
+ }
+ } else if (score.isCriticalDisp == 0) {
+ let blankCell = hrow.insertCell(0);
+ blankCell.innerText = ""
+ for (i = 0; i < judgementType.length-1; i++) {
+ let cell = hrow.insertCell(i+1);
+ cell.innerText = judgementType[i+1];
+ }
+
+
+ if (score.isTouch == 1) { // Check if Touch Notes are Needed.
+ let judgementCount = (judgementType.length - 1) + score.isCriticalDisp;
+ for (i = 0; i < noteType.length; i++) {
+ let row = detailsTable.insertRow(i);
+ let blankCell = row.insertCell(0);
+ blankCell.innerText = noteType[i]
+ for (ii = 0; ii < judgementCount; ii++) {
+ let cell = row.insertCell(ii+1);
+ cell.innerText = noteJudgement[i][ii+1]
+ }
+ }
+ } else {
+ let judgementCount = (judgementType.length - 1) + score.isCriticalDisp;
+ for (i = 0; i < noteType.length; i++) {
+ let row = detailsTable.insertRow(i);
+ let blankCell = row.insertCell(0);
+ blankCell.innerText = noteType[i]
+ for (ii = 0; ii < judgementCount-1; ii++) {
+ let cell = row.insertCell(ii+1);
+ cell.innerText = noteJudgement[i][ii+1]
+ }
+ }
+ }
+ }
+ resolve()
+ });
+} // this was 100 lines of mehness, this shouldnt have taken this long and i probably could have had it at 50 to 75 lines of code instead but i honestly am tired.
+
+
+
/* User Area Status Renderer */
async function userAreaStatusFormatter(div) {
@@ -307,9 +483,8 @@ async function userAreaStatusFormatter(div) {
let areaWrapper = document.createElement('div'); // create the Wrapper Div
for (let i = UserAreaData.length - 1; i >= 0; i--) {
const area = UserAreaData[i]; // get the area
- const mapInfo = await getReleventInformationMap(mapMetadata, area.map_id||area.mapId); // get the relevent Map Information
- console.log(mapInfo)
- if(!mapInfo) continue // continue if mapInfo cant be found for a map
+ const mapInfo = await getReleventInformationMap(mapMetadata, area.map_id || area.mapId); // get the relevent Map Information
+ if (!mapInfo) continue // continue if mapInfo cant be found for a map
const areaGrid = document.createElement('div'); // create the Grid for the area inforrmation to go
areaGrid.classList.add('areaGrid'); // add the appropriate class
/* Area Title */
@@ -331,7 +506,6 @@ async function userAreaStatusFormatter(div) {
} else if (area.distance !== 0) {
let diffrence = unlock.Distance - area.distance
if (diffrence === 0) {
- console.log(unlock)
areaKilometers.innerHTML = areaKilometers.innerHTML + ` Task Track!
Clear ${unlock.TreasureId.str} to continue!`;
} else {
areaKilometers.innerHTML = areaKilometers.innerHTML + ` ${diffrence} KM until Next Reward.`;
@@ -361,25 +535,23 @@ async function userImageFormatter(div) {
let memorialImageList = await imageList(); // get image list
let imageInfoDiv = document.getElementById("image-info-header-div");
imageInfoDiv.innerHTML = "";
- console.log("Attempting to search list with EXT_ID " + ext_id.toString())
for (var i = 0; i < memorialImageList.length; i++) { // for each name in the array
let imageName = memorialImageList[i]
- console.log(imageName)
if (imageName.startsWith(ext_id.toString())) { // Check if the External ID matches the ID within the photo at the beginning
let memorialImage = document.createElement('img');
memorialImage.classList.add('memorialImage');
memorialImage.addEventListener("error", function () {
this.src = "assets/icon/UI_Icon_000000.png";
});
- if(window.serverType === 0) {
+ if (window.serverType === 0) {
memorialImage.src = "images/" + imageName + '.jpg';
} else {
- memorialImage.src = "images/" + imageName + '.jpeg';
+ memorialImage.src = "images/" + imageName + '.jpeg';
}
imageInfoDiv.append(memorialImage)
}
}
- if(imageInfoDiv.innerHTML == "") {
+ if (imageInfoDiv.innerHTML == "") {
let error = document.createElement('h3');
error.innerText = "No Images Memorialised."
imageInfoDiv.append(error)
@@ -553,3 +725,18 @@ async function imageList() {
}
}
+async function rankImgCheck() {
+ const url = "/assets/uicon/UI_TTR_Rank_AA.png";
+
+ try {
+ const response = await fetch(url, {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+ return true
+ } catch (error) {
+ return false
+ }
+}
\ No newline at end of file
diff --git a/public/stylesheets/user.css b/public/stylesheets/user.css
index b37e9c9..c184ee1 100644
--- a/public/stylesheets/user.css
+++ b/public/stylesheets/user.css
@@ -88,10 +88,14 @@ h4.profile {
font-size: 2em;
}
-@media (max-width: 768px) {
- h4 {
- font-size: 1.5em;
+@media (max-width: 600px) {
+ h4.score-grid {
+ font-size: 4vmin;
}
+
+h4.DX-Score {
+ font-size: 3vmin;
+}
}
.error {
@@ -179,9 +183,9 @@ h4.profile {
grid-template-columns: max-content max-content min-content;
grid-template-areas:
- 'title title'
- 'kilometers kilometers'
- '. details';
+ 'title title'
+ 'kilometers kilometers'
+ '. details';
gap: 0px;
height: 100%;
@@ -201,111 +205,138 @@ h4.profile {
padding-top: 1em;
padding-bottom: 1em;
}
-/* Galexion make your fucking mind up are you going to use camelCase or dashe-instead-of-spaces */
+
+/* Galexion make your fucking mind up are you going to use camelCase or dashes-instead-of-spaces */
.score-grid {
display: grid;
- grid-template-rows: min-content min-content min-content;
- grid-template-columns: 82.5% min-content min-content;
+ grid-template-rows: 0.75fr min-content min-content;
+ grid-template-columns: 0.75fr min-content max-content;
grid-auto-rows: minmax(100px, auto);
- grid-template-areas:
- 'label0 label0'
- 'label1 label2'
- 'label1 label3'
- 'label1 label4';
+ grid-template-areas:
+ "Jacket tasGrid rGrid"
+ "Details Details Details";
gap: 0px;
- height: 100%;
- max-width: 75%;
+ margin-bottom: 0.2em;
}
+.rGrid {
+ display:grid;
+ grid-area: rGrid;
+
+ grid-template-rows: min-content min-content;
+ grid-template-areas:
+ 'FC-FS'
+ 'DXs-Fast-Slow';
+}
+
+.fcfs-grid {
+ grid-area: FC-FS;
+ display: grid;
+
+ grid-template-rows: min-content min-content;
+ grid-template-areas:
+ 'fc'
+ 'fs';
+
+ gap: 0px;
+}
+
+.tasGrid {
+ grid-area: tasGrid;
+ display:grid;
+
+ grid-template-rows: min-content min-content;
+ grid-template-areas:
+ 'title'
+ 'achivement'
+ 'score-grade';
+}
+
+
+
@media (min-width: 600px) {
.score-grid {
max-width: 80%;
width: 80%;
- grid-template-rows: max-content min-content min-content;
+ grid-template-rows: 1fr, auto;
grid-template-columns: 1fr 1fr 1fr;
- grid-auto-rows: minmax(100px, auto);
- grid-template-areas:
- 'label0 label0 label0'
- 'label1 label2 label3'
- 'label1 label4 label4';
+ grid-auto-rows: auto;
+ grid-template-areas:
+ "Jacket tasGrid rGrid"
+ "Details Details Details";
margin: auto;
+ margin-bottom: 0.2em;
}
- .score-jacket {
+ h4.score-grid {
+ font-size: 5vw;
+ }
- background-color: #9EF6B5;
- grid-area: label1;
+ .fcfs-grid {
+ grid-area: FC-FS;
+ display: grid;
+ grid-auto-columns: min-content min-content;
+
+ grid-template-areas:
+ 'fc fs';
+
+ gap: 0px;
+ }
+
+ .score-jacket {
+ grid-area: Jacket;
display: block;
margin-left: auto;
margin-right: auto;
- max-width: 100%;
- width: 100%;
-
+ max-width: 75%;
+ width: 75%;
+
}
/* Please I really dont want to make a nested grid */
-.score-info-grid {
- display: grid;
- grid-template-columns: repeat(3, 1fr);
- grid-template-rows: repeat(3, 1fr);
- grid-gap: 10px;
- grid-template-areas:
- "DX-Score DX-Score DX-Score"
- "full-combo full-sync multi-place"
- ". . details";
-}
+ .score-info-grid {
+ grid-area: Details;
+ display: grid;
+ grid-template-columns: repeat(3, 0.5fr);
+ grid-template-rows: repeat(3, 0.5fr);
+ grid-gap: 10px;
+ grid-template-areas:
+ "timingTable timingTable"
+ "maxCombo maxSync";
+ }
+
+
}
.score-title {
-
- background-color: #D5BBCA;
- grid-area: label0;
-
+ grid-area: title;
}
.score-achivement {
- background-color: #ED69FD;
- grid-area: label2;
+ grid-area: achivement;
}
.score-grade {
-
- background-color: #9B5999;
- grid-area: label3;
+ grid-area: score-grade;
}
.score-info {
-
- background-color: #58B669;
grid-area: label4;
}
-/* Please I really dont want to make a nested grid */
-.score-info-grid {
- display: grid;
- grid-template-columns: repeat(3, min-content);
- grid-template-rows: repeat(3, min-content);
- grid-gap: 10px;
- grid-template-areas:
- "DX-Score DX-Score DX-Score"
- "full-combo full-sync multi-place"
- "details details details";
-}
.DX-Score {
- grid-area: DX-Score;
+ grid-area: DXs-Fast-Slow;
}
.score-jacket {
-
- background-color: #9EF6B5;
- grid-area: label1;
+ grid-area: Jacket;
display: block;
margin-left: auto;
margin-right: auto;
@@ -314,6 +345,61 @@ h4.profile {
}
-h4.DX-Score {
- font-size: 2em;
+#user-play-data {
+ object-fit: inherit;
+}
+
+img.sg-image {
+ width:17vw;
+ max-width: 125px;
+}
+
+img.fullCombo-image {
+ width:12vw;
+ max-width: 120px;
+}
+
+img.fullSync-image {
+ width:12vw;
+ max-width: 120px;
+}
+
+.fullCombo-image:nth-of-type(1) {
+ grid-area: fc;
+}
+
+.fullSync-image:nth-of-type(1) {
+ grid-area: fs;
+}
+
+.score-info-grid {
+ grid-area: Details;
+ display: grid;
+ grid-template-columns: repeat(3, 0.5fr);
+ grid-template-rows: repeat(3, 0.5fr);
+ grid-gap: 10px;
+ grid-template-areas:
+ "timingTable timingTable"
+ "maxCombo maxSync";
+}
+
+/* I really could'nt be asked to make css code, so i asked clyde instead. ty clyde. */
+
+table {
+ border-collapse: collapse;
+ width: 100%;
+}
+
+th, td {
+ border: 1px solid black;
+ padding: 8px;
+ text-align: left;
+}
+
+th {
+ background-color: #f2f2f2;
+}
+
+tr:nth-child(even) {
+ background-color: #dddddd;
}
\ No newline at end of file
diff --git a/readme.md b/readme.md
index a8f6f59..2287f47 100644
--- a/readme.md
+++ b/readme.md
@@ -25,6 +25,7 @@ in the public folder, the assets should look like this
\_ | - icon
| - jacket
| - metadata
+ | - uicon
```
Then, create the `/public/image/` folder. this will be where the images will be stored.
@@ -32,7 +33,9 @@ Then, create the `/public/image/` folder. this will be where the images will be
You'll also need the Game metadata, extracted using [SegaParser](https://dev.s-ul.net/Galexion/segaparser),
to get the game metadata. this is ***Nessasary*** for the interface to function.
+Tip: you'll need to extract both Common (FC, FS, and Rank) and streamed assets.
+you'll also need to go and create your own Grayscale version of FC and FS. SnS.
## Aqua
diff --git a/views/index.ejs b/views/index.ejs
index acc1869..330f027 100644
--- a/views/index.ejs
+++ b/views/index.ejs
@@ -23,11 +23,18 @@
- Issue Log:
+ Issue & Update Log:
+ Hello and welcome to the beta of the new score layout, apart of a bigger redo of the front end.
+
+ Changes:
+ - literally the whole score layout
+ - score grade will now switch between Text & Image depending on if you had imported them into your assets folder.
+
+ issues:
- Site Is Not Complete
- - Artemis does not Support Memorial Photos, though that is coming.
+ - Details dropdown does nothing. that is currently intended, as i haven't coded it in yet.
UI Jackets Have Now been fixed, please redl segapaser and rerun music.js.
diff --git a/views/log.ejs b/views/log.ejs
new file mode 100644
index 0000000..08cb955
--- /dev/null
+++ b/views/log.ejs
@@ -0,0 +1,32 @@
+<% var rootPath='../' ; %>
+<%- include(rootPath + 'templates/header.ejs' ); %>
+
+
+
MaiDXNet Dashboard
+ Total Users Registered: <%= params.totalUsers %>
+ Please Input your 20 Digit Access Code.
+
+
+
+
+
+ Please Note:
+
+
+ This is mainly a Demo of MaiMaiDXNet, and should not be used for actual play.
+
+ If Testing on your own card, please visit here to import your data from any other Water based Amusement Server.
+
+ Note that Some scores, Song Jackets, or other ammenitys are missing. this is completely normal.
+
+ Everything that was not supposed to be missing is now back. Please update any personal / production instances to the latest version.
+
+ For Up to date information, join our
Discord Server
+
+
+