mirror of
				https://bitbucket.org/Ioncannon/project-meteor-server.git
				synced 2025-05-20 08:26:59 -04:00 
			
		
		
		
	Merge branch 'actor_instancing' into develop
# Conflicts: # sql/gamedata_actor_class.sql
This commit is contained in:
		| @@ -391,7 +391,6 @@ namespace FFXIVClassic_Lobby_Server | ||||
|                     birthMonth, | ||||
|                     initialTown, | ||||
|                     tribe, | ||||
|                     currentParty, | ||||
|                     restBonus, | ||||
|                     achievementPoints, | ||||
|                     playTime | ||||
| @@ -421,9 +420,9 @@ namespace FFXIVClassic_Lobby_Server | ||||
|                             player.playerWork.birthdayMonth = reader.GetByte(14); | ||||
|                             player.playerWork.initialTown = reader.GetByte(15); | ||||
|                             player.playerWork.tribe = reader.GetByte(16); | ||||
|                             player.playerWork.restBonusExpRate = reader.GetInt32(18); | ||||
|                             player.achievementPoints = reader.GetUInt32(19); | ||||
|                             player.playTime = reader.GetUInt32(20); | ||||
|                             player.playerWork.restBonusExpRate = reader.GetInt32(17); | ||||
|                             player.achievementPoints = reader.GetUInt32(18); | ||||
|                             player.playTime = reader.GetUInt32(19); | ||||
|                         } | ||||
|                     } | ||||
|                    | ||||
|   | ||||
| @@ -63,7 +63,9 @@ | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <Compile Include="actors\area\PrivateArea.cs" /> | ||||
|     <Compile Include="actors\area\SpawnLocation.cs" /> | ||||
|     <Compile Include="actors\area\Zone.cs" /> | ||||
|     <Compile Include="actors\chara\npc\ActorClass.cs" /> | ||||
|     <Compile Include="actors\chara\npc\NpcWork.cs" /> | ||||
|     <Compile Include="actors\chara\AetheryteWork.cs" /> | ||||
|     <Compile Include="actors\chara\player\Equipment.cs" /> | ||||
|   | ||||
| @@ -91,7 +91,9 @@ namespace FFXIVClassic_Lobby_Server | ||||
|             mWorldManager = new WorldManager(this); | ||||
|             mWorldManager.LoadZoneList(); | ||||
|             mWorldManager.LoadZoneEntranceList(); | ||||
|             mWorldManager.LoadNPCs(); | ||||
|             mWorldManager.LoadActorClasses(); | ||||
|             mWorldManager.LoadSpawnLocations(); | ||||
|             mWorldManager.spawnAllActors(); | ||||
|  | ||||
|             IPEndPoint serverEndPoint = new System.Net.IPEndPoint(IPAddress.Parse(ConfigConstants.OPTIONS_BINDIP), FFXIV_MAP_PORT); | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| using FFXIVClassic_Lobby_Server; | ||||
| using FFXIVClassic_Lobby_Server.common; | ||||
| using FFXIVClassic_Map_Server.actors.area; | ||||
| using FFXIVClassic_Map_Server.actors.chara.npc; | ||||
| using FFXIVClassic_Map_Server.Actors; | ||||
| using FFXIVClassic_Map_Server.common.EfficientHashTables; | ||||
| using FFXIVClassic_Map_Server.dataobjects; | ||||
| @@ -24,6 +25,7 @@ namespace FFXIVClassic_Map_Server | ||||
|         private WorldMaster worldMaster = new WorldMaster(); | ||||
|         private Dictionary<uint, Zone> zoneList; | ||||
|         private Dictionary<uint, ZoneEntrance> zoneEntranceList; | ||||
|         private Dictionary<uint, ActorClass> actorClasses = new Dictionary<uint,ActorClass>(); | ||||
|  | ||||
|         private Server mServer; | ||||
|  | ||||
| @@ -110,7 +112,7 @@ namespace FFXIVClassic_Map_Server | ||||
|                             if (zoneList.ContainsKey(parentZoneId)) | ||||
|                             { | ||||
|                                 Zone parent = zoneList[parentZoneId]; | ||||
|                                 PrivateArea privArea = new PrivateArea(parent, reader.GetUInt32("id"), reader.GetString("className"), reader.GetString("privateAreaName"), reader.GetUInt16("dayMusic"), reader.GetUInt16("nightMusic"), reader.GetUInt16("battleMusic")); | ||||
|                                 PrivateArea privArea = new PrivateArea(parent, reader.GetUInt32("id"), reader.GetString("className"), reader.GetString("privateAreaName"), 1, reader.GetUInt16("dayMusic"), reader.GetUInt16("nightMusic"), reader.GetUInt16("battleMusic")); | ||||
|                                 parent.addPrivateArea(privArea); | ||||
|                             } | ||||
|                             else | ||||
| @@ -182,7 +184,7 @@ namespace FFXIVClassic_Map_Server | ||||
|             Log.info(String.Format("Loaded {0} zone spawn locations.", count)); | ||||
|         } | ||||
|  | ||||
|         public void LoadNPCs() | ||||
|         public void LoadActorClasses() | ||||
|         {             | ||||
|             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))) | ||||
| @@ -194,20 +196,11 @@ namespace FFXIVClassic_Map_Server | ||||
|                     string query = @" | ||||
|                                     SELECT  | ||||
|                                     id, | ||||
|                                     name, | ||||
|                                     zoneId,                                     | ||||
|                                     positionX, | ||||
|                                     positionY, | ||||
|                                     positionZ, | ||||
|                                     rotation, | ||||
|                                     actorState, | ||||
|                                     animationId, | ||||
|                                     classPath,                                     | ||||
|                                     displayNameId, | ||||
|                                     customDisplayName, | ||||
|                                     actorClassName, | ||||
|                                     eventConditions | ||||
|                                     FROM gamedata_actor_class | ||||
|                                     WHERE name is not NULL AND zoneId > 0 | ||||
|                                     WHERE classPath <> '' | ||||
|                                     "; | ||||
|  | ||||
|                     MySqlCommand cmd = new MySqlCommand(query, conn); | ||||
| @@ -216,27 +209,19 @@ namespace FFXIVClassic_Map_Server | ||||
|                     { | ||||
|                         while (reader.Read()) | ||||
|                         { | ||||
|                             string customName = null; | ||||
|                             if (!reader.IsDBNull(10)) | ||||
|                                 customName = reader.GetString(10); | ||||
|                             uint id = reader.GetUInt32("id"); | ||||
|                             string classPath = reader.GetString("classPath"); | ||||
|                             uint nameId = reader.GetUInt32("displayNameId"); | ||||
|                             string eventConditions = null; | ||||
|                              | ||||
|                             if (!reader.IsDBNull(3)) | ||||
|                                 eventConditions = reader.GetString("eventConditions"); | ||||
|                             else | ||||
|                                 eventConditions = "{}"; | ||||
|  | ||||
|                             Npc npc = new Npc(reader.GetUInt32(0), reader.GetString(1), reader.GetUInt32(2), reader.GetFloat(3), reader.GetFloat(4), reader.GetFloat(5), reader.GetFloat(6), reader.GetUInt16(7), reader.GetUInt32(8), reader.GetUInt32(9), customName, reader.GetString(11)); | ||||
|  | ||||
|                             if (!reader.IsDBNull(12)) | ||||
|                             { | ||||
|                                 string eventConditions = reader.GetString(12); | ||||
|                                 npc.loadEventConditions(eventConditions); | ||||
|                             } | ||||
|  | ||||
|                             if (!zoneList.ContainsKey(npc.zoneId)) | ||||
|                                 continue; | ||||
|                             Zone zone = zoneList[npc.zoneId]; | ||||
|                             if (zone == null) | ||||
|                                 continue; | ||||
|                             npc.zone = zone; | ||||
|                             zone.addActorToZone(npc); | ||||
|                             ActorClass actorClass = new ActorClass(id, classPath, nameId, eventConditions); | ||||
|                             actorClasses.Add(id, actorClass); | ||||
|                             count++; | ||||
|  | ||||
|                         } | ||||
|                     } | ||||
|                     | ||||
| @@ -249,10 +234,10 @@ namespace FFXIVClassic_Map_Server | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             Log.info(String.Format("Loaded {0} npc(s).", count)); | ||||
|             Log.info(String.Format("Loaded {0} actor classes.", count)); | ||||
|         } | ||||
|  | ||||
|         public void LoadNPCs(uint zoneId) | ||||
|         public void LoadSpawnLocations() | ||||
|         { | ||||
|             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))) | ||||
| @@ -263,54 +248,60 @@ namespace FFXIVClassic_Map_Server | ||||
|  | ||||
|                     string query = @" | ||||
|                                     SELECT  | ||||
|                                     id, | ||||
|                                     name, | ||||
|                                     zoneId,                                     | ||||
|                                     actorClassId,   | ||||
|                                     uniqueId,                                   | ||||
|                                     zoneId,       | ||||
|                                     privateAreaName,                               | ||||
|                                     privateAreaLevel, | ||||
|                                     positionX, | ||||
|                                     positionY, | ||||
|                                     positionZ, | ||||
|                                     rotation, | ||||
|                                     actorState, | ||||
|                                     animationId, | ||||
|                                     displayNameId, | ||||
|                                     customDisplayName, | ||||
|                                     actorClassName, | ||||
|                                     eventConditions | ||||
|                                     FROM gamedata_actor_class | ||||
|                                     WHERE name is not NULL AND zoneId = @zoneId | ||||
|                                     customDisplayName | ||||
|                                     FROM server_spawn_locations                                     | ||||
|                                     "; | ||||
|  | ||||
|                     MySqlCommand cmd = new MySqlCommand(query, conn); | ||||
|                     cmd.Parameters.AddWithValue("@zoneId", zoneId); | ||||
|  | ||||
|                     using (MySqlDataReader reader = cmd.ExecuteReader()) | ||||
|                     { | ||||
|                         while (reader.Read()) | ||||
|                         { | ||||
|                             string customName = null; | ||||
|                             if (!reader.IsDBNull(10)) | ||||
|                                 customName = reader.GetString(10); | ||||
|                             if (!reader.IsDBNull(11)) | ||||
|                                 customName = reader.GetString("customDisplayName"); | ||||
|  | ||||
|                             Npc npc = new Npc(reader.GetUInt32(0), reader.GetString(1), reader.GetUInt32(2), reader.GetFloat(3), reader.GetFloat(4), reader.GetFloat(5), reader.GetFloat(6), reader.GetUInt16(7), reader.GetUInt32(8), reader.GetUInt32(9), customName, reader.GetString(11)); | ||||
|                             uint classId = reader.GetUInt32("actorClassId"); | ||||
|                             string uniqueId = reader.GetString("uniqueId"); | ||||
|                             uint zoneId = reader.GetUInt32("zoneId"); | ||||
|                             string privAreaName = reader.GetString("privateAreaName"); | ||||
|                             uint privAreaLevel = reader.GetUInt32("privateAreaLevel"); | ||||
|                             float x = reader.GetFloat("positionX"); | ||||
|                             float y = reader.GetFloat("positionY"); | ||||
|                             float z = reader.GetFloat("positionZ"); | ||||
|                             float rot = reader.GetFloat("rotation"); | ||||
|                             ushort state = reader.GetUInt16("actorState"); | ||||
|                             uint animId = reader.GetUInt32("animationId"); | ||||
|  | ||||
|                             if (!reader.IsDBNull(12)) | ||||
|                             { | ||||
|                                 string eventConditions = reader.GetString(12); | ||||
|                                 npc.loadEventConditions(eventConditions); | ||||
|                             } | ||||
|  | ||||
|                             if (!zoneList.ContainsKey(npc.zoneId)) | ||||
|                             if (!actorClasses.ContainsKey(classId))                                 | ||||
|                                 continue; | ||||
|                             Zone zone = zoneList[npc.zoneId]; | ||||
|                             if (!zoneList.ContainsKey(zoneId)) | ||||
|                                 continue; | ||||
|  | ||||
|                             Zone zone = zoneList[zoneId]; | ||||
|                             if (zone == null) | ||||
|                                 continue; | ||||
|                             npc.zone = zone; | ||||
|                             zone.addActorToZone(npc); | ||||
|                             count++; | ||||
|  | ||||
|                             SpawnLocation spawn = new SpawnLocation(classId, uniqueId, zoneId, privAreaName, privAreaLevel, x, y, z, rot, state, animId); | ||||
|  | ||||
|                             zone.addSpawnLocation(spawn); | ||||
|  | ||||
|                             count++; | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                      | ||||
|                 } | ||||
|                 catch (MySqlException e) | ||||
|                 { Console.WriteLine(e); } | ||||
| @@ -320,7 +311,14 @@ namespace FFXIVClassic_Map_Server | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             Log.info(String.Format("Loaded {0} npc(s).", count)); | ||||
|             Log.info(String.Format("Loaded {0} spawn(s).", count)); | ||||
|         } | ||||
|  | ||||
|         public void spawnAllActors() | ||||
|         { | ||||
|             Log.info("Spawning actors..."); | ||||
|             foreach (Zone z in zoneList.Values) | ||||
|                 z.spawnAllActors(true); | ||||
|         } | ||||
|  | ||||
|         //Moves the actor to the new zone if exists. No packets are sent nor position changed. | ||||
| @@ -473,7 +471,7 @@ namespace FFXIVClassic_Map_Server | ||||
|  | ||||
|             Zone zone = zoneList[zoneId]; | ||||
|             //zone.clear(); | ||||
|             LoadNPCs(zone.actorId); | ||||
|             //LoadNPCs(zone.actorId); | ||||
|  | ||||
|         } | ||||
|  | ||||
| @@ -556,6 +554,15 @@ namespace FFXIVClassic_Map_Server | ||||
|             else | ||||
|                 return null; | ||||
|         } | ||||
|  | ||||
|         public ActorClass GetActorClass(uint id) | ||||
|         { | ||||
|             if (actorClasses.ContainsKey(id)) | ||||
|                 return actorClasses[id]; | ||||
|             else | ||||
|                 return null; | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -18,7 +18,7 @@ using System.Text; | ||||
| namespace FFXIVClassic_Map_Server.Actors | ||||
| { | ||||
|     class Actor | ||||
|     {         | ||||
|     {                | ||||
|         public uint actorId; | ||||
|         public string actorName; | ||||
|  | ||||
| @@ -38,6 +38,7 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|  | ||||
|         public bool spawnedFirstTime = false; | ||||
|  | ||||
|         public string classPath; | ||||
|         public string className; | ||||
|         public List<LuaParam> classParams; | ||||
|  | ||||
| @@ -307,6 +308,53 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|             SubPacket changeSpeedPacket = SetActorSpeedPacket.buildPacket(actorId, actorId, moveSpeeds[0], moveSpeeds[1], moveSpeeds[2]); | ||||
|             zone.broadcastPacketAroundActor(this, changeSpeedPacket); | ||||
|         } | ||||
|          | ||||
|         public void generateActorName(int actorNumber) | ||||
|         { | ||||
|             //Format Class Name | ||||
|             string className = this.className.Replace("Populace", "Ppl") | ||||
|                                              .Replace("Monster", "Mon") | ||||
|                                              .Replace("Crowd", "Crd") | ||||
|                                              .Replace("MapObj", "Map") | ||||
|                                              .Replace("Object", "Obj") | ||||
|                                              .Replace("Retainer", "Rtn") | ||||
|                                              .Replace("Standard", "Std");             | ||||
|             className = Char.ToLowerInvariant(className[0]) + className.Substring(1); | ||||
|  | ||||
|             //Format Zone Name | ||||
|             string zoneName = zone.zoneName.Replace("Field", "Fld") | ||||
|                                            .Replace("Dungeon", "Dgn") | ||||
|                                            .Replace("Town", "Twn") | ||||
|                                            .Replace("Battle", "Btl") | ||||
|                                            .Replace("Test", "Tes") | ||||
|                                            .Replace("Event", "Evt") | ||||
|                                            .Replace("Ship", "Shp") | ||||
|                                            .Replace("Office", "Ofc"); | ||||
|             if (zone is PrivateArea) | ||||
|             { | ||||
|                 //Check if "normal" | ||||
|                 zoneName = zoneName.Remove(zoneName.Length - 1, 1) + "P"; | ||||
|             } | ||||
|             zoneName = Char.ToLowerInvariant(zoneName[0]) + zoneName.Substring(1); | ||||
|  | ||||
|             try | ||||
|             { | ||||
|                 className = className.Substring(0, 20 - zoneName.Length); | ||||
|             } | ||||
|             catch (ArgumentOutOfRangeException e) | ||||
|             {} | ||||
|  | ||||
|             //Convert actor number to base 63 | ||||
|             string classNumber = Utils.ToStringBase63(actorNumber); | ||||
|  | ||||
|             //Get stuff after @ | ||||
|             uint zoneId = zone.actorId; | ||||
|             uint privLevel = 0; | ||||
|             if (zone is PrivateArea) | ||||
|                 privLevel = ((PrivateArea)zone).getPrivateAreaLevel(); | ||||
|  | ||||
|             actorName = String.Format("{0}_{1}_{2}@{3:X3}{4:X2}", className, zoneName, classNumber, zoneId, privLevel); | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,8 @@ | ||||
| using FFXIVClassic_Lobby_Server.common; | ||||
| using FFXIVClassic_Lobby_Server; | ||||
| using FFXIVClassic_Lobby_Server.common; | ||||
| using FFXIVClassic_Lobby_Server.packets; | ||||
| using FFXIVClassic_Map_Server.actors.area; | ||||
| using FFXIVClassic_Map_Server.actors.chara.npc; | ||||
| using FFXIVClassic_Map_Server.dataobjects; | ||||
| using FFXIVClassic_Map_Server.dataobjects.chara; | ||||
| using FFXIVClassic_Map_Server.lua; | ||||
| @@ -21,15 +24,16 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|         public ushort weatherNormal, weatherCommon, weatherRare; | ||||
|         public ushort bgmDay, bgmNight, bgmBattle; | ||||
|  | ||||
|         private string classPath; | ||||
|         protected string classPath; | ||||
|  | ||||
|         public int boundingGridSize = 50; | ||||
|         public int minX = -1000, minY = -1000, maxX = 1000, maxY = 1000; | ||||
|         private int numXBlocks, numYBlocks; | ||||
|         private int halfWidth, halfHeight; | ||||
|         protected int numXBlocks, numYBlocks; | ||||
|         protected int halfWidth, halfHeight; | ||||
|  | ||||
|         private Dictionary<uint, Actor> mActorList = new Dictionary<uint,Actor>(); | ||||
|         private List<Actor>[,] mActorBlock; | ||||
|         protected List<SpawnLocation> mSpawnLocations = new List<SpawnLocation>(); | ||||
|         protected Dictionary<uint, Actor> mActorList = new Dictionary<uint, Actor>(); | ||||
|         protected List<Actor>[,] mActorBlock; | ||||
|  | ||||
|         Script areaScript; | ||||
|  | ||||
| @@ -335,5 +339,18 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|             }             | ||||
|         } | ||||
|  | ||||
|         public void spawnActor(SpawnLocation location) | ||||
|         { | ||||
|             ActorClass actorClass = Server.GetWorldManager().GetActorClass(location.classId); | ||||
|              | ||||
|             if (actorClass == null) | ||||
|                 return; | ||||
|  | ||||
|             Npc npc = new Npc(mActorList.Count + 1, actorClass.actorClassId, location.uniqueId, actorId, location.x, location.y, location.z, location.rot, location.state, location.animId, actorClass.displayNameId, null, actorClass.classPath); | ||||
|             npc.loadEventConditions(actorClass.eventConditions);             | ||||
|  | ||||
|             addActorToZone(npc);                           | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -14,12 +14,14 @@ namespace FFXIVClassic_Map_Server.actors.area | ||||
|     { | ||||
|         private Zone parentZone; | ||||
|         private string privateAreaName; | ||||
|         private uint privateAreaLevel; | ||||
|  | ||||
|         public PrivateArea(Zone parent, uint id, string className, string privateAreaName,ushort bgmDay, ushort bgmNight, ushort bgmBattle) | ||||
|         public PrivateArea(Zone parent, uint id, string className, string privateAreaName, uint privateAreaLevel, ushort bgmDay, ushort bgmNight, ushort bgmBattle) | ||||
|             : base(id, parent.zoneName, parent.regionId, className, bgmDay, bgmNight, bgmBattle, parent.isIsolated, parent.isInn, parent.canRideChocobo, parent.canStealth, true) | ||||
|         { | ||||
|             this.parentZone = parent; | ||||
|             this.privateAreaName = privateAreaName; | ||||
|             this.privateAreaLevel = privateAreaLevel; | ||||
|         } | ||||
|  | ||||
|         public string getPrivateAreaName() | ||||
| @@ -27,6 +29,11 @@ namespace FFXIVClassic_Map_Server.actors.area | ||||
|             return privateAreaName; | ||||
|         } | ||||
|  | ||||
|         public uint getPrivateAreaLevel() | ||||
|         { | ||||
|             return privateAreaLevel; | ||||
|         } | ||||
|  | ||||
|         public Zone getParentZone() | ||||
|         { | ||||
|             return parentZone; | ||||
| @@ -45,6 +52,17 @@ namespace FFXIVClassic_Map_Server.actors.area | ||||
|             ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, className, lParams).debugPrintSubPacket(); | ||||
|             return ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, className, lParams); | ||||
|         } | ||||
|          | ||||
|  | ||||
|  | ||||
|         public void addSpawnLocation(SpawnLocation spawn) | ||||
|         { | ||||
|             mSpawnLocations.Add(spawn); | ||||
|         } | ||||
|  | ||||
|         public void spawnAllActors() | ||||
|         { | ||||
|             foreach (SpawnLocation spawn in mSpawnLocations) | ||||
|                 spawnActor(spawn); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										38
									
								
								FFXIVClassic Map Server/actors/area/SpawnLocation.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								FFXIVClassic Map Server/actors/area/SpawnLocation.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace FFXIVClassic_Map_Server.actors.area | ||||
| { | ||||
|     class SpawnLocation | ||||
|     { | ||||
|         public uint classId; | ||||
|         public string uniqueId; | ||||
|         public uint zoneId; | ||||
|         public string privAreaName; | ||||
|         public uint privAreaLevel; | ||||
|         public float x; | ||||
|         public float y; | ||||
|         public float z; | ||||
|         public float rot; | ||||
|         public ushort state; | ||||
|         public uint animId; | ||||
|  | ||||
|         public SpawnLocation(uint classId, string uniqueId, uint zoneId, string privAreaName, uint privAreaLevel, float x, float y, float z, float rot, ushort state, uint animId) | ||||
|         { | ||||
|             this.classId = classId; | ||||
|             this.uniqueId = uniqueId; | ||||
|             this.zoneId = zoneId; | ||||
|             this.privAreaName = privAreaName; | ||||
|             this.privAreaLevel = privAreaLevel; | ||||
|             this.x = x; | ||||
|             this.y = y; | ||||
|             this.z = z; | ||||
|             this.rot = rot; | ||||
|             this.state = state; | ||||
|             this.animId = animId; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,4 +1,7 @@ | ||||
| using FFXIVClassic_Lobby_Server.packets; | ||||
| using FFXIVClassic_Lobby_Server; | ||||
| using FFXIVClassic_Lobby_Server.common; | ||||
| using FFXIVClassic_Lobby_Server.packets; | ||||
| using FFXIVClassic_Map_Server.actors.chara.npc; | ||||
| using FFXIVClassic_Map_Server.Actors; | ||||
| using FFXIVClassic_Map_Server.lua; | ||||
| using FFXIVClassic_Map_Server.packets.send.actor; | ||||
| @@ -11,7 +14,7 @@ using System.Threading.Tasks; | ||||
| namespace FFXIVClassic_Map_Server.actors.area | ||||
| { | ||||
|     class Zone : Area | ||||
|     { | ||||
|     {         | ||||
|         Dictionary<string, Dictionary<uint, PrivateArea>> privateAreas = new Dictionary<string, Dictionary<uint, PrivateArea>>(); | ||||
|  | ||||
|         public Zone(uint id, string zoneName, ushort regionId, string className, ushort bgmDay, ushort bgmNight, ushort bgmBattle, bool isIsolated, bool isInn, bool canRideChocobo, bool canStealth, bool isInstanceRaid) | ||||
| @@ -54,5 +57,40 @@ namespace FFXIVClassic_Map_Server.actors.area | ||||
|             return ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, className, lParams);         | ||||
|         } | ||||
|  | ||||
|         public void addSpawnLocation(SpawnLocation spawn) | ||||
|         { | ||||
|             //Is it in a private area? | ||||
|             if (!spawn.privAreaName.Equals("")) | ||||
|             { | ||||
|                 if (privateAreas.ContainsKey(spawn.privAreaName)) | ||||
|                 { | ||||
|                     Dictionary<uint, PrivateArea> levels = privateAreas[spawn.privAreaName]; | ||||
|                     if (levels.ContainsKey(spawn.privAreaLevel)) | ||||
|                         levels[spawn.privAreaLevel].addSpawnLocation(spawn); | ||||
|                     else | ||||
|                         Log.error(String.Format("Tried to add a spawn location to non-existing private area level \"{0}\" in area {1} in zone {2}", spawn.privAreaName, spawn.privAreaLevel, zoneName)); | ||||
|                 } | ||||
|                 else | ||||
|                     Log.error(String.Format("Tried to add a spawn location to non-existing private area \"{0}\" in zone {1}", spawn.privAreaName, zoneName)); | ||||
|             } | ||||
|             else             | ||||
|                 mSpawnLocations.Add(spawn);             | ||||
|         } | ||||
|  | ||||
|         public void spawnAllActors(bool doPrivAreas) | ||||
|         { | ||||
|             foreach (SpawnLocation spawn in mSpawnLocations)             | ||||
|                 spawnActor(spawn); | ||||
|  | ||||
|             if (doPrivAreas) | ||||
|             { | ||||
|                 foreach (Dictionary<uint, PrivateArea> areas in privateAreas.Values) | ||||
|                 { | ||||
|                     foreach (PrivateArea pa in areas.Values) | ||||
|                         pa.spawnAllActors(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										24
									
								
								FFXIVClassic Map Server/actors/chara/npc/ActorClass.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								FFXIVClassic Map Server/actors/chara/npc/ActorClass.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace FFXIVClassic_Map_Server.actors.chara.npc | ||||
| { | ||||
|     class ActorClass | ||||
|     { | ||||
|         public readonly uint actorClassId; | ||||
|         public readonly string classPath; | ||||
|         public readonly uint displayNameId; | ||||
|         public readonly string eventConditions; | ||||
|  | ||||
|         public ActorClass(uint id, string classPath, uint nameId, string eventConditions) | ||||
|         { | ||||
|             this.actorClassId = id; | ||||
|             this.classPath = classPath; | ||||
|             this.displayNameId = nameId; | ||||
|             this.eventConditions = eventConditions; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -5,12 +5,15 @@ using FFXIVClassic_Map_Server.actors; | ||||
| using FFXIVClassic_Map_Server.Actors.Chara; | ||||
| using FFXIVClassic_Map_Server.dataobjects; | ||||
| using FFXIVClassic_Map_Server.lua; | ||||
| using FFXIVClassic_Map_Server.packets.receive.events; | ||||
| using FFXIVClassic_Map_Server.packets.send.actor; | ||||
| using FFXIVClassic_Map_Server.utils; | ||||
| using MoonSharp.Interpreter; | ||||
| using MySql.Data.MySqlClient; | ||||
| using Newtonsoft.Json; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using System.Threading.Tasks; | ||||
| @@ -20,27 +23,33 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|     class Npc : Character | ||||
|     { | ||||
|         private uint actorClassId; | ||||
|         private string uniqueIdentifier; | ||||
|  | ||||
|         public NpcWork npcWork = new NpcWork(); | ||||
|  | ||||
|         public Npc(uint id, string actorName, uint zoneId, float posX, float posY, float posZ, float rot, ushort actorState, uint animationId, uint displayNameId, string customDisplayName, string className) | ||||
|             : base(id) | ||||
|         public Npc(int actorNumber, uint classId, string uniqueId, uint zoneId, float posX, float posY, float posZ, float rot, ushort actorState, uint animationId, uint displayNameId, string customDisplayName, string classPath) | ||||
|             : base((4 << 28 | zoneId << 19 | (uint)actorNumber))   | ||||
|         { | ||||
|             this.actorName = actorName; | ||||
|             this.actorClassId = id; | ||||
|             this.positionX = posX; | ||||
|             this.positionY = posY; | ||||
|             this.positionZ = posZ; | ||||
|             this.rotation = rot; | ||||
|             this.animationId = animationId; | ||||
|             this.className = className; | ||||
|  | ||||
|             this.displayNameId = displayNameId; | ||||
|             this.customDisplayName = customDisplayName; | ||||
|  | ||||
|             this.zoneId = zoneId; | ||||
|             this.uniqueIdentifier = uniqueId; | ||||
|  | ||||
|             loadNpcTemplate(id); | ||||
|             this.zoneId = zoneId; | ||||
|             this.zone = Server.GetWorldManager().GetZone(zoneId); | ||||
|  | ||||
|             this.actorClassId = classId; | ||||
|  | ||||
|             loadNpcAppearance(classId); | ||||
|  | ||||
|             this.classPath = classPath; | ||||
|             className = classPath.Substring(classPath.LastIndexOf("/")+1); | ||||
|  | ||||
|             charaWork.battleSave.potencial = 1.0f; | ||||
|  | ||||
| @@ -61,6 +70,11 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|  | ||||
|             charaWork.property[3] = 1; | ||||
|             charaWork.property[4] = 1; | ||||
|  | ||||
|             npcWork.pushCommand = 0x271D; | ||||
|             npcWork.pushCommandPriority = 1; | ||||
|  | ||||
|             generateActorName((int)actorNumber);             | ||||
|         } | ||||
|  | ||||
|         public SubPacket createAddActorPacket(uint playerActorId) | ||||
| @@ -68,19 +82,34 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|             return AddActorPacket.buildPacket(actorId, playerActorId, 8); | ||||
|         } | ||||
|  | ||||
|         // actorClassId, [], [], numBattleCommon, [battleCommon], numEventCommon, [eventCommon], args for either initForBattle/initForEvent | ||||
|         public override SubPacket createScriptBindPacket(uint playerActorId) | ||||
|         { | ||||
|             List<LuaParam> lParams; | ||||
|  | ||||
|             Player player = Server.GetWorldManager().GetPCInWorld(playerActorId); | ||||
|             lParams = LuaEngine.doActorInstantiate(player, this); | ||||
|             lParams = DoActorInit(player);             | ||||
|  | ||||
|             if (lParams == null) | ||||
|             { | ||||
|                 className = "PopulaceStandard"; | ||||
|                 lParams = LuaUtils.createLuaParamList("/Chara/Npc/Populace/PopulaceStandard", false, false, false, false, false, 0xF47F6, false, false, 0, 1, "TEST"); | ||||
|                 string classPathFake = "/Chara/Npc/Populace/PopulaceStandard"; | ||||
|                 string classNameFake = "PopulaceStandard"; | ||||
|                 lParams = LuaUtils.createLuaParamList(classPathFake, false, false, false, false, false, 0xF47F6, false, false, 0, 0); | ||||
|                 ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, classNameFake, lParams).debugPrintSubPacket(); | ||||
|                 return ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, classNameFake, lParams); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 lParams.Insert(0, new LuaParam(2, classPath)); | ||||
|                 lParams.Insert(1, new LuaParam(4, 4)); | ||||
|                 lParams.Insert(2, new LuaParam(4, 4)); | ||||
|                 lParams.Insert(3, new LuaParam(4, 4)); | ||||
|                 lParams.Insert(4, new LuaParam(4, 4)); | ||||
|                 lParams.Insert(5, new LuaParam(4, 4)); | ||||
|                 lParams.Insert(6, new LuaParam(0, (int)actorClassId)); | ||||
|             } | ||||
|  | ||||
|             ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, className, lParams).debugPrintSubPacket(); | ||||
|             return ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, className, lParams); | ||||
|         } | ||||
|  | ||||
| @@ -147,6 +176,8 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|             } | ||||
|  | ||||
|             propPacketUtil.addProperty("npcWork.hateType"); | ||||
|             propPacketUtil.addProperty("npcWork.pushCommand"); | ||||
|             propPacketUtil.addProperty("npcWork.pushCommandPriority"); | ||||
|  | ||||
|             return BasePacket.createPacket(propPacketUtil.done(), true, false); | ||||
|         } | ||||
| @@ -156,7 +187,7 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|             return actorClassId; | ||||
|         } | ||||
|  | ||||
|         public void loadNpcTemplate(uint id) | ||||
|         public void loadNpcAppearance(uint id) | ||||
|         { | ||||
|             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))) | ||||
|             { | ||||
| @@ -171,7 +202,7 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|                                     hairStyle, | ||||
|                                     hairHighlightColor, | ||||
|                                     hairVariation, | ||||
|                                     faceType, | ||||
|                                     faceType,    | ||||
|                                     characteristics, | ||||
|                                     characteristicsColor, | ||||
|                                     faceEyebrows, | ||||
| @@ -225,17 +256,25 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|                             appearanceIds[Character.HIGHLIGHT_HAIR] = (uint)(reader.GetUInt32(3) | reader.GetUInt32(2) << 10); //5- Hair Highlight, 4 - Hair Style | ||||
|                             appearanceIds[Character.VOICE] = reader.GetUInt32(17); | ||||
|                             appearanceIds[Character.MAINHAND] = reader.GetUInt32(19); | ||||
|                             //appearanceIds[Character.WEAPON2] = reader.GetUInt32(22); | ||||
|                             appearanceIds[Character.OFFHAND] = reader.GetUInt32(20); | ||||
|                             appearanceIds[Character.SPMAINHAND] = reader.GetUInt32(21); | ||||
|                             appearanceIds[Character.SPOFFHAND] = reader.GetUInt32(22); | ||||
|                             appearanceIds[Character.THROWING] = reader.GetUInt32(23); | ||||
|                             appearanceIds[Character.PACK] = reader.GetUInt32(24); | ||||
|                             appearanceIds[Character.POUCH] = reader.GetUInt32(25); | ||||
|                             appearanceIds[Character.HEADGEAR] = reader.GetUInt32(26); | ||||
|                             appearanceIds[Character.BODYGEAR] = reader.GetUInt32(27); | ||||
|                             appearanceIds[Character.LEGSGEAR] = reader.GetUInt32(28); | ||||
|                             appearanceIds[Character.HANDSGEAR] = reader.GetUInt32(29); | ||||
|                             appearanceIds[Character.FEETGEAR] = reader.GetUInt32(30); | ||||
|                             appearanceIds[Character.WAISTGEAR] = reader.GetUInt32(31); | ||||
|                             appearanceIds[Character.R_EAR] = reader.GetUInt32(32); | ||||
|                             appearanceIds[Character.L_EAR] = reader.GetUInt32(33); | ||||
|                             appearanceIds[Character.R_RINGFINGER] = reader.GetUInt32(36); | ||||
|                             appearanceIds[Character.L_RINGFINGER] = reader.GetUInt32(37); | ||||
|                             appearanceIds[Character.NECKGEAR] = reader.GetUInt32(32); | ||||
|                             appearanceIds[Character.R_EAR] = reader.GetUInt32(33); | ||||
|                             appearanceIds[Character.L_EAR] = reader.GetUInt32(34); | ||||
|                             appearanceIds[Character.R_INDEXFINGER] = reader.GetUInt32(35); | ||||
|                             appearanceIds[Character.L_INDEXFINGER] = reader.GetUInt32(36); | ||||
|                             appearanceIds[Character.R_RINGFINGER] = reader.GetUInt32(37); | ||||
|                             appearanceIds[Character.L_RINGFINGER] = reader.GetUInt32(38); | ||||
|  | ||||
|                         } | ||||
|                     } | ||||
| @@ -255,5 +294,127 @@ namespace FFXIVClassic_Map_Server.Actors | ||||
|             EventList conditions = JsonConvert.DeserializeObject<EventList>(eventConditions); | ||||
|             this.eventConditions = conditions; | ||||
|         } | ||||
|  | ||||
|         public List<LuaParam> DoActorInit(Player player) | ||||
|         { | ||||
|             Script parent = null, child = null; | ||||
|  | ||||
|             if (File.Exists("./scripts/base/" + classPath + ".lua")) | ||||
|                 parent = LuaEngine.loadScript("./scripts/base/" + classPath + ".lua"); | ||||
|             if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier))) | ||||
|                 child = LuaEngine.loadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier)); | ||||
|  | ||||
|             if (parent == null && child == null) | ||||
|             { | ||||
|                 LuaEngine.SendError(player, String.Format("ERROR: Could not find script for actor {0}.", getName())); | ||||
|                 return null; | ||||
|             } | ||||
|  | ||||
|             DynValue result; | ||||
|                              | ||||
|             if (child != null && child.Globals["init"] != null) | ||||
|                 result = child.Call(child.Globals["init"], this); | ||||
|             else if (parent.Globals["init"] != null) | ||||
|                 result = parent.Call(parent.Globals["init"], this); | ||||
|             else | ||||
|                 return null; | ||||
|  | ||||
|             List<LuaParam> lparams = LuaUtils.createLuaParamList(result); | ||||
|             return lparams;           | ||||
|         } | ||||
|  | ||||
|         public void DoEventStart(Player player, EventStartPacket eventStart) | ||||
|         { | ||||
|             Script parent = null, child = null; | ||||
|  | ||||
|             if (File.Exists("./scripts/base/" + classPath + ".lua")) | ||||
|                 parent = LuaEngine.loadScript("./scripts/base/" + classPath + ".lua"); | ||||
|             if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier))) | ||||
|                 child = LuaEngine.loadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier)); | ||||
|  | ||||
|             if (parent == null) | ||||
|             { | ||||
|                 LuaEngine.SendError(player, String.Format("ERROR: Could not find script for actor {0}.", getName())); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             //Have to do this to combine LuaParams | ||||
|             List<Object> objects = new List<Object>(); | ||||
|             objects.Add(player); | ||||
|             objects.Add(this); | ||||
|             objects.Add(eventStart.triggerName); | ||||
|  | ||||
|             if (eventStart.luaParams != null) | ||||
|                 objects.AddRange(LuaUtils.createLuaParamObjectList(eventStart.luaParams)); | ||||
|  | ||||
|             //Run Script | ||||
|             DynValue result; | ||||
|  | ||||
|             if (child != null && !child.Globals.Get("onEventStarted").IsNil()) | ||||
|                 result = child.Call(child.Globals["onEventStarted"], objects.ToArray()); | ||||
|             else if (!parent.Globals.Get("onEventStarted").IsNil()) | ||||
|                 result = parent.Call(parent.Globals["onEventStarted"], objects.ToArray()); | ||||
|             else | ||||
|                 return; | ||||
|  | ||||
|         } | ||||
|  | ||||
|         public void DoEventUpdate(Player player, EventUpdatePacket eventUpdate) | ||||
|         { | ||||
|             Script parent = null, child = null; | ||||
|  | ||||
|             if (File.Exists("./scripts/base/" + classPath + ".lua")) | ||||
|                 parent = LuaEngine.loadScript("./scripts/base/" + classPath + ".lua"); | ||||
|             if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier))) | ||||
|                 child = LuaEngine.loadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier)); | ||||
|  | ||||
|             if (parent == null) | ||||
|             { | ||||
|                 LuaEngine.SendError(player, String.Format("ERROR: Could not find script for actor {0}.", getName())); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             //Have to do this to combine LuaParams | ||||
|             List<Object> objects = new List<Object>(); | ||||
|             objects.Add(player); | ||||
|             objects.Add(this); | ||||
|             objects.Add(eventUpdate.val2); | ||||
|             objects.AddRange(LuaUtils.createLuaParamObjectList(eventUpdate.luaParams)); | ||||
|  | ||||
|             //Run Script | ||||
|             DynValue result; | ||||
|  | ||||
|             if (child != null && !child.Globals.Get("onEventUpdate").IsNil()) | ||||
|                 result = child.Call(child.Globals["onEventUpdate"], objects.ToArray()); | ||||
|             else if (!parent.Globals.Get("onEventUpdate").IsNil()) | ||||
|                 result = parent.Call(parent.Globals["onEventUpdate"], objects.ToArray()); | ||||
|             else | ||||
|                 return; | ||||
|  | ||||
|         } | ||||
|  | ||||
|         internal void DoOnActorSpawn(Player player) | ||||
|         { | ||||
|             Script parent = null, child = null; | ||||
|  | ||||
|             if (File.Exists("./scripts/base/" + classPath + ".lua")) | ||||
|                 parent = LuaEngine.loadScript("./scripts/base/" + classPath + ".lua"); | ||||
|             if (File.Exists(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier))) | ||||
|                 child = LuaEngine.loadScript(String.Format("./scripts/unique/{0}/{1}/{2}.lua", zone.zoneName, className, uniqueIdentifier)); | ||||
|  | ||||
|             if (parent == null) | ||||
|             { | ||||
|                 LuaEngine.SendError(player, String.Format("ERROR: Could not find script for actor {0}.", getName())); | ||||
|                 return; | ||||
|             } | ||||
|                 | ||||
|             //Run Script | ||||
|             if (child != null && !child.Globals.Get("onSpawn").IsNil()) | ||||
|                 child.Call(child.Globals["onSpawn"], player, this); | ||||
|             else if (!parent.Globals.Get("onSpawn").IsNil()) | ||||
|                 parent.Call(parent.Globals["onSpawn"], player, this); | ||||
|             else | ||||
|                 return;                 | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -302,5 +302,15 @@ namespace FFXIVClassic_Lobby_Server.common | ||||
|             return (value >> bits) | (value << (16 - bits)); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         public static string ToStringBase63(int number) | ||||
|         { | ||||
|             string lookup = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; | ||||
|  | ||||
|             string secondDigit = lookup.Substring((int)Math.Floor((double)number / (double)lookup.Length), 1); | ||||
|             string firstDigit = lookup.Substring(number % lookup.Length, 1); | ||||
|  | ||||
|             return secondDigit + firstDigit; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -150,7 +150,7 @@ namespace FFXIVClassic_Map_Server.dataobjects | ||||
|  | ||||
|                     if (actor is Npc) | ||||
|                     { | ||||
|                         LuaEngine.doActorOnSpawn(getActor(), (Npc)actor); | ||||
|                         ((Npc)actor).DoOnActorSpawn(playerActor); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|   | ||||
| @@ -62,6 +62,12 @@ namespace FFXIVClassic_Map_Server.lua | ||||
|  | ||||
|         public static void doActorOnEventStarted(Player player, Actor target, EventStartPacket eventStart) | ||||
|         { | ||||
|             if (target is Npc) | ||||
|             { | ||||
|                 ((Npc)target).DoEventStart(player, eventStart); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             string luaPath; | ||||
|  | ||||
|             if (target is Command) | ||||
| @@ -126,6 +132,12 @@ namespace FFXIVClassic_Map_Server.lua | ||||
|  | ||||
|         public static void doActorOnEventUpdated(Player player, Actor target, EventUpdatePacket eventUpdate) | ||||
|         { | ||||
|             if (target is Npc) | ||||
|             { | ||||
|                 ((Npc)target).DoEventUpdate(player, eventUpdate); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             string luaPath;  | ||||
|  | ||||
|             if (target is Command)             | ||||
| @@ -206,7 +218,7 @@ namespace FFXIVClassic_Map_Server.lua | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private static Script loadScript(string filename) | ||||
|         public static Script loadScript(string filename) | ||||
|         { | ||||
|             Script script = new Script(); | ||||
|             ((FileSystemScriptLoader)script.Options.ScriptLoader).ModulePaths = FileSystemScriptLoader.UnpackStringPaths("./scripts/?;./scripts/?.lua"); | ||||
| @@ -227,7 +239,7 @@ namespace FFXIVClassic_Map_Server.lua | ||||
|             return script; | ||||
|         } | ||||
|  | ||||
|         private static void SendError(Player player, string message) | ||||
|         public static void SendError(Player player, string message) | ||||
|         { | ||||
|             List<SubPacket> sendError = new List<SubPacket>(); | ||||
|             sendError.Add(EndEventPacket.buildPacket(player.actorId, player.currentEventOwner, player.currentEventName)); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user