Implemented actor instancing, as well as automatic name generation for NPCs.

This commit is contained in:
Filip Maj 2016-05-29 15:14:09 -04:00
parent 541456bd8e
commit 62ed9b22f1
12 changed files with 278 additions and 82 deletions

View File

@ -391,7 +391,6 @@ namespace FFXIVClassic_Lobby_Server
birthMonth, birthMonth,
initialTown, initialTown,
tribe, tribe,
currentParty,
restBonus, restBonus,
achievementPoints, achievementPoints,
playTime playTime
@ -421,9 +420,9 @@ namespace FFXIVClassic_Lobby_Server
player.playerWork.birthdayMonth = reader.GetByte(14); player.playerWork.birthdayMonth = reader.GetByte(14);
player.playerWork.initialTown = reader.GetByte(15); player.playerWork.initialTown = reader.GetByte(15);
player.playerWork.tribe = reader.GetByte(16); player.playerWork.tribe = reader.GetByte(16);
player.playerWork.restBonusExpRate = reader.GetInt32(18); player.playerWork.restBonusExpRate = reader.GetInt32(17);
player.achievementPoints = reader.GetUInt32(19); player.achievementPoints = reader.GetUInt32(18);
player.playTime = reader.GetUInt32(20); player.playTime = reader.GetUInt32(19);
} }
} }

View File

@ -63,7 +63,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="actors\area\PrivateArea.cs" /> <Compile Include="actors\area\PrivateArea.cs" />
<Compile Include="actors\area\SpawnLocation.cs" />
<Compile Include="actors\area\Zone.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\npc\NpcWork.cs" />
<Compile Include="actors\chara\AetheryteWork.cs" /> <Compile Include="actors\chara\AetheryteWork.cs" />
<Compile Include="actors\chara\player\Equipment.cs" /> <Compile Include="actors\chara\player\Equipment.cs" />

View File

@ -91,7 +91,9 @@ namespace FFXIVClassic_Lobby_Server
mWorldManager = new WorldManager(this); mWorldManager = new WorldManager(this);
mWorldManager.LoadZoneList(); mWorldManager.LoadZoneList();
mWorldManager.LoadZoneEntranceList(); mWorldManager.LoadZoneEntranceList();
mWorldManager.LoadNPCs(); mWorldManager.LoadActorClasses();
mWorldManager.LoadSpawnLocations();
mWorldManager.spawnAllActors();
IPEndPoint serverEndPoint = new System.Net.IPEndPoint(IPAddress.Parse(ConfigConstants.OPTIONS_BINDIP), FFXIV_MAP_PORT); IPEndPoint serverEndPoint = new System.Net.IPEndPoint(IPAddress.Parse(ConfigConstants.OPTIONS_BINDIP), FFXIV_MAP_PORT);

View File

