From b68d13ea7fe841d44285f13f0d516955c4d343f0 Mon Sep 17 00:00:00 2001 From: Filip Maj Date: Sat, 2 Apr 2016 17:56:01 -0400 Subject: [PATCH 01/21] Cleaned up the lua calls and renamed "onInstantiation" to "init". Added a "onSpawn" callback but still working on it. Added the "ActorSpecialGraphicPacket" and functions to use it. --- .../FFXIVClassic Map Server.csproj | 1 + .../actors/chara/Character.cs | 7 ++ .../actors/chara/npc/Npc.cs | 2 +- .../actors/chara/player/Player.cs | 11 +++ .../dataobjects/ConnectedPlayer.cs | 1 + FFXIVClassic Map Server/lua/LuaEngine.cs | 92 ++++++++++--------- .../send/Actor/ActorSpecialGraphicPacket.cs | 36 ++++++++ 7 files changed, 108 insertions(+), 42 deletions(-) create mode 100644 FFXIVClassic Map Server/packets/send/Actor/ActorSpecialGraphicPacket.cs diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj index 27a9891d..2ecccff3 100644 --- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj +++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj @@ -134,6 +134,7 @@ + diff --git a/FFXIVClassic Map Server/actors/chara/Character.cs b/FFXIVClassic Map Server/actors/chara/Character.cs index 8ada9422..dd5f5266 100644 --- a/FFXIVClassic Map Server/actors/chara/Character.cs +++ b/FFXIVClassic Map Server/actors/chara/Character.cs @@ -81,6 +81,13 @@ namespace FFXIVClassic_Map_Server.Actors return SetActorIdleAnimationPacket.buildPacket(actorId, playerActorId, animationId); } + public void setQuestIcon(Player player, bool hasIcon) + { + ActorSpecialGraphicPacket.buildPacket(player.actorId, actorId, hasIcon ? ActorSpecialGraphicPacket.QUEST : 0x0).debugPrintSubPacket(); + //player.queuePacket(ActorSpecialGraphicPacket.buildPacket(player.actorId, actorId, hasIcon ? ActorSpecialGraphicPacket.QUEST : 0x0)); + + } + } } diff --git a/FFXIVClassic Map Server/actors/chara/npc/Npc.cs b/FFXIVClassic Map Server/actors/chara/npc/Npc.cs index 9e43c677..f84b4e24 100644 --- a/FFXIVClassic Map Server/actors/chara/npc/Npc.cs +++ b/FFXIVClassic Map Server/actors/chara/npc/Npc.cs @@ -50,7 +50,7 @@ namespace FFXIVClassic_Map_Server.Actors List lParams; Player player = Server.GetWorldManager().GetPCInWorld(playerActorId); - lParams = LuaEngine.doActorOnInstantiate(player, this); + lParams = LuaEngine.doActorInstantiate(player, this); if (lParams == null) { diff --git a/FFXIVClassic Map Server/actors/chara/player/Player.cs b/FFXIVClassic Map Server/actors/chara/player/Player.cs index 9ef1b188..bcb44705 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Player.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Player.cs @@ -965,6 +965,17 @@ namespace FFXIVClassic_Map_Server.Actors return null; } + public Quest getQuest(string name) + { + for (int i = 0; i < questScenario.Length; i++) + { + if (questScenario[i] != null && questScenario[i].actorName.Equals(name)) + return questScenario[i]; + } + + return null; + } + public bool hasQuest(uint id) { for (int i = 0; i < questScenario.Length; i++) diff --git a/FFXIVClassic Map Server/dataobjects/ConnectedPlayer.cs b/FFXIVClassic Map Server/dataobjects/ConnectedPlayer.cs index 455448dc..567aec3c 100644 --- a/FFXIVClassic Map Server/dataobjects/ConnectedPlayer.cs +++ b/FFXIVClassic Map Server/dataobjects/ConnectedPlayer.cs @@ -2,6 +2,7 @@ using FFXIVClassic_Lobby_Server.common; using FFXIVClassic_Lobby_Server.packets; using FFXIVClassic_Map_Server.Actors; +using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.packets.send.actor; using System; using System.Collections.Generic; diff --git a/FFXIVClassic Map Server/lua/LuaEngine.cs b/FFXIVClassic Map Server/lua/LuaEngine.cs index a9d18ee5..7a7603bd 100644 --- a/FFXIVClassic Map Server/lua/LuaEngine.cs +++ b/FFXIVClassic Map Server/lua/LuaEngine.cs @@ -31,7 +31,7 @@ namespace FFXIVClassic_Map_Server.lua UserData.RegistrationPolicy = InteropRegistrationPolicy.Automatic; } - public static List doActorOnInstantiate(Player player, Actor target) + public static List doActorInstantiate(Player player, Actor target) { string luaPath; @@ -39,14 +39,10 @@ namespace FFXIVClassic_Map_Server.lua { luaPath = String.Format(FILEPATH_NPCS, target.zoneId, target.getName()); if (File.Exists(luaPath)) - { - Script script = new Script(); - ((ScriptLoaderBase)script.Options.ScriptLoader).ModulePaths = new string[] { "./scripts/?", "./scripts/?.lua" }; - script.Globals["getStaticActor"] = (Func)Server.getStaticActors; - script.Globals["getWorldMaster"] = (Func)Server.GetWorldManager().GetActor; - script.Globals["getItemGamedata"] = (Func)Server.getItemGamedata; - script.DoFile(luaPath); - DynValue result = script.Call(script.Globals["onInstantiate"], target); + { + Script script = loadScript(luaPath); + + DynValue result = script.Call(script.Globals["init"], target); List lparams = LuaUtils.createLuaParamList(result); return lparams; } @@ -80,13 +76,7 @@ namespace FFXIVClassic_Map_Server.lua if (File.Exists(luaPath)) { - Script script = new Script(); - ((ScriptLoaderBase)script.Options.ScriptLoader).ModulePaths = new string[] { "./scripts/?", "./scripts/?.lua" }; - script.Globals["getWorldManager"] = (Func)Server.GetWorldManager; - script.Globals["getStaticActor"] = (Func)Server.getStaticActors; - script.Globals["getWorldMaster"] = (Func)Server.GetWorldManager().GetActor; - script.Globals["getItemGamedata"] = (Func)Server.getItemGamedata; - script.DoFile(luaPath); + Script script = loadScript(luaPath); //Have to do this to combine LuaParams List objects = new List(); @@ -98,7 +88,8 @@ namespace FFXIVClassic_Map_Server.lua objects.AddRange(LuaUtils.createLuaParamObjectList(eventStart.luaParams)); //Run Script - DynValue result = script.Call(script.Globals["onEventStarted"], objects.ToArray()); + if (!script.Globals.Get("onEventStarted").IsNil()) + script.Call(script.Globals["onEventStarted"], objects.ToArray()); } else { @@ -110,6 +101,28 @@ namespace FFXIVClassic_Map_Server.lua } + public static void doActorOnSpawn(Player player, Npc target) + { + string luaPath = String.Format(FILEPATH_NPCS, target.zoneId, target.getName()); + + if (File.Exists(luaPath)) + { + Script script = loadScript(luaPath); + + //Run Script + if (!script.Globals.Get("onSpawn").IsNil()) + script.Call(script.Globals["onSpawn"], player, target); + } + else + { + List sendError = new List(); + sendError.Add(EndEventPacket.buildPacket(player.actorId, player.eventCurrentOwner, player.eventCurrentStarter)); + player.sendMessage(SendMessagePacket.MESSAGE_TYPE_SYSTEM_ERROR, "", String.Format("ERROR: Could not find script for actor {0}.", target.getName())); + player.playerSession.queuePacket(BasePacket.createPacket(sendError, true, false)); + } + + } + public static void doActorOnEventUpdated(Player player, Actor target, EventUpdatePacket eventUpdate) { string luaPath; @@ -123,13 +136,7 @@ namespace FFXIVClassic_Map_Server.lua if (File.Exists(luaPath)) { - Script script = new Script(); - ((ScriptLoaderBase)script.Options.ScriptLoader).ModulePaths = new string[] { "./scripts/?", "./scripts/?.lua" }; - script.Globals["getWorldManager"] = (Func)Server.GetWorldManager; - script.Globals["getStaticActor"] = (Func)Server.getStaticActors; - script.Globals["getWorldMaster"] = (Func)Server.GetWorldManager().GetActor; - script.Globals["getItemGamedata"] = (Func)Server.getItemGamedata; - script.DoFile(luaPath); + Script script = loadScript(luaPath); //Have to do this to combine LuaParams List objects = new List(); @@ -139,7 +146,8 @@ namespace FFXIVClassic_Map_Server.lua objects.AddRange(LuaUtils.createLuaParamObjectList(eventUpdate.luaParams)); //Run Script - DynValue result = script.Call(script.Globals["onEventUpdate"], objects.ToArray()); + if (!script.Globals.Get("onEventUpdate").IsNil()) + script.Call(script.Globals["onEventUpdate"], objects.ToArray()); } else { @@ -156,16 +164,11 @@ namespace FFXIVClassic_Map_Server.lua if (File.Exists(luaPath)) { - Script script = new Script(); - ((ScriptLoaderBase)script.Options.ScriptLoader).ModulePaths = new string[] { "./scripts/?", "./scripts/?.lua" }; - script.Globals["getWorldManager"] = (Func)Server.GetWorldManager; - script.Globals["getStaticActor"] = (Func)Server.getStaticActors; - script.Globals["getWorldMaster"] = (Func)Server.GetWorldManager().GetActor; - script.Globals["getItemGamedata"] = (Func)Server.getItemGamedata; - script.DoFile(luaPath); + Script script = loadScript(luaPath); //Run Script - DynValue result = script.Call(script.Globals["onZoneIn"], player); + if (!script.Globals.Get("onZoneIn").IsNil()) + script.Call(script.Globals["onZoneIn"], player); } } @@ -173,18 +176,25 @@ namespace FFXIVClassic_Map_Server.lua { if (File.Exists(FILEPATH_PLAYER)) { - Script script = new Script(); - ((ScriptLoaderBase)script.Options.ScriptLoader).ModulePaths = new string[] { "./scripts/?", "./scripts/?.lua" }; - script.Globals["getWorldManager"] = (Func)Server.GetWorldManager; - script.Globals["getStaticActor"] = (Func)Server.getStaticActors; - script.Globals["getWorldMaster"] = (Func)Server.GetWorldManager().GetActor; - script.Globals["getItemGamedata"] = (Func)Server.getItemGamedata; - script.DoFile(FILEPATH_PLAYER); + Script script = loadScript(FILEPATH_PLAYER); //Run Script - DynValue result = script.Call(script.Globals["onLogin"], player); + if (!script.Globals.Get("onZoneIn").IsNil()) + script.Call(script.Globals["onZoneIn"], player); } } + private static Script loadScript(string filename) + { + Script script = new Script(); + ((FileSystemScriptLoader)script.Options.ScriptLoader).ModulePaths = FileSystemScriptLoader.UnpackStringPaths("./scripts/?;./scripts/?.lua"); + script.Globals["getWorldManager"] = (Func)Server.GetWorldManager; + script.Globals["getStaticActor"] = (Func)Server.getStaticActors; + script.Globals["getWorldMaster"] = (Func)Server.GetWorldManager().GetActor; + script.Globals["getItemGamedata"] = (Func)Server.getItemGamedata; + script.DoFile(filename); + return script; + } + } } diff --git a/FFXIVClassic Map Server/packets/send/Actor/ActorSpecialGraphicPacket.cs b/FFXIVClassic Map Server/packets/send/Actor/ActorSpecialGraphicPacket.cs new file mode 100644 index 00000000..d2604645 --- /dev/null +++ b/FFXIVClassic Map Server/packets/send/Actor/ActorSpecialGraphicPacket.cs @@ -0,0 +1,36 @@ +using FFXIVClassic_Lobby_Server.packets; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Map_Server.packets.send.actor +{ + class ActorSpecialGraphicPacket + { + public const int NONE = 0x0; + public const int QUEST = 0x2; + public const int NOGRAPHIC = 0x3; + public const int QUEST_IMPORTANT = 0x4; + + public const ushort OPCODE = 0x00E3; + public const uint PACKET_SIZE = 0x28; + + public static SubPacket buildPacket(uint playerActorID, uint targetActorID, int iconCode) + { + byte[] data = new byte[PACKET_SIZE - 0x20]; + + using (MemoryStream mem = new MemoryStream(data)) + { + using (BinaryWriter binWriter = new BinaryWriter(mem)) + { + binWriter.Write((Int32)iconCode); + } + } + + return new SubPacket(OPCODE, targetActorID, playerActorID, data); + } + } +} From 1f5788def8efcef02b07d1cda24db6bb79cbda4f Mon Sep 17 00:00:00 2001 From: Filip Maj Date: Thu, 7 Apr 2016 22:32:04 -0400 Subject: [PATCH 02/21] Redundent zoneid was redundent. --- FFXIVClassic Map Server/WorldManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FFXIVClassic Map Server/WorldManager.cs b/FFXIVClassic Map Server/WorldManager.cs index cbac035a..f43fef23 100644 --- a/FFXIVClassic Map Server/WorldManager.cs +++ b/FFXIVClassic Map Server/WorldManager.cs @@ -347,7 +347,7 @@ namespace FFXIVClassic_Map_Server } //Moves actor to new zone, and sends packets to spawn at the given zone entrance - public void DoZoneChange(Player player, uint destinationZoneId, uint zoneEntrance) + public void DoZoneChange(Player player, uint zoneEntrance) { if (!zoneEntranceList.ContainsKey(zoneEntrance)) { @@ -356,7 +356,7 @@ namespace FFXIVClassic_Map_Server } ZoneEntrance ze = zoneEntranceList[zoneEntrance]; - DoZoneChange(player, destinationZoneId, ze.privateAreaName, ze.spawnType, ze.spawnX, ze.spawnY, ze.spawnZ, ze.spawnRotation); + DoZoneChange(player, ze.zoneId, ze.privateAreaName, ze.spawnType, ze.spawnX, ze.spawnY, ze.spawnZ, ze.spawnRotation); } //Moves actor to new zone, and sends packets to spawn at the given coords. From c0cd7555e1550832d808b50f3bb11015a79b6b89 Mon Sep 17 00:00:00 2001 From: Filip Maj Date: Thu, 7 Apr 2016 22:34:10 -0400 Subject: [PATCH 03/21] -Fixed up the quest flag functions. -Renamed the ActorSpecialGraphicPacket to SetActorQuestGraphic as those icons all have to do with questing. -Got onSpawn to work and implemented the quest graphics. -Added new QuestDirector class. --- .../actors/area/PrivateArea.cs | 9 ++- .../actors/chara/Character.cs | 6 +- .../actors/chara/player/Player.cs | 23 ++++--- .../director/quest/QuestDirectorMan0L001..cs | 39 +++++++++++ FFXIVClassic Map Server/actors/quest/Quest.cs | 2 +- .../dataobjects/ConnectedPlayer.cs | 24 ++++--- FFXIVClassic Map Server/lua/LuaEngine.cs | 64 +++++++++++++------ .../send/Actor/ActorSpecialGraphicPacket.cs | 2 +- 8 files changed, 120 insertions(+), 49 deletions(-) create mode 100644 FFXIVClassic Map Server/actors/director/quest/QuestDirectorMan0L001..cs diff --git a/FFXIVClassic Map Server/actors/area/PrivateArea.cs b/FFXIVClassic Map Server/actors/area/PrivateArea.cs index ab788357..3c6f6726 100644 --- a/FFXIVClassic Map Server/actors/area/PrivateArea.cs +++ b/FFXIVClassic Map Server/actors/area/PrivateArea.cs @@ -35,7 +35,14 @@ namespace FFXIVClassic_Map_Server.actors.area public override SubPacket createScriptBindPacket(uint playerActorId) { List lParams; - lParams = LuaUtils.createLuaParamList("/Area/PrivateArea/" + className, false, true, zoneName, privateAreaName, 0x9E, canRideChocobo ? (byte)1 : (byte)0, canStealth, isInn, false, false, false, false, false, false); + + string path = className; + + if (className.ToLower().Contains("content")) + path = "Content/" + className; + + lParams = LuaUtils.createLuaParamList("/Area/PrivateArea/" + path, false, true, zoneName, privateAreaName, 0x9E, canRideChocobo ? (byte)1 : (byte)0, canStealth, isInn, false, false, false, false, false, false); + ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, className, lParams).debugPrintSubPacket(); return ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, className, lParams); } diff --git a/FFXIVClassic Map Server/actors/chara/Character.cs b/FFXIVClassic Map Server/actors/chara/Character.cs index dd5f5266..c453e82f 100644 --- a/FFXIVClassic Map Server/actors/chara/Character.cs +++ b/FFXIVClassic Map Server/actors/chara/Character.cs @@ -81,11 +81,9 @@ namespace FFXIVClassic_Map_Server.Actors return SetActorIdleAnimationPacket.buildPacket(actorId, playerActorId, animationId); } - public void setQuestIcon(Player player, bool hasIcon) + public void setQuestGraphic(Player player, int graphicNum) { - ActorSpecialGraphicPacket.buildPacket(player.actorId, actorId, hasIcon ? ActorSpecialGraphicPacket.QUEST : 0x0).debugPrintSubPacket(); - //player.queuePacket(ActorSpecialGraphicPacket.buildPacket(player.actorId, actorId, hasIcon ? ActorSpecialGraphicPacket.QUEST : 0x0)); - + player.queuePacket(SetActorQuestGraphicPacket.buildPacket(player.actorId, actorId, graphicNum)); } } diff --git a/FFXIVClassic Map Server/actors/chara/player/Player.cs b/FFXIVClassic Map Server/actors/chara/player/Player.cs index bcb44705..4c5849d8 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Player.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Player.cs @@ -125,7 +125,7 @@ namespace FFXIVClassic_Map_Server.Actors public Quest[] questScenario = new Quest[16]; public Quest[] questGuildleve = new Quest[8]; - public Director currentDirector;// = new OpeningDirector(0x46080012); + public Director currentDirector = new OpeningDirector(0x46080012); public PlayerWork playerWork = new PlayerWork(); @@ -590,6 +590,12 @@ namespace FFXIVClassic_Map_Server.Actors playerSession.queuePacket(packet, true, false); } + public void queuePackets(List packets) + { + foreach (SubPacket subpacket in packets) + playerSession.queuePacket(subpacket, true, false); + } + public void broadcastPacket(SubPacket packet, bool sendToSelf) { if (sendToSelf) @@ -969,7 +975,7 @@ namespace FFXIVClassic_Map_Server.Actors { for (int i = 0; i < questScenario.Length; i++) { - if (questScenario[i] != null && questScenario[i].actorName.Equals(name)) + if (questScenario[i] != null && questScenario[i].actorName.ToLower().Equals(name.ToLower())) return questScenario[i]; } @@ -991,7 +997,11 @@ namespace FFXIVClassic_Map_Server.Actors { if (directorType.Equals("openingDirector")) { - currentDirector = new OpeningDirector(0x46080012); + currentDirector = new OpeningDirector(0x46080012); + } + else if (directorType.Equals("QuestDirectorMan0l001")) + { + currentDirector = new QuestDirectorMan0l001(0x46080012); } queuePacket(RemoveActorPacket.buildPacket(actorId, 0x46080012)); @@ -1077,12 +1087,7 @@ namespace FFXIVClassic_Map_Server.Actors { //Update Instance - List instanceUpdatePackets = playerSession.updateInstance(zone.getActorsAroundActor(this, 50)); - foreach (BasePacket bp in instanceUpdatePackets) - { - // bp.debugPrintPacket(); - queuePacket(bp); - } + playerSession.updateInstance(zone.getActorsAroundActor(this, 50)); } diff --git a/FFXIVClassic Map Server/actors/director/quest/QuestDirectorMan0L001..cs b/FFXIVClassic Map Server/actors/director/quest/QuestDirectorMan0L001..cs new file mode 100644 index 00000000..6f00a12a --- /dev/null +++ b/FFXIVClassic Map Server/actors/director/quest/QuestDirectorMan0L001..cs @@ -0,0 +1,39 @@ +using FFXIVClassic_Lobby_Server.packets; +using FFXIVClassic_Map_Server.lua; +using FFXIVClassic_Map_Server.packets.send.actor; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Map_Server.actors.director +{ + class QuestDirectorMan0l001 : Director + { + public QuestDirectorMan0l001(uint id) : base(id) + { + this.displayNameId = 0; + this.customDisplayName = "questDirect_ocn0Btl02_01"; + + this.actorName = "questDirect_ocn0Btl02_01@0C196"; + this.className = "QuestDirectorMan0l001"; + + this.eventConditions = new EventList(); + + List noticeEventList = new List(); + + noticeEventList.Add(new EventList.NoticeEventCondition("noticeEvent", 0xE, 0x0)); + noticeEventList.Add(new EventList.NoticeEventCondition("noticeRequest", 0x0, 0x1)); + + this.eventConditions.noticeEventConditions = noticeEventList; + } + + public override SubPacket createScriptBindPacket(uint playerActorId) + { + List lParams; + lParams = LuaUtils.createLuaParamList("/Director/Quest/QuestDirectorMan0l001", false, false, false, false, 0x7532); + return ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, className, lParams); + } + } +} diff --git a/FFXIVClassic Map Server/actors/quest/Quest.cs b/FFXIVClassic Map Server/actors/quest/Quest.cs index c125548e..707349b8 100644 --- a/FFXIVClassic Map Server/actors/quest/Quest.cs +++ b/FFXIVClassic Map Server/actors/quest/Quest.cs @@ -68,7 +68,7 @@ namespace FFXIVClassic_Map_Server.Actors return false; } else - return (questFlags & (1 << bitIndex)) == 1; + return (questFlags & (1 << bitIndex)) == (1 << bitIndex); } public int GetPhase() diff --git a/FFXIVClassic Map Server/dataobjects/ConnectedPlayer.cs b/FFXIVClassic Map Server/dataobjects/ConnectedPlayer.cs index 567aec3c..2a966f81 100644 --- a/FFXIVClassic Map Server/dataobjects/ConnectedPlayer.cs +++ b/FFXIVClassic Map Server/dataobjects/ConnectedPlayer.cs @@ -113,7 +113,7 @@ namespace FFXIVClassic_Map_Server.dataobjects } - public List updateInstance(List list) + public void updateInstance(List list) { List basePackets = new List(); List removeActorSubpackets = new List(); @@ -124,14 +124,11 @@ namespace FFXIVClassic_Map_Server.dataobjects { if (!list.Contains(actorInstanceList[i])) { - removeActorSubpackets.Add(RemoveActorPacket.buildPacket(playerActor.actorId, actorInstanceList[i].actorId)); + getActor().queuePacket(RemoveActorPacket.buildPacket(playerActor.actorId, actorInstanceList[i].actorId)); actorInstanceList.RemoveAt(i); } } - if (removeActorSubpackets.Count != 0) - basePackets.Add(BasePacket.createPacket(removeActorSubpackets, true, false)); - //Add new actors or move for (int i = 0; i < list.Count; i++) { @@ -142,21 +139,22 @@ namespace FFXIVClassic_Map_Server.dataobjects if (actorInstanceList.Contains(actor)) { - posUpdateSubpackets.Add(actor.createPositionUpdatePacket(playerActor.actorId)); + getActor().queuePacket(actor.createPositionUpdatePacket(playerActor.actorId)); } else { - basePackets.Add(actor.getSpawnPackets(playerActor.actorId, 1)); - basePackets.Add(actor.getInitPackets(playerActor.actorId)); - basePackets.Add(actor.getSetEventStatusPackets(playerActor.actorId)); + getActor().queuePacket(actor.getSpawnPackets(playerActor.actorId, 1)); + getActor().queuePacket(actor.getInitPackets(playerActor.actorId)); + getActor().queuePacket(actor.getSetEventStatusPackets(playerActor.actorId)); actorInstanceList.Add(actor); + + if (actor is Npc) + { + LuaEngine.doActorOnSpawn(getActor(), (Npc)actor); + } } } - if (posUpdateSubpackets.Count > 0) - basePackets.Add(BasePacket.createPacket(posUpdateSubpackets, true, false)); - - return basePackets; } diff --git a/FFXIVClassic Map Server/lua/LuaEngine.cs b/FFXIVClassic Map Server/lua/LuaEngine.cs index 7a7603bd..8d8d92eb 100644 --- a/FFXIVClassic Map Server/lua/LuaEngine.cs +++ b/FFXIVClassic Map Server/lua/LuaEngine.cs @@ -1,4 +1,5 @@ using FFXIVClassic_Lobby_Server; +using FFXIVClassic_Lobby_Server.common; using FFXIVClassic_Lobby_Server.packets; using FFXIVClassic_Map_Server.actors.director; using FFXIVClassic_Map_Server.Actors; @@ -42,16 +43,16 @@ namespace FFXIVClassic_Map_Server.lua { Script script = loadScript(luaPath); + if (script == null) + return null; + DynValue result = script.Call(script.Globals["init"], target); List lparams = LuaUtils.createLuaParamList(result); return lparams; } else { - List sendError = new List(); - sendError.Add(EndEventPacket.buildPacket(player.actorId, player.eventCurrentOwner, player.eventCurrentStarter)); - player.sendMessage(SendMessagePacket.MESSAGE_TYPE_SYSTEM_ERROR, "", String.Format("ERROR: Could not find script for actor {0}.", target.getName())); - player.playerSession.queuePacket(BasePacket.createPacket(sendError, true, false)); + SendError(player, String.Format("ERROR: Could not find script for actor {0}.", target.getName())); return null; } } @@ -78,6 +79,9 @@ namespace FFXIVClassic_Map_Server.lua { Script script = loadScript(luaPath); + if (script == null) + return; + //Have to do this to combine LuaParams List objects = new List(); objects.Add(player); @@ -93,10 +97,7 @@ namespace FFXIVClassic_Map_Server.lua } else { - List sendError = new List(); - sendError.Add(EndEventPacket.buildPacket(player.actorId, player.eventCurrentOwner, player.eventCurrentStarter)); - player.sendMessage(SendMessagePacket.MESSAGE_TYPE_SYSTEM_ERROR, "", String.Format("ERROR: Could not find script for actor {0}.", target.getName())); - player.playerSession.queuePacket(BasePacket.createPacket(sendError, true, false)); + SendError(player, String.Format("ERROR: Could not find script for actor {0}.", target.getName())); } } @@ -108,17 +109,17 @@ namespace FFXIVClassic_Map_Server.lua if (File.Exists(luaPath)) { Script script = loadScript(luaPath); - + + if (script == null) + return; + //Run Script if (!script.Globals.Get("onSpawn").IsNil()) script.Call(script.Globals["onSpawn"], player, target); } else { - List sendError = new List(); - sendError.Add(EndEventPacket.buildPacket(player.actorId, player.eventCurrentOwner, player.eventCurrentStarter)); - player.sendMessage(SendMessagePacket.MESSAGE_TYPE_SYSTEM_ERROR, "", String.Format("ERROR: Could not find script for actor {0}.", target.getName())); - player.playerSession.queuePacket(BasePacket.createPacket(sendError, true, false)); + SendError(player, String.Format("ERROR: Could not find script for actor {0}.", target.getName())); } } @@ -138,11 +139,14 @@ namespace FFXIVClassic_Map_Server.lua { Script script = loadScript(luaPath); + if (script == null) + return; + //Have to do this to combine LuaParams List objects = new List(); objects.Add(player); objects.Add(target); - objects.Add(eventUpdate.step); + objects.Add(eventUpdate.val2); objects.AddRange(LuaUtils.createLuaParamObjectList(eventUpdate.luaParams)); //Run Script @@ -151,10 +155,7 @@ namespace FFXIVClassic_Map_Server.lua } else { - List sendError = new List(); - sendError.Add(EndEventPacket.buildPacket(player.actorId, player.eventCurrentOwner, player.eventCurrentStarter)); - player.sendMessage(SendMessagePacket.MESSAGE_TYPE_SYSTEM_ERROR, "", String.Format("ERROR: Could not find script for actor {0}.", target.getName())); - player.playerSession.queuePacket(BasePacket.createPacket(sendError, true, false)); + SendError(player, String.Format("ERROR: Could not find script for actor {0}.", target.getName())); } } @@ -165,7 +166,10 @@ namespace FFXIVClassic_Map_Server.lua if (File.Exists(luaPath)) { Script script = loadScript(luaPath); - + + if (script == null) + return; + //Run Script if (!script.Globals.Get("onZoneIn").IsNil()) script.Call(script.Globals["onZoneIn"], player); @@ -178,6 +182,9 @@ namespace FFXIVClassic_Map_Server.lua { Script script = loadScript(FILEPATH_PLAYER); + if (script == null) + return; + //Run Script if (!script.Globals.Get("onZoneIn").IsNil()) script.Call(script.Globals["onZoneIn"], player); @@ -192,9 +199,26 @@ namespace FFXIVClassic_Map_Server.lua script.Globals["getStaticActor"] = (Func)Server.getStaticActors; script.Globals["getWorldMaster"] = (Func)Server.GetWorldManager().GetActor; script.Globals["getItemGamedata"] = (Func)Server.getItemGamedata; - script.DoFile(filename); + + try + { + script.DoFile(filename); + } + catch(SyntaxErrorException e) + { + Log.error(String.Format("LUAERROR: {0}.", e.DecoratedMessage)); + return null; + } return script; } + private static void SendError(Player player, string message) + { + List sendError = new List(); + sendError.Add(EndEventPacket.buildPacket(player.actorId, player.eventCurrentOwner, player.eventCurrentStarter)); + player.sendMessage(SendMessagePacket.MESSAGE_TYPE_SYSTEM_ERROR, "", message); + player.playerSession.queuePacket(BasePacket.createPacket(sendError, true, false)); + } + } } diff --git a/FFXIVClassic Map Server/packets/send/Actor/ActorSpecialGraphicPacket.cs b/FFXIVClassic Map Server/packets/send/Actor/ActorSpecialGraphicPacket.cs index d2604645..1efd25dd 100644 --- a/FFXIVClassic Map Server/packets/send/Actor/ActorSpecialGraphicPacket.cs +++ b/FFXIVClassic Map Server/packets/send/Actor/ActorSpecialGraphicPacket.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace FFXIVClassic_Map_Server.packets.send.actor { - class ActorSpecialGraphicPacket + class SetActorQuestGraphicPacket { public const int NONE = 0x0; public const int QUEST = 0x2; From b8a3d4f1e039545ba9c712318050ba6578403935 Mon Sep 17 00:00:00 2001 From: Filip Maj Date: Sun, 10 Apr 2016 11:14:36 -0400 Subject: [PATCH 04/21] Added quest director class. --- FFXIVClassic Map Server/FFXIVClassic Map Server.csproj | 1 + FFXIVClassic Map Server/actors/chara/player/Player.cs | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj index 2ecccff3..6a861225 100644 --- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj +++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj @@ -72,6 +72,7 @@ + diff --git a/FFXIVClassic Map Server/actors/chara/player/Player.cs b/FFXIVClassic Map Server/actors/chara/player/Player.cs index 4c5849d8..d2bad572 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Player.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Player.cs @@ -125,7 +125,7 @@ namespace FFXIVClassic_Map_Server.Actors public Quest[] questScenario = new Quest[16]; public Quest[] questGuildleve = new Quest[8]; - public Director currentDirector = new OpeningDirector(0x46080012); + public Director currentDirector;// = new OpeningDirector(0x46080012); public PlayerWork playerWork = new PlayerWork(); @@ -1004,9 +1004,9 @@ namespace FFXIVClassic_Map_Server.Actors currentDirector = new QuestDirectorMan0l001(0x46080012); } - queuePacket(RemoveActorPacket.buildPacket(actorId, 0x46080012)); - queuePacket(currentDirector.getSpawnPackets(actorId)); - queuePacket(currentDirector.getInitPackets(actorId)); + // queuePacket(RemoveActorPacket.buildPacket(actorId, 0x46080012)); + // queuePacket(currentDirector.getSpawnPackets(actorId)); + // queuePacket(currentDirector.getInitPackets(actorId)); // queuePacket(currentDirector.getSetEventStatusPackets(actorId)); // currentDirector.getSpawnPackets(actorId).debugPrintPacket(); // currentDirector.getInitPackets(actorId).debugPrintPacket(); From fe111ab6ca44bfce98e74e5f9901e2b22f33c53b Mon Sep 17 00:00:00 2001 From: Filip Maj Date: Sun, 10 Apr 2016 13:11:12 -0400 Subject: [PATCH 05/21] Quest data is now saved/loaded from the DB. --- FFXIVClassic Map Server/Database.cs | 68 ++++++++++++++++++- .../actors/chara/player/Player.cs | 11 +++ FFXIVClassic Map Server/actors/quest/Quest.cs | 39 ++++++++--- 3 files changed, 108 insertions(+), 10 deletions(-) diff --git a/FFXIVClassic Map Server/Database.cs b/FFXIVClassic Map Server/Database.cs index 06a03b1e..881910bc 100644 --- a/FFXIVClassic Map Server/Database.cs +++ b/FFXIVClassic Map Server/Database.cs @@ -310,6 +310,56 @@ namespace FFXIVClassic_Lobby_Server } } + public static void saveQuest(Player player, Quest quest) + { + int slot = player.getQuestSlot(quest.actorId); + if (slot == -1) + { + Log.error(String.Format("Tried saving quest player didn't have: Player: {0:x}, QuestId: {0:x}", player.actorId, quest.actorId)); + return; + } + else + saveQuest(player, quest, slot); + } + + public static void saveQuest(Player player, Quest quest, int slot) + { + 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))) + { + try + { + conn.Open(); + + query = @" + INSERT INTO characters_quest_scenario + (characterId, slot, questId, questData, questFlags) + VALUES + (@charaId, @slot, @questId, @questData, @questFlags) + ON DUPLICATE KEY UPDATE + questData = @questData, questFlags = @questFlags + "; + + cmd = new MySqlCommand(query, conn); + cmd.Parameters.AddWithValue("@charaId", player.actorId); + cmd.Parameters.AddWithValue("@slot", slot); + cmd.Parameters.AddWithValue("@questId", quest.actorId); + cmd.Parameters.AddWithValue("@questData", quest.GetSerializedQuestData()); + cmd.Parameters.AddWithValue("@questFlags", quest.GetQuestFlags()); + + cmd.ExecuteNonQuery(); + } + catch (MySqlException e) + { Console.WriteLine(e); } + finally + { + conn.Dispose(); + } + } + } + public static void loadPlayerCharacter(Player player) { string query; @@ -627,7 +677,9 @@ namespace FFXIVClassic_Lobby_Server query = @" SELECT slot, - questId + questId, + questData, + questFlags FROM characters_quest_scenario WHERE characterId = @charId"; cmd = new MySqlCommand(query, conn); @@ -638,9 +690,21 @@ namespace FFXIVClassic_Lobby_Server { int index = reader.GetUInt16(0); player.playerWork.questScenario[index] = 0xA0F00000 | reader.GetUInt32(1); + string questData = null; + uint questFlags = 0; + + if (!reader.IsDBNull(2)) + questData = reader.GetString(2); + else + questData = "{}"; + + if (!reader.IsDBNull(3)) + questFlags = reader.GetUInt32(3); + else + questFlags = 0; string questName = Server.getStaticActors(player.playerWork.questScenario[index]).actorName; - player.questScenario[index] = new Quest(player.playerWork.questScenario[index], questName); + player.questScenario[index] = new Quest(player, player.playerWork.questScenario[index], questName, questData, questFlags); } } diff --git a/FFXIVClassic Map Server/actors/chara/player/Player.cs b/FFXIVClassic Map Server/actors/chara/player/Player.cs index d2bad572..7405ed9d 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Player.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Player.cs @@ -993,6 +993,17 @@ namespace FFXIVClassic_Map_Server.Actors return false; } + public int getQuestSlot(uint id) + { + for (int i = 0; i < questScenario.Length; i++) + { + if (questScenario[i] != null && questScenario[i].actorId == (0xA0F00000 | id)) + return i; + } + + return -1; + } + public void setDirector(string directorType) { if (directorType.Equals("openingDirector")) diff --git a/FFXIVClassic Map Server/actors/quest/Quest.cs b/FFXIVClassic Map Server/actors/quest/Quest.cs index 707349b8..a8bd5c34 100644 --- a/FFXIVClassic Map Server/actors/quest/Quest.cs +++ b/FFXIVClassic Map Server/actors/quest/Quest.cs @@ -1,4 +1,6 @@ -using FFXIVClassic_Lobby_Server.common; +using FFXIVClassic_Lobby_Server; +using FFXIVClassic_Lobby_Server.common; +using Newtonsoft.Json; using System; using System.Collections.Generic; @@ -6,6 +8,7 @@ namespace FFXIVClassic_Map_Server.Actors { class Quest : Actor { + private Player owner; private int currentPhase = 0; private uint questFlags = 0; private Dictionary questData = new Dictionary(); @@ -13,17 +16,22 @@ namespace FFXIVClassic_Map_Server.Actors public Quest(uint actorID, string name) : base(actorID) { - actorName = name; + actorName = name; } - public void InitQuestData(string dataName, object initialValue) + public Quest(Player owner, uint actorID, string name, string questDataJson, uint questFlags) + : base(actorID) { - questData[dataName] = initialValue; + this.owner = owner; + actorName = name; + this.questFlags = questFlags; + this.questData = JsonConvert.DeserializeObject>(questDataJson); + if (questData == null) + questData = new Dictionary(); } - - public void UpdateQuestData(string dataName, object data) - { - if (questData.ContainsKey(dataName)) + + public void SetQuestData(string dataName, object data) + { questData[dataName] = data; //Inform update @@ -81,5 +89,20 @@ namespace FFXIVClassic_Map_Server.Actors currentPhase++; } + public uint GetQuestFlags() + { + return questFlags; + } + + public string GetSerializedQuestData() + { + return JsonConvert.SerializeObject(questData, Formatting.Indented); + } + + public void SaveData() + { + Database.saveQuest(owner, this); + } + } } From 1ce34914bcf3595b52605c01d08e93f249fd77a0 Mon Sep 17 00:00:00 2001 From: TheManii Date: Mon, 11 Apr 2016 14:35:17 -0400 Subject: [PATCH 06/21] Remove unused files --- www/login.php | 89 ----------------------------------------------- www/testmysql.php | 7 ---- 2 files changed, 96 deletions(-) delete mode 100644 www/login.php delete mode 100644 www/testmysql.php diff --git a/www/login.php b/www/login.php deleted file mode 100644 index 40870a8f..00000000 --- a/www/login.php +++ /dev/null @@ -1,89 +0,0 @@ -getMessage(); - } -} - -?> - - - - FFXIV 1.0 Login - - - - - window.location=\"ffxiv://login_success?sessionId=" . $sessionId . "\";"; - } - ?> - -
-
- -
- -
-
-
-
- - - - - - - - - - - - -
Username:
Password:
- -
-
-

-
-
-
- - - diff --git a/www/testmysql.php b/www/testmysql.php deleted file mode 100644 index fdb5dd88..00000000 --- a/www/testmysql.php +++ /dev/null @@ -1,7 +0,0 @@ - \ No newline at end of file From c9838254b976500f6106967a0d730d07195f308b Mon Sep 17 00:00:00 2001 From: TheManii Date: Mon, 11 Apr 2016 14:39:33 -0400 Subject: [PATCH 07/21] Revert "Remove unused files" This reverts commit 1ce34914bcf3595b52605c01d08e93f249fd77a0. --- www/login.php | 89 +++++++++++++++++++++++++++++++++++++++++++++++ www/testmysql.php | 7 ++++ 2 files changed, 96 insertions(+) create mode 100644 www/login.php create mode 100644 www/testmysql.php diff --git a/www/login.php b/www/login.php new file mode 100644 index 00000000..40870a8f --- /dev/null +++ b/www/login.php @@ -0,0 +1,89 @@ +getMessage(); + } +} + +?> + + + + FFXIV 1.0 Login + + + + + window.location=\"ffxiv://login_success?sessionId=" . $sessionId . "\";"; + } + ?> + +
+
+ +
+ +
+
+
+
+ + + + + + + + + + + + +
Username:
Password:
+ +
+
+

