# Zadanie 4 - Návrh databázy pre online RPG hru
**Autori:** Rastislav Balcerčík, Jakub Sorád
**Použité nástroje:**
* **draw.io** - návrh logického modelu
* **MySQL Workbench** - návrh fyzického modelu
# Opis riešenia
## Logický model
V logickom modeli sme zadefinovali štruktúru dát relačnej databázy pomocou entít, ktoré obsahujú atribúty bližšie špecifikujúce konkrétnu entitu. Entity, ktoré medzi sebou majú vzťah sme v logickom modeli znázornili pomocou väzby a jednoduchým popisom vzťahu. Pri jednotlivých vzťahoch sme vhodne zobrazili kardinality.
## Fyzický model
Používateľ, ktorý chce hrať hru sa musí najprv zaregistrovať. Hra mu ponúka tri možnosti a to registráciu cez e-mail, facebook a google. Možnosť, ktorú si používateľ zvolí, je uložená v tabuľke **`Users`** v stĺpci `registration_type`. Stav overovania účtu je uložený v stĺpci `verified`.
Používatelia vedia vytvárať priateľstvá. Všetky vzťahy medzi používateľmi sú reprezentované v tabuľke **`Relationships`**, kde stĺpec `userOneID` je cudzí kľúč na používateľa, ktorý priateľstvo inicializoval (poslal žiadosť) a v stĺpci `userTwoID` je cudzí kľúč na používateľa, ktorému žiadosť prišla. Status vzťahu môže nadobúdať hodnoty:
* `accepted`
* `declined`
* `pending`
* `ignored`
Hráč si vie svoje vzťahy a ich status zobraziť v UI hry vyfiltrovaním všetkých záznamov z tabuľky **`Relationships`**, kde sa `userOneID` alebo `userTwoID` zhoduje s jeho identifikačným číslom.
Každý hráč si vie vytvoriť svoj vlastný tím, do ktorého vie pozývať ďalších hráčov alebo sa vie pripojiť do jedného z tímov po prijatí pozvánky od tímového lídra. Tím, do ktorého hráč patrí je reprezentovaný stĺpcom `guildID`, ktorý referencuje ID tímu.
Každá pozvánka je zaznamenaná v tabuľke **`InviteList`**, kde sa v stĺpci `guildID` nachádza cudzí kľúč na identifikačné číslo tímu z tabuľky **`Guilds`** a v stĺpci `userID` je ID používateľa, ktorý pozvánku dostal. Status pozvánky sa nachádza v stĺpci `status` a nadobúda hodnoty:
* `accepted`
* `declined`
* `pending`
Ak sa hráč nachádza v niektorom z tímov, má možnosť z neho odísť. V tom prípade sa nastaví hodnota `guildID` v zázname používateľa v tabuľke **`Users`** na hodnotu `null`.
Do tabuľky **`Chat`** sa ukladajú záznamy o každej poslanej správe. Každý hráč vie kontaktovať iného hráča alebo tím. Adresáta správy vieme rozoznať na základe stĺpcov `receiverUserID` a `receiverGuildID`, kde sa nachádzajú cudzie kľúče na hráča resp. tím, ktorý správu prijal. Ak je adresátom správy hráč, tak sa stĺpec pre ID tímu nastaví na `null` a naopak. Záznam ďalej obsahuje stĺpce `senderID`, ktorý reprezentuje ID používaľa, ktorý správu poslal, `message` obsahuje text správy a `senderAt` predstavuje čas, kedy bola správa odoslaná.
Ak je hodnota stĺpca `status` v tabuľke **`Relationships`** nastavená na `ignored`, tak správa sa v UI hry adresátovi nezobrazí. Správa je však zaznamenaná v databáze, vďaka čomu ju je možné neskôr použiť pri odôvodnení zablokovania hráča za zlé správanie.
Každý hráč môže vlastniť viacero postáv. Každá postava je reprezentovaná záznamom v tabuľke **`Characters`**. Každá postava má svoje jedinečné ID a obsahuje aj cudzí kľúč na tabuľku **`Users`**, aby bolo jasné, kto danú postavu vlastní a k akému účtu patrí. Progress v hre je zaznamenávaný v stĺpcoch `experience`, kde sa nachádzajú body skúseností postavy a v stĺpci `level` sa nachádza úroveň postavy, ktorá je počítaná na základe bodov skúseností.
Počet bodov skúseností, ktoré je nutné získať na to aby postava pokročila na vyšší level je uložený v tabuľke **`Levels`**, kde primárny kľúč je číslo úrovne a `experienceRequired` je počet skúsenostných bodov na získanie príslušnej úrovne. Postava sa v hre stretáva len s príšerami, ktoré majú úroveň v podobnom rozsahu ako je úroveň postavy.
Údaje o atribútoch ako sú zdravie, útok a obrana sa nachádzajú v stĺpcoch `health`, `attack`, `defense`.
Každá z postáv môže mať jednu z viacerých rol, každá rola je repzerentovaná záznamom v tabuľke **`roles`**, kde názov roly sa nachádza v stĺpci `name`. Každá z rol získava atribúty inak, napr. bojovník má viac bodov zdravia ako mág a ten má naopak viac bodov poškodenia, preto sme v zázname každej roly pridali stĺpce `healthIncrease`, `attackIncrease` a `defenseIncrease`, ktoré reprezentujú ako sa atribúty každou novou úrovňou zmenia. Napr. ak je v stĺpci `healthIncrease` hodnota 5, postave sa na každej úrovni zvýši počet bodov zdravia o 5%.
Každej role prislúchajú schopnosti, ktoré sú uložené v tabuľke **`Spells`**. Každá schopnosť obsahuje cudzí kľúč `roleID` na tabuľku **`Roles`**, aby bolo jednoznačne určené, ktorá rola túto schopnosť používa. Každá zo schopností obsahuje stĺpec `damage`, v ktorom sa nachádza hodnota koľko bodov poškodenia daná schopnosť dáva protivníkovi. K výslednému poškodeniu sa následne ešte pripočítava hodnota zo stĺpca `attack` postavy. V stĺpci `cooldown` sa nachádza číselná hodnota v sekundách o tom, ako často môže postava použíť danú schopnosť.
Schopnosti sa každá postava učí postupne a je nutné ich odomykať. Stav schopnosti či je schopnosť naučená sa nachádza v stĺpci `learned` a údaj o tom či je odomknutá alebo nie sa nachádza v stĺpci `unlocked`. Na to aby postava odomkla schopnosť je nutné mať naučené predošlé schopnosti v strome schopností a musí sa nachádzať na úrovni, ktorá je požadovaná na odomknutie schopnosti.
Údaj o schopnosti, ktorú je nutné mať naučenú aby postava odomkla ďalšiu schopnosť sa nachádza v stĺpci `requiredSpellID`, ktorý obsahuje cudzí kľúč na inú schopnosť z tej istej tabuľky. Ak je táto predošlá schopnosť naučená, resp. hodnota v stĺpci `learned` je true a postava má rovnakú alebo vyššiu úroveň ako hodnota v stĺpci `requiredLevel`, tak sa hodnota `unlocked` nastaví na true a postava má možnosť naučiť sa ďalšiu schopnosť.
V hre sa nachádza množstvo príšer, ale aj priateľských NPC, preto má každé NPC v stĺpci `npcType` zapísaný údaj jeho type. `npcType` nadobúda hodnoty `enemy` pre nepriateľské NPC, `friendly` pre priateľské alebo neutrálne NPC a `boss` pre hlavného nepriateľa v hre. Všetky tieto NPC sú uložené v tabuľke **`NPCs`**.
Podobne ako postava tak aj NPC obsahuje údaje o mene, úrovni, bodoch zdravia, útoku a obrany. Tie sa nachádzajú v stĺpcoch `npcName`, `level`, `health`, `attack` a `defense`. Niektoré nepriateľské NPC sú však zamknuté a postava musí najskôr zabiť iné NPC, ktoré odomkne ďalšie. Každé NPC preto obsahuje stĺpce `wasKilled`, v ktorom sa nachádza údaj o tom či postava dané NPC zabila a `unlocked`, či má postava k danému NPC prístup. Hodnota v stĺpci `unlocked` sa nastavuje podľa toho, či NPC referencované v stĺpci `requiredNPC` bolo zabité, resp. má hodnotu v stĺpci `wasKilled` nastavenú na true.
Ak postava porazí niektoré NPC, získava skúsenostné body. Každé NPC má v stĺpci `experienceGiven` hodnotu o tom, koľko skúsenostných bodov sa pripočíta do stĺpca `experience` postavy.
Všetky udalosti, ktoré sa stali počas boja medzi nepriateľským NPC a postavou sa ukladajú do tabuľky **`EventList`**. Každá udalosť obsahuje údaje o udelenom a prijatom poškodení postavy v stĺpcoch `damageDealt` a `damageGiven`. Aby bolo možné rozlíšiť akú schopnosť postava použila v stĺpci `usedSpellID` sa nachádza referencia na ID schopnosti. Každá udalosť obsahuje aj časovú známku, ktorá je uložená v stĺpci `time`.
Aby bolo jedoznačne rozlíšíteľné v ktorom súboji sa daná udalosť stala, tak v stĺpci `combatID` sa nachádza referencia na súboj. Každý súboj obsahuje referenciu na príšeru, s ktorou postava bojovala a to v stĺpci `npcID`. Ak bola príšera porazená, tak postava získava skúsenostné body, preto sa v tabuľke **`Combats`** nachádza aj tento údaj a to v stĺpci `experienceEarned`.
Každý záznam v tabuľke **`Combats`** obsahuje aj stĺpec `combatLogID`, ktorý ukazuje na tabuľku **`CombatLogs`**. Vďaka tejto referencii vieme všetky súboje, v ktorých sa postava nachádzala spojiť s jediným záznamom, o ktorom bude mať postava vedomosť, vďaka stĺpcu `combatLogID` v tabuľke **`Characters`**. Vyhodnocovanie štatistík pre každého z hráčov bude kvôli tomu jednoduchšie.
Postava môže počas hry plniť rôzne úlohy. Záznamy o úlohách sú uložené v tabuľke **`Quests`**. Každá z úloh má svoj názov, a rôzne požiadavky na to aby bola splnená. Obidve tieto hodnoty sú uložené v stĺpoch `questName` a `tasks`. Podobne ako pri schopnostiach alebo nepriateľských príšerách aj niektoré úlohy je najprv potrebné odomknúť splnením predošlej úlohy. V stĺpci `requiredQuestID` je cudzí kľúč na rovnakú tabuľku **`Quests`**, ak táto predošlá úloha má v stĺpci `wasCompleted` hodnotu true, je možné odomknúť nasledujúcu úlohu.
Úlohu je možné prijať u niektorej z priateľských NPC. O tom, ktoré NPC zadáva úlohu ukladáme informácie v tabuľke **`QuestGivers`** . Každý zadávač úlohy je označený v stĺpci `npcID` aby bolo jednoznačne určené, ktoré priateľské NPC zadáva túto úlohu. Referencia na úlohu, ktorú NPC zadáva sa nachádza v stĺpci `questID`.
Po splnení úlohy postava získava skúsenostné body, ich počet je uložený v stĺpci `experience` a v niektorých úlohách je možné získať aj predmet. V stĺpci `dropsItemID` sa nachádza cudzí kľúč na tabuľku **`Items`** a práve tento predmet môže postava po splnení úlohy získať.
Všetky predmety majú svoje záznamy uložené v tabuľke **`Items`**. Každý z predmetov má svoj názov uložený v stĺpci itemName. Každý predmet môže po jeho použití pridávať niektoré z atribútov postavy. Atribúty, ktoré predmet postave pridáva sú uložené v stĺpcoch `healthIncrease`, `attackIncrease` a `defenseIncrease`. Na to aby mohla postava predmet nosiť alebo použiť je nutné aby mala vyššiu úroveň ako je úroveň predmetu, ktorá je uložená v stĺpci `itemLevel`. Predmet sa môže používaním opotrebovať, preto sme do tabuľky **`Items`** pridali aj stĺpec `durability`, ktorý predstavuje ako je na tom predmet s životnosťou, číslo sa pohybuje od 100 (nový) až po 0 (opotrebovaný).
Každá z postáv má svoj vlastný inventár, do ktorého si ukladá predmety, ktoré počas hry nazbierala. Inventáre sú uložené v tabuľke **`Inventories`** a každý záznam obsahuje stĺpec `characterID`, aby bolo jasné, ktorej postave daný inventár patrí. Každý inventár je možné postupne plnením úloh, alebo dosahovaním vyšších úrovni zväčšovať. Preto má každá postava v inventári len miesto pre niekoľko predmetov. Táto hodnota je uložená v stĺpci `slots`. Všetky nazbierané predmety sú uložené v tabuľke **`LootedItems`**, kde každý záznam obsahuje stĺpec `itemID`, aby bolo jasné o ktorý predmet ide a `inventoryID` aby bolo určené, v ktorom inventári sa nachádza.
Niektoré predmety ako sú napr. helma, brnenie a pod. si môže postava nasadiť. Každá postava má rovnaký počet miest, kde si môže predmety nasadiť a každý z týchto "slotov" je uložený v tabuľke **`EquipmentSlots`** a obsahuje stĺpec `itemID`, ktorý predstavuje referenciu, ktorý predmet je na tomto mieste nasadený. Aby bolo jednoznačne určené, ktorá postava má tento predmet nasadený, tabuľka obsahuje aj referenciu na postavu v stĺpci `characterID`.
Veľmi dôležitým prvkom v našej hre je mapa, na ktorej sa všetko odohráva. Mapa je rozdelená na viacero lokácií, do ktorých sa postava postupne počas hry môže dostať. Všetky lokácie sú uložené v tabuľke **`Locations`** a obsahuje hodnotu `locationName`, v ktorej je uložený názov lokácie. Každá postava má v stĺpci `locationUnlockedID` referenciu na lokáciu, ktorú má odomknutú. Lokácie sa odomykajú postupne, takže ak má postava odomknutú lokáciu s číslom napr. 5, má tým pádom otvorené aj všetky lokácie s nižším ID (1,2,3,4).
Postavy, NPC a dokonca aj Itemy sa môžu nachádzať v rôznych lokáciách. Preto každá z tabuliek **`Characters`**, **`NPCs`** a **`Items`** obsahuje aj informáciu o tom, v ktorej lokácii sa momentálne nachádza a to v stĺpci `locationID`. Aby bolo jednoznačné na ktorom mieste v tejto lokácii sa postava, NPC alebo predmet nachádza, majú všetky tabuľky aj stĺpce `xPosition`, `yPosition`, ktoré predstavujú súradnice.
### Tabuľky vo fyzickom modeli
**Users**
`userID` - Primárny kľúč
`userName` - Reprezentuje užívateľské meno
`mail` - Email, ktorým je registrovaný
`passwordHash` - Používateľove zahešované heslo
`verified` - Či je verifikovaný (hodnoty True, False)
`registrain_type` - Akým spôsobom je zaregistrovaný (email, Facebook, Google)
`guildID` - ID tímu, v ktorom sa môže nachádzať. Ak nie je v tíme alebo opustil tím, hodnota je null
**Relationships**
`relationshipID` - Primárny kľúč
`userOneID` - Cuzdí kľúč na tabuľku **`Users`**. Používateľ, ktorý žiadosť odoslal
`userTwoID` - Cudzí kľúč na tabuľku **`Users`**. Používateľ, ktorému žiadosť prišla.
`status` - Status vzťahu medzi dvoma používateľmi
**Guilds**
`guildID` - Primárny kľúč
`guildLeaderID` - Cudzí klúč na tabuľku **`Users`**. Používateľ, ktorý je líder tímu
`guildName` - meno tímu
**InviteList**
`inviteID` - Primárny kľúč
`guildID` - Cudzí kľúč na tabuľku **`Guilds`**. Vieme k akému tímu sa konkrétny záznam viaže
`userID` - Cudzí kľúč na tabuľku **`Users`**. Vieme k akému úžívateľovi sa záznam viaže
`status` - Status pozvánky do tímu
**Chat**
`messageID` - Primárny kľúč
`senderID` - Cudzí kľúč na tabuľku **`Users`**. ID používateľa, ktorý posiela správu
`receiverUserID` - Cudzí kľúč na tabuľku **`Users`**. ID používateľa, ktorý príjma správu
`receiverGuildID` - Cudzí kľúč na tabuľku **`Guilds`**. ID tímu, ktorá príjma správu
`message` - obsah samotnej správy
`sendedAt` - časový údaj, kedy bola správa poslaná/vytvorená
**Characters**
`characterID` - Primárny kľúč
`userID` - Cudzí kľúč na tabuľku **`Users`**. Vieme k akéj postave sa viaže.
`charName` - meno postavy
`health` - údaje o živote
`attack` - údaj o útoku
`defense` - údaj o obrane
`level` - level postavy
`roleID` - Cudzí kľúč na tabuľku **`Roles`**. Postava má určitú rolu
`experience` - body skúsenosti
`locationUnlockedID` - Cudzí kľúč na tabuľku **`Locations`**. Postava sa nachádza v určitej lokácií, ktorú má odomknutú a tiež aj všetky predošlé lokácie.
`xPosition` - x-ová pozicia v lokácii, kde sa postava nachádza
`yPosition` - y-ová pozicia v lokácii, kde sa postava nachádza
`combatLogID` - Cudzí kľúč na tabuľku **`CombatLogs`**. Každá postava tam má záznam, kde sa nachádzajú štatistiky o súbojoch
**Roles**
`roleID` - Primárny kľúč
`name` - meno role
`healthIncrease` - hodnota (v %) o koľko sa každým levelom zvýšia body zdravia
`attackIncrease` - hodnota (v %) o koľko sa každým levelom zvýšia body útoku
`defenseIncrease` - hodnota (v %) o koľko sa každým levelom zvýšia body obrany
**Spells**
`spellID` - Primárny kľúč
`roleID` - Cudzí kľúč na tabuľku **`Roles`**. Každá rola ma svoje spelly.
`unlocked` - Či je daný spell odomknutý (True/False)
`damage` - Hodnota poškodenia, ktoré daný spell spôsobí
`cooldown` - Čas, ktorý je potreba na znovupoužitie spellu
`requiredLevel` - Potrebný level nato, aby bol spell k odomknutý.
`requiredSpellID` - Cudzí kľúč na tabuľku **`Spells`**. Nato, aby mohol by odomknutý aktuálny spell, tak v tom spelle, na ktorý tento kľúč ukazuje už musí byť `learned` na hodnote True
`learned` - Či má postava spell naučený (True/False)
**Locations**
`locationID` - Primárny kľúč
`locationName` - Názov lokácie
**Levels**
`levelNumberID` - Primárny kľúč
`experienceRequired` - Potrebné body skúseností k dosiahnutiu tohto levela
**EventLists**
`eventID` - Primárny kľúč
`damageDealt` - Koľko poškodenia utrpela postava v danej udalosti
`damageTaken` - Koľko poškodenia postava dala NPCčku v danej udalosti
`usedSpellID` - ID použitého spellu v danej udalosti
`time` - Časový údaj, kedy udalosť nastala
`combatID` - Cudzí kľúč na tabuľku **`Combats`**. Jeden boj može mať veľa udalostí a o každej z nich vieme dôležité informácie
**Combats**
`combatID` - Primárny kľúč
`npcID` - Cudzí kľúč na tabuľku **`NPCs`**. V rámci súboja vieme presne s akým NPCčkom postava bojovala.
`locationID` - ID lokácie, kde sa súboj odohrával
`experienceEarned` - Získané body skúseností v boji
`combatLogID` - Cudzí kľúč na tabuľku **`CombatLogs`**. Tento súboj bude dostupný v rámci všetkých súbojov.
**CombatLogs**
`combatLogID` - Primárny kľúč
**NPCs**
`npcID` - Primárny kľúč
`npcName` - meno NPCčka
`npcType` - typ NPC. Friendly, enemy a boss
`health` - body zdravia
`attack` - údaj o útoku
`defense` - údaj o obrane
`level` - level NPC
`unlocked` - Či je NPC odomknuté a postava s ňou môže interagovať (True/False)
`experienceGiven` - Koľko bodov skúseností postava dostane ak dané NPC zabije.
`locationID` - Cudzí kľúč na tabuľku **`Locations`**
`xPosition` - x-ová pozicia v lokácii, kde sa NPC nachádza
`yPosition` - y-ová pozicia v lokácii, kde sa NPC nachádza
`dropsItemID` - Cudzí kľúč na tabuľku **`Items`**. NPC dropne určitý item s konkrétnym ID
`requiredNPCID` - Cudzí kľúč na tabuľku **`NPCs`**. Predošlé NPC, ktoré bolo nutné zabiť, aby sme postava mohla bojovať s týmto aktuálnym NPC
`wasKilled` - Či už bolo toto NPC zabité aspoň raz, nech môžeme odomykať ďalšie NPC.
**QuestGivers**
`ID` - Primárny kľúč
`npcID` - Cudzí kľúč na tabuľku **`NPCs`**. Vieme, ktoré friendly NPC nám dáva quest.
`questID` - Cudzí kľúč na tabuľku **`Quests`**. Friendly NPC dá postave špefický quest.
**Quests**
`questID` - Primárny kľúč
`questName` - Pomenovanie questu
`task` - hlavná úloha a cieľ questu
`unlocked` - Či je daný quest odomknutý (True/False)
`dropsItemID` - Cudzí kľúč na tabuľku **`Items`**. Informácia, aký predmet dostaneme po splnený úlohy
`experience` - Počet skúsenostných bodov, ktoré postava dostane po splnení úlohy
`requiredQuestID` - Cudzí kľúč na tabuľku **`NPCs`**. Aký predošlý quest je nutné splniť nato, aby postava mohla plniť aktuálny quest
**Items**
`itemID` - Primárny kľúč
`itemName` - Názov predmetu
`durability` - Stav predmetu 0 (opotrebovaný) - 100 (nový)
`healthIncrease` - Predstavuje o koľko sa navýši počet bodov zdravia postavy po nasadení/použití predmetu
`attackIncrease` - Predstavuje o koľko sa navýši počet bodov útoku postavy po nasadení/použití predmetu
`defenseIncrease` - Predstavuje o koľko sa navýši počet bodov obrany postavy po nasadení/použití predmetu
`locationID` - Cudzí kľúč na tabuľku **`Locations`**. V ktorej lokácii sa predmet nachádza
`xPosition` - Predstavuje x-ovú súradnicu na mape, kde sa predmet nachádza
`yPosition` - Predstavuje y-ovú súradnicu na mape, kde sa predmet nachádza
`itemLevel` - Úroveň, ktorú musí postava dosiahnuť, aby mohla predmet použiť/nasadiť
**Inventories**
`ID` - Primárny kľúč
`characterID` - Cudzí kľúč na tabuľku **`Characters`**. Aby bolo jasné ktorej postave patrí inventár
`slots` - počet všetkých slotov v inventári
**EquipmentSlots**
`equipmentSlotID` - Primárny kľúč
`slotName` - názov slotu
`itemID` - Cudzí kľúč na tabuľku **`Items`**. Predmet, ktorý má postava nasadený v danom slote