diff --git a/.gitignore b/.gitignore index eaa75434..c57e2874 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ FFXIVClassic Map Server/bin/Debug/packets/wireshark packets/ FFXIVClassic Map Server/bin/ FFXIVClassic Map Server/obj/ +config.ini diff --git a/FFXIVClassic Map Server/Database.cs b/FFXIVClassic Map Server/Database.cs index e82f4e3e..dddeea59 100644 --- a/FFXIVClassic Map Server/Database.cs +++ b/FFXIVClassic Map Server/Database.cs @@ -1,5 +1,4 @@ -using FFXIVClassic_Lobby_Server.dataobjects; -using MySql.Data.MySqlClient; +using MySql.Data.MySqlClient; using Dapper; using Newtonsoft.Json; using System; @@ -8,13 +7,21 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using FFXIVClassic_Lobby_Server.common; -using FFXIVClassic_Map_Server.dataobjects.database; +using FFXIVClassic_Map_Server.dataobjects.chara.npc; +using FFXIVClassic_Map_Server.dataobjects.chara; +using FFXIVClassic_Map_Server.utils; +using FFXIVClassic_Lobby_Server.packets; +using FFXIVClassic_Map_Server.packets.send.player; +using FFXIVClassic_Lobby_Server.dataobjects; +using FFXIVClassic_Map_Server; +using FFXIVClassic_Map_Server.common.EfficientHashTables; namespace FFXIVClassic_Lobby_Server { class Database { + public static uint getUserIdFromSession(String sessionId) { uint id = 0; @@ -65,15 +72,15 @@ namespace FFXIVClassic_Lobby_Server } } - public static DBCharacter getCharacter(uint charId) + public static List getNpcList() { using (var conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) { - DBCharacter chara = null; + List npcList = null; try { conn.Open(); - chara = conn.Query("SELECT * FROM characters WHERE id=@CharaId", new { CharaId = charId }).SingleOrDefault(); + npcList = conn.Query("SELECT * FROM npc_list").ToList(); } catch (MySqlException e) { @@ -83,52 +90,503 @@ namespace FFXIVClassic_Lobby_Server conn.Dispose(); } - return chara; + return npcList; } } - public static DBAppearance getAppearance(uint charaId) - { - using (var conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) + public static void loadPlayerCharacter(Player player) + { + string query; + MySqlCommand cmd; + + using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) { - DBAppearance appearance = null; try { conn.Open(); - appearance = conn.Query("SELECT * FROM characters_appearance WHERE characterId=@CharaId", new { CharaId = charaId }).SingleOrDefault(); + + //Load basic info + query = @" + SELECT + name, + positionX, + positionY, + positionZ, + rotation, + actorState, + currentZoneId, + currentClassJob, + gcCurrent, + gcLimsaRank, + gcGridaniaRank, + gcUldahRank, + currentTitle, + guardian, + birthDay, + birthMonth, + initialTown, + tribe, + currentParty, + restBonus, + achievementPoints + FROM characters WHERE id = @charId"; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + player.displayNameId = 0xFFFFFFFF; + player.customDisplayName = reader.GetString(0); + player.oldPositionX = player.positionX = reader.GetFloat(1); + player.oldPositionY = player.positionY = reader.GetFloat(2); + player.oldPositionZ = player.positionZ = reader.GetFloat(3); + player.oldRotation = player.rotation = reader.GetFloat(4); + player.currentMainState = reader.GetUInt16(5); + player.zoneId = reader.GetUInt32(6); + player.charaWork.parameterSave.state_mainSkill[0] = reader.GetByte(7); + player.gcCurrent = reader.GetByte(8); + player.gcRankLimsa = reader.GetByte(9); + player.gcRankGridania = reader.GetByte(10); + player.gcRankUldah = reader.GetByte(11); + player.currentTitle = reader.GetUInt32(12); + player.playerWork.guardian = reader.GetByte(13); + player.playerWork.birthdayDay = reader.GetByte(14); + player.playerWork.birthdayMonth = reader.GetByte(15); + player.playerWork.initialTown = reader.GetByte(16); + player.playerWork.tribe = reader.GetByte(17); + player.playerWork.restBonusExpRate = reader.GetInt32(19); + player.achievementPoints = reader.GetUInt32(20); + } + } + + player.charaWork.parameterSave.state_mainSkillLevel = 49; + + /* + //Get level of our classjob + //Load appearance + query = @" + SELECT + baseId + FROM characters_appearance WHERE characterId = @charId"; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + + } + + } + */ + + //Get level of our classjob + //Load appearance + query = @" + SELECT + hp, + hpMax, + mp, + mpMax + FROM characters_parametersave WHERE characterId = @charId"; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + player.charaWork.parameterSave.hp[0] = reader.GetInt16(0); + player.charaWork.parameterSave.hpMax[0] = reader.GetInt16(1); + player.charaWork.parameterSave.mp = reader.GetInt16(2); + player.charaWork.parameterSave.mpMax = reader.GetInt16(3); + } + } + + //Load appearance + query = @" + SELECT + baseId, + size, + voice, + skinColor, + hairStyle, + hairColor, + hairHighlightColor, + eyeColor, + characteristics, + characteristicsColor, + faceType, + ears, + faceMouth, + faceFeatures, + faceNose, + faceEyeShape, + faceIrisSize, + faceEyebrows, + mainHand, + offHand, + head, + body, + hands, + legs, + feet, + waist, + leftFinger, + rightFinger, + leftEars, + rightEars + FROM characters_appearance WHERE characterId = @charId"; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + if (reader.GetUInt32(0) == 0xFFFFFFFF) + player.modelId = CharacterUtils.getTribeModel(player.playerWork.tribe); + else + player.modelId = reader.GetUInt32(0); + player.appearanceIds[Character.SIZE] = reader.GetByte(1); + player.appearanceIds[Character.COLORINFO] = (uint)(reader.GetUInt16(3) | (reader.GetUInt16(5) << 10) | (reader.GetUInt16(7) << 20)); + player.appearanceIds[Character.FACEINFO] = PrimitiveConversion.ToUInt32(CharacterUtils.getFaceInfo(reader.GetByte(8), reader.GetByte(9), reader.GetByte(10), reader.GetByte(11), reader.GetByte(12), reader.GetByte(13), reader.GetByte(14), reader.GetByte(15), reader.GetByte(16), reader.GetByte(17))); + player.appearanceIds[Character.HIGHLIGHT_HAIR] = (uint)(reader.GetUInt16(6) | reader.GetUInt16(4) << 10); + player.appearanceIds[Character.VOICE] = reader.GetByte(2); + player.appearanceIds[Character.WEAPON1] = reader.GetUInt32(18); + player.appearanceIds[Character.WEAPON2] = reader.GetUInt32(19); + player.appearanceIds[Character.HEADGEAR] = reader.GetUInt32(20); + player.appearanceIds[Character.BODYGEAR] = reader.GetUInt32(21); + player.appearanceIds[Character.LEGSGEAR] = reader.GetUInt32(22); + player.appearanceIds[Character.HANDSGEAR] = reader.GetUInt32(23); + player.appearanceIds[Character.FEETGEAR] = reader.GetUInt32(24); + player.appearanceIds[Character.WAISTGEAR] = reader.GetUInt32(25); + player.appearanceIds[Character.R_EAR] = reader.GetUInt32(26); + player.appearanceIds[Character.L_EAR] = reader.GetUInt32(27); + player.appearanceIds[Character.R_FINGER] = reader.GetUInt32(28); + player.appearanceIds[Character.L_FINGER] = reader.GetUInt32(29); + } + + } + + //Load Status Effects + query = @" + SELECT + statusId, + expireTime + FROM characters_statuseffect WHERE characterId = @charId"; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + int count = 0; + while (reader.Read()) + { + player.charaWork.status[count] = reader.GetUInt16(0); + player.charaWork.statusShownTime[count] = reader.GetUInt32(1); + } + } + + //Load Chocobo + query = @" + SELECT + hasChocobo, + hasGoobbue, + chocoboAppearance, + chocoboName + FROM characters_chocobo WHERE characterId = @charId"; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + player.hasChocobo = reader.GetBoolean(0); + player.hasGoobbue = reader.GetBoolean(1); + player.chocoboAppearance = reader.GetByte(2); + player.chocoboName = reader.GetString(3); + } + } + + //Load Timers + query = @" + SELECT + thousandmaws, + dzemaeldarkhold, + bowlofembers_hard, + bowlofembers, + thornmarch, + aurumvale, + cutterscry, + battle_aleport, + battle_hyrstmill, + battle_goldenbazaar, + howlingeye_hard, + howlingeye, + castrumnovum, + bowlofembers_extreme, + rivenroad, + rivenroad_hard, + behests, + companybehests, + returntimer, + skirmish + FROM characters_timers WHERE characterId = @charId"; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + for (int i = 0; i < player.timers.Length; i++) + player.timers[i] = reader.GetUInt32(i); + } + } + + //Load Hotbar + query = @" + SELECT + hotbarSlot, + commandId, + recastTime + FROM characters_hotbar WHERE characterId = @charId AND classId = @classId"; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + cmd.Parameters.AddWithValue("@classId", player.charaWork.parameterSave.state_mainSkill[0]); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + int index = reader.GetUInt16(0); + player.charaWork.command[index+32] = reader.GetUInt32(1); + player.charaWork.parameterSave.commandSlot_recastTime[index] = reader.GetUInt32(2); + } + } + + //Load Scenario Quests + query = @" + SELECT + slot, + questId + FROM characters_quest_scenario WHERE characterId = @charId"; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + int index = reader.GetUInt16(0); + player.playerWork.questScenario[index] = 0xA0F00000 | reader.GetUInt32(1); + } + } + + //Load Local Guildleves + query = @" + SELECT + slot, + questId, + abandoned, + completed + FROM characters_quest_guildleve_local WHERE characterId = @charId"; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + int index = reader.GetUInt16(0); + player.playerWork.questGuildleve[index] = 0xA0F00000 | reader.GetUInt32(1); + } + } + + //Load Regional Guildleve Quests + query = @" + SELECT + slot, + guildleveId, + abandoned, + completed + FROM characters_quest_guildleve_regional WHERE characterId = @charId"; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + int index = reader.GetUInt16(0); + player.work.guildleveId[index] = reader.GetUInt16(1); + player.work.guildleveDone[index] = reader.GetBoolean(2); + player.work.guildleveChecked[index] = reader.GetBoolean(3); + } + } + + //Load NPC Linkshell + query = @" + SELECT + npcLinkshellId, + isCalling, + isExtra + FROM characters_npclinkshell WHERE characterId = @charId"; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + int npcLSId = reader.GetUInt16(0); + player.playerWork.npcLinkshellChatCalling[npcLSId] = reader.GetBoolean(1); + player.playerWork.npcLinkshellChatExtra[npcLSId] = reader.GetBoolean(2); + } + } + } catch (MySqlException e) - { - } + { Console.WriteLine(e); } finally { conn.Dispose(); } - - return appearance; } } - public static DBStats getCharacterStats(uint charaId) + public static SubPacket getLatestAchievements(Player player) { - using (var conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) + uint[] latestAchievements = new uint[5]; + using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) { - DBStats stats = null; try { conn.Open(); - stats = conn.Query("SELECT * FROM characters_stats WHERE characterId=@CharaId", new { CharaId = charaId }).SingleOrDefault(); + + //Load Last 5 Completed + string query = @" + SELECT + characters_achievements.achievementId FROM characters_achievements + INNER JOIN gamedata_achievements ON characters_achievements.achievementId = gamedata_achievements.achievementId + WHERE characterId = @charId AND rewardPoints <> 0 ORDER BY timeDone LIMIT 5"; + + MySqlCommand cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + int count = 0; + while (reader.Read()) + { + uint id = reader.GetUInt32(0); + latestAchievements[count++] = id; + } + } } catch (MySqlException e) - { - } + { Console.WriteLine(e); } finally { conn.Dispose(); } - - return stats; } + + return SetLatestAchievementsPacket.buildPacket(player.actorId, latestAchievements); + } + + public static SubPacket getAchievementsPacket(Player player) + { + SetCompletedAchievementsPacket cheevosPacket = new SetCompletedAchievementsPacket(); + + using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) + { + try + { + conn.Open(); + + string query = @" + SELECT packetOffsetId + FROM characters_achievements + INNER JOIN gamedata_achievements ON characters_achievements.achievementId = gamedata_achievements.achievementId + WHERE characterId = @charId AND timeDone IS NOT NULL"; + + MySqlCommand cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charId", player.actorId); + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + uint offset = reader.GetUInt32(0); + + if (offset < 0 || offset >= cheevosPacket.achievementFlags.Length) + { + Log.error("SQL Error; achievement flag offset id out of range: " + offset); + continue; + } + cheevosPacket.achievementFlags[offset] = true; + } + } + } + catch (MySqlException e) + { Console.WriteLine(e); } + finally + { + conn.Dispose(); + } + } + + return cheevosPacket.buildPacket(player.actorId); + } + + public static void loadZones(Efficient32bitHashTable zoneList) + { + int count = 0; + using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) + { + try + { + conn.Open(); + + string query = @" + SELECT + id, + regionId, + zoneName, + dayMusic, + nightMusic, + battleMusic, + isInn, + canRideChocobo, + canStealth, + isInstanceRaid + FROM server_zones + WHERE zoneName IS NOT NULL"; + + MySqlCommand cmd = new MySqlCommand(query, conn); + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) { + Zone zone = new Zone(reader.GetUInt32(0), reader.GetString(2), reader.GetUInt16(1), reader.GetUInt16(3), reader.GetUInt16(4), reader.GetUInt16(5), reader.GetBoolean(6), reader.GetBoolean(7), reader.GetBoolean(8), reader.GetBoolean(9)); + zoneList.Add(zone.actorId, zone); + count++; + } + } + } + catch (MySqlException e) + { Console.WriteLine(e); } + finally + { + conn.Dispose(); + } + } + + Log.info(String.Format("Loaded {0} zones.", count)); } } diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj index 4523e232..42f3674e 100644 --- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj +++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj @@ -41,6 +41,9 @@ ..\packages\Dapper.1.42\lib\net45\Dapper.dll True + + ..\packages\NLua.1.3.2.1\lib\net45\KeraLua.dll + ..\packages\MySql.Data.6.9.7\lib\net45\MySql.Data.dll True @@ -49,6 +52,9 @@ ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll True + + ..\packages\NLua.1.3.2.1\lib\net45\NLua.dll + @@ -58,55 +64,65 @@ + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + + + + + + - - - + + @@ -119,8 +135,11 @@ + + + @@ -130,6 +149,8 @@ + + @@ -162,8 +183,6 @@ - - @@ -182,14 +201,18 @@ + - + - + + + + @@ -197,6 +220,10 @@ + + +xcopy /s /y "D:\Coding\FFXIV Related\ffxiv-classic-map-server\packages\NLua.1.3.2.1\lib\native\*.*" "$(TargetDir)" +