+
+
+
+ + + diff --git a/www/testmysql.php b/www/testmysql.php new file mode 100644 index 00000000..fdb5dd88 --- /dev/null +++ b/www/testmysql.php @@ -0,0 +1,7 @@ + \ No newline at end of file From e33bd05f09b09f96ac0996be7c9d1ddaf97a7df9 Mon Sep 17 00:00:00 2001 From: TheManii Date: Mon, 11 Apr 2016 14:40:08 -0400 Subject: [PATCH 08/21] Removed wrong files --- www/index.php | 553 ---------------------------------------------- www/testmysql.php | 7 - 2 files changed, 560 deletions(-) delete mode 100644 www/index.php delete mode 100644 www/testmysql.php diff --git a/www/index.php b/www/index.php deleted file mode 100644 index 2236f73b..00000000 --- a/www/index.php +++ /dev/null @@ -1,553 +0,0 @@ - -// Arno Esterhuizen -// et Romain Bourdon -// et Hervé Leclerc -// -// Mise à jour par Herve Leclerc herve.leclerc@alterway.fr -// Icônes par Mark James -//------ -//[modif oto] Modifications Dominique Ottello (Otomatic) -//Suppression des vhosts, le dossier n'étant plus créé à l'installation -//Affichage des Outils, Projets et Alias sur trois colonnes -// - Recodage en utf-8 -// - Modification des styles : ajout .third .left et .right -// - Ajouts d'index dans $langues['en'] et ['fr'] : -// 'locale' pour set_locale -// 'docp' url des documentations PHP -// 'docm' url des documentations MySQL -// 'doca2.2' url de la documentation Apache 2.2 -// 'doca2.4' url de la documentation Apache 2.4 -// 'server' Server Software -// - Classement alphabétique des extensions PHP en fonction de la localisation -// - Liens sur les documentations Apache, PHP et MySQL -// - Ajout variable $suppress_localhost = true; -// - Conformité W3C par ajout de
  • ...
  • sur les variables -// $aliasContents et $projectContents si vides - -//[modif oto] - Pour supprimer niveau localhost dans les url -$suppress_localhost = true; -// avec modification de la ligne -//$projectContents .= '
  • '.$file.'
  • '; -//Par : -//$projectContents .= '
  • '.$file.'
  • '; -//----- -//[modif oto] Ajout $server_dir pour un seul remplacement -// si déplacement www hors de Wamp et pas d'utilisation des jonctions -//Par défaut la valeur est "../" -//$server_dir = "WAMPROOT/"; -$server_dir = "../"; -//Fonctionne à condition d'avoir ServerSignature On et ServerTokens Full dans httpd.conf -$server_software = $_SERVER['SERVER_SOFTWARE']; - -$wampConfFile = $server_dir.'wampmanager.conf'; -//chemin jusqu'aux fichiers alias -$aliasDir = $server_dir.'alias/'; - -// on charge le fichier de conf locale -if (!is_file($wampConfFile)) - die ('Unable to open WampServer\'s config file, please change path in index.php file'); -$fp = fopen($wampConfFile,'r'); -$wampConfFileContents = fread ($fp, filesize ($wampConfFile)); -fclose ($fp); - - -// on récupère les versions des applis -preg_match('|phpVersion = (.*)\n|',$wampConfFileContents,$result); -$phpVersion = str_replace('"','',$result[1]); -preg_match('|apacheVersion = (.*)\n|',$wampConfFileContents,$result); -$apacheVersion = str_replace('"','',$result[1]); -$doca_version = 'doca'.substr($apacheVersion,0,3); -preg_match('|mysqlVersion = (.*)\n|',$wampConfFileContents,$result); -$mysqlVersion = str_replace('"','',$result[1]); -preg_match('|wampserverVersion = (.*)\n|',$wampConfFileContents,$result); -$wampserverVersion = str_replace('"','',$result[1]); - -// répertoires à ignorer dans les projets -$projectsListIgnore = array ('.','..'); - -// textes -$langues = array( - 'en' => array( - 'langue' => 'English', - 'locale' => 'english', - 'autreLangue' => 'Version Française', - 'autreLangueLien' => 'fr', - 'titreHtml' => 'WAMPSERVER Homepage', - 'titreConf' => 'Server Configuration', - 'versa' => 'Apache Version :', - 'doca2.2' => 'httpd.apache.org/docs/2.2/en/', - 'doca2.4' => 'httpd.apache.org/docs/2.4/en/', - 'versp' => 'PHP Version :', - 'server' => 'Server Software:', - 'docp' => 'www.php.net/manual/en/', - 'versm' => 'MySQL Version :', - 'docm' => 'dev.mysql.com/doc/index.html', - 'phpExt' => 'Loaded Extensions : ', - 'titrePage' => 'Tools', - 'txtProjet' => 'Your Projects', - 'txtNoProjet' => 'No projects yet.
    To create a new one, just create a directory in \'www\'.', - 'txtAlias' => 'Your Aliases', - 'txtNoAlias' => 'No Alias yet.
    To create a new one, use the WAMPSERVER menu.', - 'faq' => 'http://www.en.wampserver.com/faq.php' - ), - 'fr' => array( - 'langue' => 'Français', - 'locale' => 'french', - 'autreLangue' => 'English Version', - 'autreLangueLien' => 'en', - 'titreHtml' => 'Accueil WAMPSERVER', - 'titreConf' => 'Configuration Serveur', - 'versa' => 'Version Apache:', - 'doca2.2' => 'httpd.apache.org/docs/2.2/fr/', - 'doca2.4' => 'httpd.apache.org/docs/2.4/fr/', - 'versp' => 'Version de PHP:', - 'server' => 'Server Software:', - 'docp' => 'www.php.net/manual/fr/', - 'versm' => 'Version de MySQL:', - 'docm' => 'dev.mysql.com/doc/index.html', - 'phpExt' => 'Extensions Chargées: ', - 'titrePage' => 'Outils', - 'txtProjet' => 'Vos Projets', - 'txtNoProjet' => 'Aucun projet.
    Pour en ajouter un nouveau, créez simplement un répertoire dans \'www\'.', - 'txtAlias' => 'Vos Alias', - 'txtNoAlias' => 'Aucun alias.
    Pour en ajouter un nouveau, utilisez le menu de WAMPSERVER.', - 'faq' => 'http://www.wampserver.com/faq.php' - ) -); - -// images -$pngFolder = <<< EOFILE -iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAA3NCSVQICAjb4U/gAAABhlBMVEX//v7//v3///7//fr//fj+/v3//fb+/fT+/Pf//PX+/Pb+/PP+/PL+/PH+/PD+++/+++7++u/9+vL9+vH79+r79+n79uj89tj89Nf889D88sj78sz78sr58N3u7u7u7ev777j67bL67Kv46sHt6uP26cns6d356aP56aD56Jv45pT45pP45ZD45I324av344r344T14J734oT34YD13pD24Hv03af13pP233X025303JL23nX23nHz2pX23Gvn2a7122fz2I3122T12mLz14Xv1JPy1YD12Vz02Fvy1H7v04T011Py03j011b01k7v0n/x0nHz1Ejv0Hnuz3Xx0Gvz00buzofz00Pxz2juz3Hy0TrmznzmzoHy0Djqy2vtymnxzS3xzi/kyG3jyG7wyyXkwJjpwHLiw2Liw2HhwmDdvlXevVPduVThsX7btDrbsj/gq3DbsDzbrT7brDvaqzjapjrbpTraojnboTrbmzrbmjrbl0Tbljrakz3ajzzZjTfZijLZiTJdVmhqAAAAgnRSTlP///////////////////////////////////////8A////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9XzUpQAAAAlwSFlzAAALEgAACxIB0t1+/AAAAB90RVh0U29mdHdhcmUATWFjcm9tZWRpYSBGaXJld29ya3MgOLVo0ngAAACqSURBVBiVY5BDAwxECGRlpgNBtpoKCMjLM8jnsYKASFJycnJ0tD1QRT6HromhHj8YMOcABYqEzc3d4uO9vIKCIkULgQIlYq5haao8YMBUDBQoZWIBAnFtAwsHD4kyoEA5l5SCkqa+qZ27X7hkBVCgUkhRXcvI2sk3MCpRugooUCOooWNs4+wdGpuQIlMDFKiWNbO0dXTx9AwICVGuBQqkFtQ1wEB9LhGeAwDSdzMEmZfC0wAAAABJRU5ErkJggg== -EOFILE; -$pngFolderGo = <<< EOFILE -iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJISURBVDjLpZPLS5RhFIef93NmnMIRSynvgRF5KWhRlmWbbotwU9sWLupfCBeBEYhQm2iVq1oF0TKIILIkMgosxBaBkpFDmpo549y+772dFl5bBIG/5eGch9+5KRFhOwrYpmIAk8+OjScr29uV2soTotzXtLOZLiD6q0oBUDjY89nGAJQErU3dD+NKKZDVYpTChr9a5sdvpWUtClCWqBRxZiE/9+o68CQGgJUQr8ujn/dxugyCSpRKkaw/S33n7QQigAfxgKCCitqpp939mwCjAvEapxOIF3xpBlOYJ78wQjxZB2LAa0QsYEm19iUQv29jBihJeltCF0F0AZNbIdXaS7K6ba3hdQey6iBWBS6IbQJMQGzHHqrarm0kCh6vf2AzLxGX5eboc5ZLBe52dZBsvAGRsAUgIi7EFycQl0VcDrEZvFlGXBZshtCGNNa0cXVkjEdXIjBb1kiEiLd4s4jYLOKy9L1+DGLQ3qKtpW7XAdpqj5MLC/Q8uMi98oYtAC2icIj9jdgMYjNYrznf0YsTj/MOjzCbTXO48RR5XaJ35k2yMBCoGIBov2yLSztNPpHCpwKROKHVOPF8X5rCeIv1BuMMK1GOI02nyZsiH769DVcBYXRneuhSJ8I5FCmAsNomrbPsrWzGeocTz1x2ht0VtXxKj/Jl+v1y0dCg/vVMl4daXKg12mtCq9lf0xGcaLnA2Mw7hidfTGhL5+ygROp/v/HQQLB4tPlMzcjk8EftOTk7KHr1hP4T0NKvFp0vqyl5F18YFLse/wPLHlqRZqo3CAAAAABJRU5ErkJggg== -EOFILE; -$gifLogo = <<< EOFILE -iVBORw0KGgoAAAANSUhEUgAAAGAAAABTCAYAAABgdgI7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ -bWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdp -bj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6 -eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEz -NDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJo -dHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlw -dGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEu -MC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVz -b3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1N -Ok9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1ODg0QkM3NUZBMDhFMDExODkyQ0U2NkE5ODVB -M0Q2OSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoyMEQ2RDU5MDA5M0UxMUUwOUUwRkYwRTg2 -NjQyMzQzQyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoyMEQ2RDU4RjA5M0UxMUUwOUUwRkYw -RTg2NjQyMzQzQyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3Mi -PiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo1ODg0QkM3NUZB -MDhFMDExODkyQ0U2NkE5ODVBM0Q2OSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo1ODg0QkM3 -NUZBMDhFMDExODkyQ0U2NkE5ODVBM0Q2OSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRG -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 -EOFILE; -$pngPlugin = <<< EOFILE -iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsSAAALEgHS3X78AAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAABmklEQVR42mL4//8/AyUYIIDAxK5du1BwXEb3/9D4FjBOzZ/wH10ehkF6AQIIw4B1G7b+D09o/h+X3gXG4YmteA0ACCCsLghPbPkfm9b5PzK5439Sdg9eAwACCEyANMBwaFwTGIMMAOEQIBuGA6Mb/qMbABBAEAOQnIyMo1M74Tgiqf2/b3gVhgEAAQQmQuKa/8ekdYMxyLCgmEYMHJXc9t87FNMAgACCGgBxIkgzyDaQU5FxQGQN2AUBUXX/vULKwdgjsOQ/SC9AAKEEYlB03f+oFJABdSjYP6L6P0guIqkVjt0DisEGAAQQigEgG0AhHxBVi4L9wqvBBiEHtqs/xACAAAIbEBBd/x+Eg2ObwH4FORmGfYCaQRikCUS7B5YBNReBMUgvQABBDADaAtIIwsEx9f/Dk9pQsH9kHTh8XANKMAIRIIDAhF9ELTiQQH4FaQAZCAsskPNhyRpkK7oBAAEEMSC8GsVGkEaYIlBghcU3gbGzL6YBAAEEJnzCgP6EYs/gcjCGKQI5G4Z9QiswDAAIIAZKszNAgAEAHgFgGSNMTwgAAAAASUVORK5CYII= -EOFILE; -$pngWrench = <<< EOFILE -iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAA3NCSVQICAjb4U/gAAABO1BMVEXu7u7n5+fk5OTi4uLg4ODd3d3X19fV1dXU1NTS0tLPz8+7z+/MzMy6zu65ze65zu7Kysq3zO62zO3IyMjHx8e1yOiyyO2yyOzFxcXExMSyxue0xuexxefDw8OtxeuwxOXCwsLBwcGuxOWsw+q/v7+qweqqwuqrwuq+vr6nv+qmv+m7u7ukvumkvemivOi5ubm4uLicuOebuOeat+e0tLSYtuabtuaatuaXteaZteaatN6Xs+aVs+WTsuaTsuWRsOSrq6uLreKoqKinp6elpaWLqNijo6OFpt2CpNyAo92BotyAo9+dnZ18oNqbm5t4nt57nth7ntp4nt15ndp3nd6ZmZmYmJhym956mtJzm96WlpaVlZVwmNyTk5Nvl9lultuSkpKNjY2Li4uKioqIiIiHh4eGhoZQgtVKfNFdha6iAAAAaXRSTlMA//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////914ivwAAAACXBIWXMAAAsSAAALEgHS3X78AAAAH3RFWHRTb2Z0d2FyZQBNYWNyb21lZGlhIEZpcmV3b3JrcyA4tWjSeAAAAKFJREFUGJVjYIABASc/PwYkIODDxBCNLODEzGiQgCwQxsTlzJCYmAgXiGKVdHFxYEuB8dkTOIS1tRUVocaIWiWI8IiIKKikaoD50kYWrpwmKSkpsRC+lBk3t2NEMgtMu4wpr5aeuHcAjC9vzadjYyjn7w7lK9kK6tqZK4d4wBQECenZW6pHesEdFC9mbK0W7otwsqenqmpMILIn4tIzgpG4ADUpGMOpkOiuAAAAAElFTkSuQmCC -EOFILE; -$favicon = <<< EOFILE -iVBORw0KGgoAAAANSUhEUgAAAB8AAAAfCAYAAAAfrhY5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ -bWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdp -bj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6 -eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEz -NDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJo -dHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlw -dGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEu -MC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVz -b3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1N -Ok9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1ODg0QkM3NUZBMDhFMDExODkyQ0U2NkE5ODVB -M0Q2OSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxRkI1ODNGRTA5MDMxMUUwQjAwNEEwODc0 -OTk5N0ZEOCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxRkI1ODNGRDA5MDMxMUUwQjAwNEEw -ODc0OTk5N0ZEOCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3Mi -PiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo1ODg0QkM3NUZB -MDhFMDExODkyQ0U2NkE5ODVBM0Q2OSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo1ODg0QkM3 -NUZBMDhFMDExODkyQ0U2NkE5ODVBM0Q2OSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRG -PiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PiUukzAAAAHHSURBVHja5FfRccIwDLVz -/W+7QdggbJBM0HQCwg+/LRNwTJDymx9ggmYDsgEZwRuUDVI5ET1XyE5CuIa76k7ABVtPluQnRVZV -JcYST4woD85/ZRbC5wxUf/sdbZagBehGVAvlNM+GXWYaaIugQ+QDdA1OnLqByyyAzwPo042iqyMx -BwdKN7jMNODREWKFyonv2KdPPqERoDlPGQMKQ7drPWPjfAy6Inb080/QiK/2Js8JMacBpzWwzGIs -QFdxhujkFMNtSkj3m1ftjTnxEg0f0XNXAYb1mmatwFPSFM1s4NTwuUp18QU9CiyonWj2rhkHWXAK -kNeh7gdMQ5wzRdnKcAo9DwZcsRBtqL70qm7Ior3B/5zbI0IKrvv8mxarhXSsXtrY8m5OfjB+F5SN -BkhKrpi8635uaxAvkO9HpgZSB/v57f2cFpEQzz+UeZ28Yvq+bMXpkb5rSgwLc+Z5Fylwb+y68x4p -MlNW2CLnPUmnrE/d7F1dOGXJ+Qb0neQqre9ptZiAscTI38ng7YTQ8g6Budlg75pktkxPV9idctss -1mGYOKciupsxatQB8pJkmkUTpgCvHZ0jDtg+t4/60vAf3tVGBf8WYAC3Rq8Ub3mHyQAAAABJRU5E -rkJggg== -EOFILE; - - -//affichage du phpinfo -if (isset($_GET['phpinfo'])) -{ - phpinfo(); - exit(); -} - - -//affichage des images -if (isset($_GET['img'])) -{ - switch ($_GET['img']) - { - case 'pngFolder' : - header("Content-type: image/png"); - echo base64_decode($pngFolder); - exit(); - - case 'pngFolderGo' : - header("Content-type: image/png"); - echo base64_decode($pngFolderGo); - exit(); - - case 'gifLogo' : - header("Content-type: image/gif"); - echo base64_decode($gifLogo); - exit(); - - case 'pngPlugin' : - header("Content-type: image/png"); - echo base64_decode($pngPlugin); - exit(); - - case 'pngWrench' : - header("Content-type: image/png"); - echo base64_decode($pngWrench); - exit(); - - case 'favicon' : - header("Content-type: image/x-icon"); - echo base64_decode($favicon); - exit(); - } -} - - - -// Définition de la langue et des textes - -if (isset ($_GET['lang'])) -{ - $langue = htmlspecialchars($_GET['lang'],ENT_QUOTES); - if ($langue != 'en' && $langue != 'fr' ) { - $langue = 'fr'; - } - } -elseif (isset ($_SERVER['HTTP_ACCEPT_LANGUAGE']) AND preg_match("/^fr/", $_SERVER['HTTP_ACCEPT_LANGUAGE'])) -{ - $langue = 'fr'; -} -else -{ - $langue = 'en'; -} - -//initialisation -$aliasContents = ''; - -// récupération des alias -if (is_dir($aliasDir)) -{ - $handle=opendir($aliasDir); - while (($file = readdir($handle))!==false) - { - if (is_file($aliasDir.$file) && strstr($file, '.conf')) - { - $msg = ''; - $aliasContents .= '
  • '.str_replace('.conf','',$file).'
  • '; - } - } - closedir($handle); -} -if (empty($aliasContents)) - $aliasContents = "
  • ".$langues[$langue]['txtNoAlias']."
  • \n"; - -// récupération des projets -$handle=opendir("."); -$projectContents = ''; -while (($file = readdir($handle))!==false) -{ - if (is_dir($file) && !in_array($file,$projectsListIgnore)) - { - //[modif oto] Ajout éventuel de http:// pour éviter le niveau localhost dans les url - $projectContents .= '
  • '.$file.'
  • '; - } -} -closedir($handle); -if (empty($projectContents)) - $projectContents = "
  • ".$langues[$langue]['txtNoProjet']."
  • \n";; - - -//initialisation -$phpExtContents = ''; - -// récupération des extensions PHP -$loaded_extensions = get_loaded_extensions(); -// [modif oto] classement alphabétique des extensions -setlocale(LC_ALL,"{$langues[$langue]['locale']}"); -sort($loaded_extensions,SORT_LOCALE_STRING); -foreach ($loaded_extensions as $extension) - $phpExtContents .= "
  • ${extension}
  • "; - - -//header('Status: 301 Moved Permanently', false, 301); -//header('Location: /aviatechno/index.php'); -//exit(); - -$pageContents = <<< EOPAGE - - - - - - {$langues[$langue]['titreHtml']} - - - - - - - - - - - -

    {$langues[$langue]['titreConf']}

    - -
    -
    {$langues[$langue]['versa']}
    -
    ${apacheVersion}  - Documentation
    -
    {$langues[$langue]['versp']}
    -
    ${phpVersion}  - Documentation
    -
    {$langues[$langue]['server']}
    -
    ${server_software}
    -
    {$langues[$langue]['phpExt']}
    -
    -
      - ${phpExtContents} -
    -
    -
    {$langues[$langue]['versm']}
    -
    ${mysqlVersion}  -  Documentation
    -
    -
    -
    -

    {$langues[$langue]['titrePage']}

    - -
    -
    -

    {$langues[$langue]['txtProjet']}

    -
      - $projectContents -
    -
    -
    -

    {$langues[$langue]['txtAlias']}

    -
      - ${aliasContents} -
    -
    -
    - - - -EOPAGE; - -echo $pageContents; -?> \ No newline at end of file diff --git a/www/testmysql.php b/www/testmysql.php deleted file mode 100644 index fdb5dd88..00000000 --- a/www/testmysql.php +++ /dev/null @@ -1,7 +0,0 @@ - \ No newline at end of file From 863e006830e0c135e2c80993530d8f7065e9fc47 Mon Sep 17 00:00:00 2001 From: TheManii Date: Mon, 11 Apr 2016 17:00:26 -0400 Subject: [PATCH 09/21] Converted initial profile + appearence to new db schema, currently only read only due to submit functions being unmodified --- www/control_panel_edit_character.php | 115 ++++++++++++++++++++------- www/database.php | 19 +++++ 2 files changed, 106 insertions(+), 28 deletions(-) diff --git a/www/control_panel_edit_character.php b/www/control_panel_edit_character.php index 2af1ddbf..721fc439 100644 --- a/www/control_panel_edit_character.php +++ b/www/control_panel_edit_character.php @@ -61,12 +61,12 @@ $g_htmlToDbFieldMapping = array( "characterSkinColor" => "skinColor", "characterHairStyle" => "hairStyle", "characterHairColor" => "hairColor", - "characterHairOption" => "hairOption", + "characterHairOption" => "hairVariation", "characterEyeColor" => "eyeColor", "characterFaceType" => "faceType", - "characterFaceBrow" => "faceBrow", - "characterFaceEye" => "faceEye", - "characterFaceIris" => "faceIris", + "characterFaceBrow" => "faceEyebrows", + "characterFaceEye" => "faceEyeShape", + "characterFaceIris" => "faceIrisSize", "characterFaceNose" => "faceNose", "characterFaceMouth" => "faceMouth", "characterFaceJaw" => "faceJaw", @@ -76,7 +76,7 @@ $g_htmlToDbFieldMapping = array( "characterGuardian" => "guardian", "characterBirthMonth" => "birthMonth", "characterBirthDay" => "birthDay", - "characterAllegiance" => "allegiance", + "characterAllegiance" => "initialTown", "characterWeapon1" => "weapon1", "characterWeapon2" => "weapon2", "characterHeadGear" => "headGear", @@ -91,6 +91,58 @@ $g_htmlToDbFieldMapping = array( "characterLeftFingerGear" => "leftFingerGear" ); +$g_profileMapping = array( + "characterName" => "name", +/* + "characterIsLegacy" => "islegacy", + "characterPlayTime" => "playTime", + "characterPositionX" => "positionX", + "characterPositionY" => "positionY", + "characterPositionZ" => "positionZ", + "characterPositionR" => "rotation", + "characterCurrentZoneId" => "currentZoneId", +*/ + "characterGuardian" => "guardian", + "characterBirthDay" => "birthDay", + "characterBirthMonth" => "birthMonth", + "characterAllegiance" => "initialTown", + "characterTribe" => "tribe" +/* + "characterGcCurrent" => "gcCurrent", + "characterGcLimsaRank" => "gcLimsaRank", + "characterGcGridaniaRank" => "gcGridaniaRank", + "characterGcUldahRank" => "gcUldahRank", + "characterCurrentTitle" => "currentTitle", + "characterRestBonus" => "restBonus", + "characterAchievementPoints" => "achievementPoints", +*/ +); + +$g_appearanceMapping = array( +/* + "characterBaseId" => "baseId", +*/ + "characterSize" => "size", + "characterVoice" => "voice", + "characterSkinColor" => "skinColor", + "characterHairStyle" => "hairStyle", + "characterHairColor" => "hairColor", +/* "characterHairHighlightColor" => "hairHighlightColor", */ + "characterHairOption" => "hairVariation", + "characterEyeColor" => "eyeColor", + "characterFaceType" => "faceType", + "characterFaceBrow" => "faceEyebrows", + "characterFaceEye" => "faceEyeShape", + "characterFaceIris" => "faceIrisSize", + "characterFaceNose" => "faceNose", + "characterFaceMouth" => "faceMouth", + "characterFaceJaw" => "faceFeatures", + "characterFaceCheek" => "ears", + "characterFaceOption1" => "characteristics", + "characterFaceOption2" => "characteristicsColor" +); + + function SaveCharacter($databaseConnection, $htmlFieldMapping, $characterId) { $characterInfo = array(); @@ -140,6 +192,7 @@ if(isset($_POST["save"])) try { $g_characterInfo = GetCharacterInfo($g_databaseConnection, $g_userId, $g_characterId); + $g_characterAppearance = GetCharacterAppearance($g_databaseConnection, $g_userId, $g_characterId); } catch(Exception $e) { @@ -364,7 +417,7 @@ catch(Exception $e) Name: - + Guardian: @@ -373,10 +426,10 @@ catch(Exception $e) Allegiance: - - - - + + + +
    @@ -389,7 +442,7 @@ catch(Exception $e) Tribe: - + Size: @@ -398,10 +451,10 @@ catch(Exception $e) Hair Style: - - - - + + + + Hair Color: @@ -410,10 +463,10 @@ catch(Exception $e) Face Type: - - - - + + + + Face Brow: @@ -422,10 +475,10 @@ catch(Exception $e) Face Nose: - - - - + + + + Face Mouth: @@ -434,10 +487,10 @@ catch(Exception $e) Face Option 1: - - - - + + + + Face Option 2: @@ -446,9 +499,10 @@ catch(Exception $e) - + +

    + +
    diff --git a/www/database.php b/www/database.php index 79aabc0b..b20b52f8 100644 --- a/www/database.php +++ b/www/database.php @@ -341,6 +341,25 @@ function GetCharacterInfo($dataConnection, $userId, $characterId) return $row; } +function GetCharacterAppearance($dataConnection, $userId, $characterId) +{ + $query = sprintf("SELECT * FROM characters_appearance INNER JOIN characters ON characters_appearance.characterId = characters.id WHERE characters.userId = '%d' AND characters.Id='%d'", + $userId, $characterId); + $result = $dataConnection->query($query); + if(!$result) + { + throw new Exception(__FUNCTION__ . " failed: " . $dataConnection->error); + } + + $row = $result->fetch_assoc(); + if(!$row) + { + throw new Exception(__FUNCTION__ . " failed: " . $dataConnection->error); + } + + return $row; +} + function UpdateCharacterInfo($dataConnection, $characterId, $characterInfo) { $statement = $dataConnection->prepare("UPDATE ffxiv_characters SET From 108f5aa67732c1a43ee78c92d019dddfc9520935 Mon Sep 17 00:00:00 2001 From: Filip Maj Date: Mon, 11 Apr 2016 22:49:05 -0400 Subject: [PATCH 10/21] Fixed crash due to bad constructor for QuestDirectorMan0L001. Unsigned integers will also write out as lua 0-datatype. --- .../actors/director/quest/QuestDirectorMan0L001..cs | 2 +- FFXIVClassic Map Server/lua/LuaUtils.cs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/FFXIVClassic Map Server/actors/director/quest/QuestDirectorMan0L001..cs b/FFXIVClassic Map Server/actors/director/quest/QuestDirectorMan0L001..cs index 6f00a12a..d7f2bfd0 100644 --- a/FFXIVClassic Map Server/actors/director/quest/QuestDirectorMan0L001..cs +++ b/FFXIVClassic Map Server/actors/director/quest/QuestDirectorMan0L001..cs @@ -32,7 +32,7 @@ namespace FFXIVClassic_Map_Server.actors.director public override SubPacket createScriptBindPacket(uint playerActorId) { List lParams; - lParams = LuaUtils.createLuaParamList("/Director/Quest/QuestDirectorMan0l001", false, false, false, false, 0x7532); + lParams = LuaUtils.createLuaParamList("/Director/Quest/QuestDirectorMan0l001", false, false, false, false, false, 0x7532); return ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, className, lParams); } } diff --git a/FFXIVClassic Map Server/lua/LuaUtils.cs b/FFXIVClassic Map Server/lua/LuaUtils.cs index 38410542..101b9fd3 100644 --- a/FFXIVClassic Map Server/lua/LuaUtils.cs +++ b/FFXIVClassic Map Server/lua/LuaUtils.cs @@ -121,7 +121,11 @@ namespace FFXIVClassic_Map_Server { foreach (LuaParam l in luaParams) { - writer.Write((Byte)l.typeID); + if (l.typeID == 0x1) + writer.Write((Byte)0); + else + writer.Write((Byte)l.typeID); + switch (l.typeID) { case 0x0: //Int32 From 14a7a4172a2c90b2a75ed724f48a15ec63957b50 Mon Sep 17 00:00:00 2001 From: TheManii Date: Thu, 14 Apr 2016 03:44:05 -0400 Subject: [PATCH 11/21] Added rest of fields, chocobo fields are disabled as they dont work if there is no chocobo entries for a character --- www/control_panel_edit_character.php | 274 ++++++++++++++++++++------- www/database.php | 38 ++++ 2 files changed, 247 insertions(+), 65 deletions(-) diff --git a/www/control_panel_edit_character.php b/www/control_panel_edit_character.php index 721fc439..470b6f41 100644 --- a/www/control_panel_edit_character.php +++ b/www/control_panel_edit_character.php @@ -53,6 +53,7 @@ $g_allegiances = array( 3 => "Ul'dah", ); +/* $g_htmlToDbFieldMapping = array( "characterName" => "name", "characterTribe" => "tribe", @@ -90,12 +91,35 @@ $g_htmlToDbFieldMapping = array( "characterRightFingerGear" => "rightFingerGear", "characterLeftFingerGear" => "leftFingerGear" ); +*/ + +$g_height = array( + 0 => "Shortest", + 1 => "Short", + 2 => "Average", + 3 => "Tall", + 4 => "Tallest" +); + +$g_yesno = array( + 0 => "No", + 1 => "Yes" +); + +$g_grandcompany = array( + 0 => "None", + /* TODO: Find correct order for 1+ */ + 1 => "Maelstrom", + 2 => "Order of the Twin Adder ", + 3 => "Immortal Flames" +); $g_profileMapping = array( "characterName" => "name", -/* - "characterIsLegacy" => "islegacy", + "characterCreationDate" => "creationDate", + "characterIsLegacy" => "isLegacy", "characterPlayTime" => "playTime", +/* "characterPositionX" => "positionX", "characterPositionY" => "positionY", "characterPositionZ" => "positionZ", @@ -106,29 +130,29 @@ $g_profileMapping = array( "characterBirthDay" => "birthDay", "characterBirthMonth" => "birthMonth", "characterAllegiance" => "initialTown", - "characterTribe" => "tribe" -/* + "characterTribe" => "tribe", "characterGcCurrent" => "gcCurrent", "characterGcLimsaRank" => "gcLimsaRank", "characterGcGridaniaRank" => "gcGridaniaRank", "characterGcUldahRank" => "gcUldahRank", +/* "characterCurrentTitle" => "currentTitle", "characterRestBonus" => "restBonus", - "characterAchievementPoints" => "achievementPoints", */ + "characterAchievementPoints" => "achievementPoints", ); $g_appearanceMapping = array( /* - "characterBaseId" => "baseId", + "characterBaseId" => "baseId", // Basic appearance? */ "characterSize" => "size", "characterVoice" => "voice", "characterSkinColor" => "skinColor", "characterHairStyle" => "hairStyle", "characterHairColor" => "hairColor", -/* "characterHairHighlightColor" => "hairHighlightColor", */ - "characterHairOption" => "hairVariation", + "characterHairHighlightColor" => "hairHighlightColor", + "characterHairVariation" => "hairVariation", "characterEyeColor" => "eyeColor", "characterFaceType" => "faceType", "characterFaceBrow" => "faceEyebrows", @@ -136,12 +160,39 @@ $g_appearanceMapping = array( "characterFaceIris" => "faceIrisSize", "characterFaceNose" => "faceNose", "characterFaceMouth" => "faceMouth", - "characterFaceJaw" => "faceFeatures", - "characterFaceCheek" => "ears", - "characterFaceOption1" => "characteristics", - "characterFaceOption2" => "characteristicsColor" + "characterFaceFeatures" => "faceFeatures", + "characterFaceEars" => "ears", + "characterFaceCharacteristics" => "characteristics", + "characterFaceCharacteristicsColor" => "characteristicsColor" ); +$g_chocoboMapping = array( + "characterHasChocobo" => "hasChocobo", + "characterHasGoobbue" => "hasGoobbue", + "characterChocoboAppearance" => "chocoboAppearance", + "characterChocoboName" => "chocoboName" +); + +$g_classLevels = array( + "characterGla" => "gla", + "characterPug" => "pug", + "characterMrd" => "mrd", + "characterLnc" => "lnc", + "characterArc" => "arc", + "characterCnj" => "cnj", + "characterThm" => "thm", + "characterCrp" => "crp", + "characterBsm" => "bsm", + "characterArm" => "arm", + "characterGsm" => "gsm", + "characterLtw" => "ltw", + "characterWvr" => "wvr", + "characterAlc" => "alc", + "characterCul" => "cul", + "characterMin" => "min", + "characterBtn" => "btn", + "characterFsh" => "fsh" +); function SaveCharacter($databaseConnection, $htmlFieldMapping, $characterId) { @@ -156,7 +207,7 @@ function SaveCharacter($databaseConnection, $htmlFieldMapping, $characterId) function GenerateTextField($characterInfo, $htmlFieldMapping, $htmlFieldName, $fieldMaxLength = null) { $inputMaxLength = ($fieldMaxLength === null) ? "" : sprintf("maxlength=\"%d\"", $fieldMaxLength); - return sprintf("", + return sprintf("", $htmlFieldName, $htmlFieldName, $characterInfo[$htmlFieldMapping[$htmlFieldName]], $inputMaxLength); } @@ -193,6 +244,8 @@ try { $g_characterInfo = GetCharacterInfo($g_databaseConnection, $g_userId, $g_characterId); $g_characterAppearance = GetCharacterAppearance($g_databaseConnection, $g_userId, $g_characterId); +/* $g_characterChocobo = GetCharacterChocobo($g_databaseConnection, $g_userId, $g_characterId); */ + $g_characterClassLevels = GetCharacterClassLevels($g_databaseConnection, $g_userId, $g_characterId); } catch(Exception $e) { @@ -205,14 +258,13 @@ catch(Exception $e) - Seventh Umbral Server + Character Info