@ -1,6 +1,7 @@
using FFXIVClassic_Lobby_Server; using FFXIVClassic_Lobby_Server;
using FFXIVClassic_Lobby_Server.common; using FFXIVClassic_Lobby_Server.common;
using FFXIVClassic_Map_Server.actors.area; using FFXIVClassic_Map_Server.actors.area;
using FFXIVClassic_Map_Server.actors.chara.npc;
using FFXIVClassic_Map_Server.Actors; using FFXIVClassic_Map_Server.Actors;
using FFXIVClassic_Map_Server.common.EfficientHashTables; using FFXIVClassic_Map_Server.common.EfficientHashTables;
using FFXIVClassic_Map_Server.dataobjects; using FFXIVClassic_Map_Server.dataobjects;
@ -24,6 +25,7 @@ namespace FFXIVClassic_Map_Server
private WorldMaster worldMaster = new WorldMaster(); private WorldMaster worldMaster = new WorldMaster();
private Dictionary<uint, Zone> zoneList; private Dictionary<uint, Zone> zoneList;
private Dictionary<uint, ZoneEntrance> zoneEntranceList; private Dictionary<uint, ZoneEntrance> zoneEntranceList;
private Dictionary<uint, ActorClass> actorClasses = new Dictionary<uint,ActorClass>();
private Server mServer; private Server mServer;
@ -110,7 +112,7 @@ namespace FFXIVClassic_Map_Server
if (zoneList.ContainsKey(parentZoneId)) if (zoneList.ContainsKey(parentZoneId))
{ {
Zone parent = zoneList[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); parent.addPrivateArea(privArea);
} }
else else
@ -182,7 +184,7 @@ namespace FFXIVClassic_Map_Server
Log.info(String.Format("Loaded {0} zone spawn locations.", count)); Log.info(String.Format("Loaded {0} zone spawn locations.", count));
} }
public void LoadNPCs() public void LoadActorClasses()
{ {
int count = 0; 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))) 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 = @" string query = @"
SELECT SELECT
id, id,
name, classPath,
zoneId,
positionX,
positionY,
positionZ,
rotation,
actorState,
animationId,
displayNameId, displayNameId,
customDisplayName,
actorClassName,
eventConditions eventConditions
FROM gamedata_actor_class FROM gamedata_actor_class
WHERE name is not NULL AND zoneId > 0 WHERE classPath <> '' AND eventConditions is not NULL
"; ";
MySqlCommand cmd = new MySqlCommand(query, conn); MySqlCommand cmd = new MySqlCommand(query, conn);
@ -216,27 +209,14 @@ namespace FFXIVClassic_Map_Server
{ {
while (reader.Read()) while (reader.Read())
{ {
string customName = null; uint id = reader.GetUInt32("id");
if (!reader.IsDBNull(10)) string classPath = reader.GetString("classPath");
customName = reader.GetString(10); uint nameId = reader.GetUInt32("displayNameId");
string eventConditions = reader.GetString("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)); ActorClass actorClass = new ActorClass(id, classPath, nameId, eventConditions);
actorClasses.Add(id, actorClass);
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);
count++; count++;
} }
} }
@ -249,10 +229,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; 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))) 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,25 +243,21 @@ namespace FFXIVClassic_Map_Server
string query = @" string query = @"
SELECT SELECT
id, actorClassId,
name,
zoneId, zoneId,
privateAreaName,
privateAreaLevel,
positionX, positionX,
positionY, positionY,
positionZ, positionZ,
rotation, rotation,
actorState, actorState,
animationId, animationId,
displayNameId, customDisplayName
customDisplayName, FROM server_spawn_locations
actorClassName,
eventConditions
FROM gamedata_actor_class
WHERE name is not NULL AND zoneId = @zoneId
"; ";
MySqlCommand cmd = new MySqlCommand(query, conn); MySqlCommand cmd = new MySqlCommand(query, conn);
cmd.Parameters.AddWithValue("@zoneId", zoneId);
using (MySqlDataReader reader = cmd.ExecuteReader()) using (MySqlDataReader reader = cmd.ExecuteReader())
{ {
@ -289,25 +265,33 @@ namespace FFXIVClassic_Map_Server
{ {
string customName = null; string customName = null;
if (!reader.IsDBNull(10)) if (!reader.IsDBNull(10))
customName = reader.GetString(10); 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");
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)) if (!actorClasses.ContainsKey(classId))
{
string eventConditions = reader.GetString(12);
npc.loadEventConditions(eventConditions);
}
if (!zoneList.ContainsKey(npc.zoneId))
continue; continue;
Zone zone = zoneList[npc.zoneId]; if (!zoneList.ContainsKey(zoneId))
continue;
Zone zone = zoneList[zoneId];
if (zone == null) if (zone == null)
continue; continue;
npc.zone = zone;
zone.addActorToZone(npc);
count++;
SpawnLocation spawn = new SpawnLocation(classId, zoneId, privAreaName, privAreaLevel, x, y, z, rot, state, animId);
zone.addSpawnLocation(spawn);
count++;
} }
} }
@ -320,7 +304,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. //Moves the actor to the new zone if exists. No packets are sent nor position changed.
@ -473,7 +464,7 @@ namespace FFXIVClassic_Map_Server
Zone zone = zoneList[zoneId]; Zone zone = zoneList[zoneId];
//zone.clear(); //zone.clear();
LoadNPCs(zone.actorId); //LoadNPCs(zone.actorId);
} }
@ -556,6 +547,15 @@ namespace FFXIVClassic_Map_Server
else else
return null; return null;
} }
public ActorClass GetActorClass(uint id)
{
if (actorClasses.ContainsKey(id))
return actorClasses[id];
else
return null;
}
} }
} }

View File

@ -308,6 +308,53 @@ namespace FFXIVClassic_Map_Server.Actors
zone.broadcastPacketAroundActor(this, changeSpeedPacket); 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);
}
} }
} }

View File

@ -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_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;
using FFXIVClassic_Map_Server.dataobjects.chara; using FFXIVClassic_Map_Server.dataobjects.chara;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
@ -21,15 +24,16 @@ namespace FFXIVClassic_Map_Server.Actors
public ushort weatherNormal, weatherCommon, weatherRare; public ushort weatherNormal, weatherCommon, weatherRare;
public ushort bgmDay, bgmNight, bgmBattle; public ushort bgmDay, bgmNight, bgmBattle;
private string classPath; protected string classPath;
public int boundingGridSize = 50; public int boundingGridSize = 50;
public int minX = -1000, minY = -1000, maxX = 1000, maxY = 1000; public int minX = -1000, minY = -1000, maxX = 1000, maxY = 1000;
private int numXBlocks, numYBlocks; protected int numXBlocks, numYBlocks;
private int halfWidth, halfHeight; protected int halfWidth, halfHeight;
private Dictionary<uint, Actor> mActorList = new Dictionary<uint,Actor>(); protected List<SpawnLocation> mSpawnLocations = new List<SpawnLocation>();
private List<Actor>[,] mActorBlock; protected Dictionary<uint, Actor> mActorList = new Dictionary<uint, Actor>();
protected List<Actor>[,] mActorBlock;
Script areaScript; 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, actorId, location.x, location.y, location.z, location.rot, location.state, location.animId, actorClass.displayNameId, null, actorClass.classPath);
npc.loadEventConditions(actorClass.eventConditions);
addActorToZone(npc);
}
} }
} }

View File

@ -14,12 +14,14 @@ namespace FFXIVClassic_Map_Server.actors.area
{ {
private Zone parentZone; private Zone parentZone;
private string privateAreaName; 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) : base(id, parent.zoneName, parent.regionId, className, bgmDay, bgmNight, bgmBattle, parent.isIsolated, parent.isInn, parent.canRideChocobo, parent.canStealth, true)
{ {
this.parentZone = parent; this.parentZone = parent;
this.privateAreaName = privateAreaName; this.privateAreaName = privateAreaName;
this.privateAreaLevel = privateAreaLevel;
} }
public string getPrivateAreaName() public string getPrivateAreaName()
@ -27,6 +29,11 @@ namespace FFXIVClassic_Map_Server.actors.area
return privateAreaName; return privateAreaName;
} }
public uint getPrivateAreaLevel()
{
return privateAreaLevel;
}
public Zone getParentZone() public Zone getParentZone()
{ {
return parentZone; return parentZone;
@ -46,5 +53,16 @@ namespace FFXIVClassic_Map_Server.actors.area
return ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, className, lParams); 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);
}
} }
} }

View File

@ -0,0 +1,36 @@
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 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, uint zoneId, string privAreaName, uint privAreaLevel, float x, float y, float z, float rot, ushort state, uint animId)
{
this.classId = classId;
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;
}
}
}

View File

@ -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.Actors;
using FFXIVClassic_Map_Server.lua; using FFXIVClassic_Map_Server.lua;
using FFXIVClassic_Map_Server.packets.send.actor; using FFXIVClassic_Map_Server.packets.send.actor;
@ -54,5 +57,40 @@ namespace FFXIVClassic_Map_Server.actors.area
return ActorInstantiatePacket.buildPacket(actorId, playerActorId, actorName, className, lParams); 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();
}
}
}
} }
} }

View 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;
}
}
}

View File

@ -23,11 +23,9 @@ namespace FFXIVClassic_Map_Server.Actors
public NpcWork npcWork = new NpcWork(); 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) public Npc(int actorNumber, uint classId, uint zoneId, float posX, float posY, float posZ, float rot, ushort actorState, uint animationId, uint displayNameId, string customDisplayName, string classPath)
: base(id) : base((4 << 28 | zoneId << 19 | (uint)actorNumber))
{ {
this.actorName = actorName;
this.actorClassId = id;
this.positionX = posX; this.positionX = posX;
this.positionY = posY; this.positionY = posY;
this.positionZ = posZ; this.positionZ = posZ;
@ -39,8 +37,11 @@ namespace FFXIVClassic_Map_Server.Actors
this.customDisplayName = customDisplayName; this.customDisplayName = customDisplayName;
this.zoneId = zoneId; this.zoneId = zoneId;
this.zone = Server.GetWorldManager().GetZone(zoneId);
loadNpcTemplate(id); loadNpcAppearance(classId);
className = classPath.Substring(classPath.LastIndexOf("/")+1);
charaWork.battleSave.potencial = 1.0f; charaWork.battleSave.potencial = 1.0f;
@ -61,6 +62,8 @@ namespace FFXIVClassic_Map_Server.Actors
charaWork.property[3] = 1; charaWork.property[3] = 1;
charaWork.property[4] = 1; charaWork.property[4] = 1;
generateActorName((int)actorNumber);
} }
public SubPacket createAddActorPacket(uint playerActorId) public SubPacket createAddActorPacket(uint playerActorId)
@ -156,7 +159,7 @@ namespace FFXIVClassic_Map_Server.Actors
return actorClassId; 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))) 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)))
{ {

View File

@ -302,5 +302,15 @@ namespace FFXIVClassic_Lobby_Server.common
return (value >> bits) | (value << (16 - bits)); 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;
}
} }
} }