537 lines
18 KiB
Plaintext
537 lines
18 KiB
Plaintext
// Name : Avlis Persistence System include
|
||
// Purpose : Various APS/NWNX2 related functions
|
||
// Authors : Ingmar Stieger, Adam Colon, Josh Simon
|
||
// Modified : December 21, 2003
|
||
|
||
// Changes by FastFrench to include important optimisation fixes
|
||
// as part of the NWN-FF Package
|
||
|
||
// This file is licensed under the terms of the
|
||
// GNU GENERAL PUBLIC LICENSE (GPL) Version 2
|
||
|
||
/************************************/
|
||
/* Return codes */
|
||
/************************************/
|
||
|
||
// FF: better put those as constants.
|
||
const int SQL_ERROR = 0;
|
||
const int SQL_SUCCESS = 1;
|
||
|
||
/************************************/
|
||
/* Function prototypes */
|
||
/************************************/
|
||
|
||
// Setup placeholders for ODBC requests and responses
|
||
void SQLInit();
|
||
|
||
// Execute statement in sSQL
|
||
void SQLExecDirect(string sSQL);
|
||
|
||
// Position cursor on next row of the resultset
|
||
// Call this before using SQLGetData().
|
||
// returns: SQL_SUCCESS if there is a row
|
||
// SQL_ERROR if there are no more rows
|
||
int SQLFetch();
|
||
|
||
// * deprecated. Use SQLFetch instead.
|
||
// Position cursor on first row of the resultset and name it sResultSetName
|
||
// Call this before using SQLNextRow() and SQLGetData().
|
||
// returns: SQL_SUCCESS if result set is not empty
|
||
// SQL_ERROR is result set is empty
|
||
int SQLFirstRow();
|
||
|
||
// * deprecated. Use SQLFetch instead.
|
||
// Position cursor on next row of the result set sResultSetName
|
||
// returns: SQL_SUCCESS if cursor could be advanced to next row
|
||
// SQL_ERROR if there was no next row
|
||
int SQLNextRow();
|
||
|
||
// Return value of column iCol in the current row of result set sResultSetName
|
||
string SQLGetData(int iCol);
|
||
|
||
// Return a string value when given a location
|
||
string APSLocationToString(location lLocation);
|
||
|
||
// Return a location value when given the string form of the location
|
||
location APSStringToLocation(string sLocation);
|
||
|
||
// Return a string value when given a vector
|
||
string APSVectorToString(vector vVector);
|
||
|
||
// Return a vector value when given the string form of the vector
|
||
vector APSStringToVector(string sVector);
|
||
|
||
// Set oObject's persistent string variable sVarName to sValue
|
||
// Optional parameters:
|
||
// iExpiration: Number of days the persistent variable should be kept in database (default: 0=forever)
|
||
// sTable: Name of the table where variable should be stored (default: pwdata)
|
||
void SetPersistentString(object oObject, string sVarName, string sValue, int iExpiration =
|
||
0, string sTable = "pwdata");
|
||
|
||
// Set oObject's persistent integer variable sVarName to iValue
|
||
// Optional parameters:
|
||
// iExpiration: Number of days the persistent variable should be kept in database (default: 0=forever)
|
||
// sTable: Name of the table where variable should be stored (default: pwdata)
|
||
void SetPersistentInt(object oObject, string sVarName, int iValue, int iExpiration =
|
||
0, string sTable = "pwdata");
|
||
|
||
// Set oObject's persistent float variable sVarName to fValue
|
||
// Optional parameters:
|
||
// iExpiration: Number of days the persistent variable should be kept in database (default: 0=forever)
|
||
// sTable: Name of the table where variable should be stored (default: pwdata)
|
||
void SetPersistentFloat(object oObject, string sVarName, float fValue, int iExpiration =
|
||
0, string sTable = "pwdata");
|
||
|
||
// Set oObject's persistent location variable sVarName to lLocation
|
||
// Optional parameters:
|
||
// iExpiration: Number of days the persistent variable should be kept in database (default: 0=forever)
|
||
// sTable: Name of the table where variable should be stored (default: pwdata)
|
||
// This function converts location to a string for storage in the database.
|
||
void SetPersistentLocation(object oObject, string sVarName, location lLocation, int iExpiration =
|
||
0, string sTable = "pwdata");
|
||
|
||
// Set oObject's persistent vector variable sVarName to vVector
|
||
// Optional parameters:
|
||
// iExpiration: Number of days the persistent variable should be kept in database (default: 0=forever)
|
||
// sTable: Name of the table where variable should be stored (default: pwdata)
|
||
// This function converts vector to a string for storage in the database.
|
||
void SetPersistentVector(object oObject, string sVarName, vector vVector, int iExpiration =
|
||
0, string sTable = "pwdata");
|
||
|
||
// Get oObject's persistent string variable sVarName
|
||
// Optional parameters:
|
||
// sTable: Name of the table where variable is stored (default: pwdata)
|
||
// * Return value on error: ""
|
||
string GetPersistentString(object oObject, string sVarName, string sTable = "pwdata");
|
||
|
||
// Get oObject's persistent integer variable sVarName
|
||
// Optional parameters:
|
||
// sTable: Name of the table where variable is stored (default: pwdata)
|
||
// * Return value on error: 0
|
||
int GetPersistentInt(object oObject, string sVarName, string sTable = "pwdata");
|
||
|
||
// Get oObject's persistent float variable sVarName
|
||
// Optional parameters:
|
||
// sTable: Name of the table where variable is stored (default: pwdata)
|
||
// * Return value on error: 0
|
||
float GetPersistentFloat(object oObject, string sVarName, string sTable = "pwdata");
|
||
|
||
// Get oObject's persistent location variable sVarName
|
||
// Optional parameters:
|
||
// sTable: Name of the table where variable is stored (default: pwdata)
|
||
// * Return value on error: 0
|
||
location GetPersistentLocation(object oObject, string sVarname, string sTable = "pwdata");
|
||
|
||
// Get oObject's persistent vector variable sVarName
|
||
// Optional parameters:
|
||
// sTable: Name of the table where variable is stored (default: pwdata)
|
||
// * Return value on error: 0
|
||
vector GetPersistentVector(object oObject, string sVarName, string sTable = "pwdata");
|
||
|
||
// Delete persistent variable sVarName stored on oObject
|
||
// Optional parameters:
|
||
// sTable: Name of the table where variable is stored (default: pwdata)
|
||
void DeletePersistentVariable(object oObject, string sVarName, string sTable = "pwdata");
|
||
|
||
// (private function) Replace special character ' with ~
|
||
string SQLEncodeSpecialChars(string sString);
|
||
|
||
// (private function)Replace special character ' with ~
|
||
string SQLDecodeSpecialChars(string sString);
|
||
|
||
/************************************/
|
||
/* Implementation */
|
||
/************************************/
|
||
|
||
// Functions for initializing APS and working with result sets
|
||
object oSpecific=OBJECT_INVALID;
|
||
|
||
object GetNWNMySQLWP()
|
||
{
|
||
if (oSpecific != OBJECT_INVALID) return oSpecific;
|
||
return oSpecific = GetWaypointByTag("NWN_MySQL_WP");
|
||
}
|
||
|
||
|
||
void SQLInit()
|
||
{
|
||
int i;
|
||
|
||
// Placeholder for ODBC persistence
|
||
string sMemory;
|
||
|
||
for (i = 0; i < 8; i++) // reserve 8*128 bytes
|
||
sMemory +=
|
||
"<22>...............................................................................................................................";
|
||
sMemory = sMemory+sMemory; // 2KB
|
||
sMemory = sMemory+sMemory; // 4KB
|
||
|
||
oSpecific = GetWaypointByTag("NWN_MySQL_WP");
|
||
if (oSpecific == OBJECT_INVALID)
|
||
oSpecific = CreateObject(OBJECT_TYPE_WAYPOINT, "nw_waypoint001",GetStartingLocation(),FALSE,"NWN_MySQL_WP");
|
||
|
||
SetLocalString(oSpecific, "NWNX!ODBC!SPACER", sMemory);
|
||
}
|
||
|
||
void SQLExecDirect(string sSQL)
|
||
{
|
||
SetLocalString(GetNWNMySQLWP(), "NWNX!ODBC!EXEC", sSQL);
|
||
}
|
||
|
||
int SQLFetch()
|
||
{
|
||
string sRow;
|
||
object oModule = GetNWNMySQLWP();
|
||
|
||
SetLocalString(oModule, "NWNX!ODBC!FETCH", GetLocalString(oModule, "NWNX!ODBC!SPACER"));
|
||
sRow = GetLocalString(oModule, "NWNX!ODBC!FETCH");
|
||
if (GetStringLength(sRow) > 0)
|
||
{
|
||
SetLocalString(oModule, "NWNX_ODBC_CurrentRow", sRow);
|
||
return SQL_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
SetLocalString(oModule, "NWNX_ODBC_CurrentRow", "");
|
||
return SQL_ERROR;
|
||
}
|
||
}
|
||
|
||
// deprecated. use SQLFetch().
|
||
int SQLFirstRow()
|
||
{
|
||
return SQLFetch();
|
||
}
|
||
|
||
// deprecated. use SQLFetch().
|
||
int SQLNextRow()
|
||
{
|
||
return SQLFetch();
|
||
}
|
||
|
||
string SQLGetData(int iCol)
|
||
{
|
||
int iPos;
|
||
string sResultSet = GetLocalString(GetNWNMySQLWP(), "NWNX_ODBC_CurrentRow");
|
||
|
||
// find column in current row
|
||
int iCount = 0;
|
||
string sColValue = "";
|
||
|
||
iPos = FindSubString(sResultSet, "<22>");
|
||
if ((iPos == -1) && (iCol == 1))
|
||
{
|
||
// only one column, return value immediately
|
||
sColValue = sResultSet;
|
||
}
|
||
else if (iPos == -1)
|
||
{
|
||
// only one column but requested column > 1
|
||
sColValue = "";
|
||
}
|
||
else
|
||
{
|
||
// loop through columns until found
|
||
while (iCount != iCol)
|
||
{
|
||
iCount++;
|
||
if (iCount == iCol)
|
||
sColValue = GetStringLeft(sResultSet, iPos);
|
||
else
|
||
{
|
||
sResultSet = GetStringRight(sResultSet, GetStringLength(sResultSet) - iPos - 1);
|
||
iPos = FindSubString(sResultSet, "<22>");
|
||
}
|
||
|
||
// special case: last column in row
|
||
if (iPos == -1)
|
||
iPos = GetStringLength(sResultSet);
|
||
}
|
||
}
|
||
|
||
return sColValue;
|
||
}
|
||
|
||
// These functions deal with various data types. Ultimately, all information
|
||
// must be stored in the database as strings, and converted back to the proper
|
||
// form when retrieved.
|
||
|
||
string APSVectorToString(vector vVector)
|
||
{
|
||
return "#POSITION_X#" + FloatToString(vVector.x) + "#POSITION_Y#" + FloatToString(vVector.y) +
|
||
"#POSITION_Z#" + FloatToString(vVector.z) + "#END#";
|
||
}
|
||
|
||
vector APSStringToVector(string sVector)
|
||
{
|
||
float fX, fY, fZ;
|
||
int iPos, iCount;
|
||
int iLen = GetStringLength(sVector);
|
||
|
||
if (iLen > 0)
|
||
{
|
||
iPos = FindSubString(sVector, "#POSITION_X#") + 12;
|
||
iCount = FindSubString(GetSubString(sVector, iPos, iLen - iPos), "#");
|
||
fX = StringToFloat(GetSubString(sVector, iPos, iCount));
|
||
|
||
iPos = FindSubString(sVector, "#POSITION_Y#") + 12;
|
||
iCount = FindSubString(GetSubString(sVector, iPos, iLen - iPos), "#");
|
||
fY = StringToFloat(GetSubString(sVector, iPos, iCount));
|
||
|
||
iPos = FindSubString(sVector, "#POSITION_Z#") + 12;
|
||
iCount = FindSubString(GetSubString(sVector, iPos, iLen - iPos), "#");
|
||
fZ = StringToFloat(GetSubString(sVector, iPos, iCount));
|
||
}
|
||
|
||
return Vector(fX, fY, fZ);
|
||
}
|
||
|
||
string APSLocationToString(location lLocation)
|
||
{
|
||
object oArea = GetAreaFromLocation(lLocation);
|
||
vector vPosition = GetPositionFromLocation(lLocation);
|
||
float fOrientation = GetFacingFromLocation(lLocation);
|
||
string sReturnValue;
|
||
|
||
if (GetIsObjectValid(oArea))
|
||
sReturnValue =
|
||
"#AREA#" + GetTag(oArea) + "#POSITION_X#" + FloatToString(vPosition.x) +
|
||
"#POSITION_Y#" + FloatToString(vPosition.y) + "#POSITION_Z#" +
|
||
FloatToString(vPosition.z) + "#ORIENTATION#" + FloatToString(fOrientation) + "#END#";
|
||
|
||
return sReturnValue;
|
||
}
|
||
|
||
location APSStringToLocation(string sLocation)
|
||
{
|
||
location lReturnValue;
|
||
object oArea;
|
||
vector vPosition;
|
||
float fOrientation, fX, fY, fZ;
|
||
|
||
int iPos, iCount;
|
||
int iLen = GetStringLength(sLocation);
|
||
|
||
if (iLen > 0)
|
||
{
|
||
iPos = FindSubString(sLocation, "#AREA#") + 6;
|
||
iCount = FindSubString(GetSubString(sLocation, iPos, iLen - iPos), "#");
|
||
oArea = GetObjectByTag(GetSubString(sLocation, iPos, iCount));
|
||
|
||
iPos = FindSubString(sLocation, "#POSITION_X#") + 12;
|
||
iCount = FindSubString(GetSubString(sLocation, iPos, iLen - iPos), "#");
|
||
fX = StringToFloat(GetSubString(sLocation, iPos, iCount));
|
||
|
||
iPos = FindSubString(sLocation, "#POSITION_Y#") + 12;
|
||
iCount = FindSubString(GetSubString(sLocation, iPos, iLen - iPos), "#");
|
||
fY = StringToFloat(GetSubString(sLocation, iPos, iCount));
|
||
|
||
iPos = FindSubString(sLocation, "#POSITION_Z#") + 12;
|
||
iCount = FindSubString(GetSubString(sLocation, iPos, iLen - iPos), "#");
|
||
fZ = StringToFloat(GetSubString(sLocation, iPos, iCount));
|
||
|
||
vPosition = Vector(fX, fY, fZ);
|
||
|
||
iPos = FindSubString(sLocation, "#ORIENTATION#") + 13;
|
||
iCount = FindSubString(GetSubString(sLocation, iPos, iLen - iPos), "#");
|
||
fOrientation = StringToFloat(GetSubString(sLocation, iPos, iCount));
|
||
|
||
lReturnValue = Location(oArea, vPosition, fOrientation);
|
||
}
|
||
|
||
return lReturnValue;
|
||
}
|
||
|
||
// These functions are responsible for transporting the various data types back
|
||
// and forth to the database.
|
||
|
||
void SetPersistentString(object oObject, string sVarName, string sValue, int iExpiration =
|
||
0, string sTable = "pwdata")
|
||
{
|
||
string sPlayer;
|
||
string sTag;
|
||
|
||
if (GetIsPC(oObject))
|
||
{
|
||
sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oObject));
|
||
sTag = SQLEncodeSpecialChars(GetName(oObject));
|
||
}
|
||
else
|
||
{
|
||
sPlayer = "~";
|
||
sTag = GetTag(oObject);
|
||
}
|
||
|
||
sVarName = SQLEncodeSpecialChars(sVarName);
|
||
sValue = SQLEncodeSpecialChars(sValue);
|
||
|
||
string sSQL = "SELECT player FROM " + sTable + " WHERE player='" + sPlayer +
|
||
"' AND tag='" + sTag + "' AND name='" + sVarName + "'";
|
||
SQLExecDirect(sSQL);
|
||
|
||
if (SQLFirstRow() == SQL_SUCCESS)
|
||
{
|
||
// row exists
|
||
sSQL = "UPDATE " + sTable + " SET val='" + sValue +
|
||
"',expire=" + IntToString(iExpiration) + " WHERE player='" + sPlayer +
|
||
"' AND tag='" + sTag + "' AND name='" + sVarName + "'";
|
||
SQLExecDirect(sSQL);
|
||
}
|
||
else
|
||
{
|
||
// row doesn't exist
|
||
sSQL = "INSERT INTO " + sTable + " (player,tag,name,val,expire) VALUES" +
|
||
"('" + sPlayer + "','" + sTag + "','" + sVarName + "','" +
|
||
sValue + "'," + IntToString(iExpiration) + ")";
|
||
SQLExecDirect(sSQL);
|
||
}
|
||
}
|
||
|
||
string GetPersistentString(object oObject, string sVarName, string sTable = "pwdata")
|
||
{
|
||
string sPlayer;
|
||
string sTag;
|
||
|
||
if (GetIsPC(oObject))
|
||
{
|
||
sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oObject));
|
||
sTag = SQLEncodeSpecialChars(GetName(oObject));
|
||
}
|
||
else
|
||
{
|
||
sPlayer = "~";
|
||
sTag = GetTag(oObject);
|
||
}
|
||
|
||
sVarName = SQLEncodeSpecialChars(sVarName);
|
||
|
||
string sSQL = "SELECT val FROM " + sTable + " WHERE player='" + sPlayer +
|
||
"' AND tag='" + sTag + "' AND name='" + sVarName + "'";
|
||
SQLExecDirect(sSQL);
|
||
|
||
if (SQLFirstRow() == SQL_SUCCESS)
|
||
return SQLDecodeSpecialChars(SQLGetData(1));
|
||
else
|
||
{
|
||
return "";
|
||
// If you want to convert your existing persistent data to APS, this
|
||
// would be the place to do it. The requested variable was not found
|
||
// in the database, you should
|
||
// 1) query it's value using your existing persistence functions
|
||
// 2) save the value to the database using SetPersistentString()
|
||
// 3) return the string value here.
|
||
}
|
||
}
|
||
|
||
void SetPersistentInt(object oObject, string sVarName, int iValue, int iExpiration =
|
||
0, string sTable = "pwdata")
|
||
{
|
||
SetPersistentString(oObject, sVarName, IntToString(iValue), iExpiration, sTable);
|
||
}
|
||
|
||
int GetPersistentInt(object oObject, string sVarName, string sTable = "pwdata")
|
||
{
|
||
return StringToInt(GetPersistentString(oObject, sVarName, sTable));
|
||
}
|
||
|
||
void SetPersistentFloat(object oObject, string sVarName, float fValue, int iExpiration =
|
||
0, string sTable = "pwdata")
|
||
{
|
||
SetPersistentString(oObject, sVarName, FloatToString(fValue), iExpiration, sTable);
|
||
}
|
||
|
||
float GetPersistentFloat(object oObject, string sVarName, string sTable = "pwdata")
|
||
{
|
||
return StringToFloat(GetPersistentString(oObject, sVarName, sTable));
|
||
}
|
||
|
||
void SetPersistentLocation(object oObject, string sVarName, location lLocation, int iExpiration =
|
||
0, string sTable = "pwdata")
|
||
{
|
||
SetPersistentString(oObject, sVarName, APSLocationToString(lLocation), iExpiration, sTable);
|
||
}
|
||
|
||
location GetPersistentLocation(object oObject, string sVarName, string sTable = "pwdata")
|
||
{
|
||
return APSStringToLocation(GetPersistentString(oObject, sVarName, sTable));
|
||
}
|
||
|
||
void SetPersistentVector(object oObject, string sVarName, vector vVector, int iExpiration =
|
||
0, string sTable = "pwdata")
|
||
{
|
||
SetPersistentString(oObject, sVarName, APSVectorToString(vVector), iExpiration, sTable);
|
||
}
|
||
|
||
vector GetPersistentVector(object oObject, string sVarName, string sTable = "pwdata")
|
||
{
|
||
return APSStringToVector(GetPersistentString(oObject, sVarName, sTable));
|
||
}
|
||
|
||
void DeletePersistentVariable(object oObject, string sVarName, string sTable = "pwdata")
|
||
{
|
||
string sPlayer;
|
||
string sTag;
|
||
|
||
if (GetIsPC(oObject))
|
||
{
|
||
sPlayer = SQLEncodeSpecialChars(GetPCPlayerName(oObject));
|
||
sTag = SQLEncodeSpecialChars(GetName(oObject));
|
||
}
|
||
else
|
||
{
|
||
sPlayer = "~";
|
||
sTag = GetTag(oObject);
|
||
}
|
||
|
||
sVarName = SQLEncodeSpecialChars(sVarName);
|
||
string sSQL = "DELETE FROM " + sTable + " WHERE player='" + sPlayer +
|
||
"' AND tag='" + sTag + "' AND name='" + sVarName + "'";
|
||
SQLExecDirect(sSQL);
|
||
}
|
||
|
||
// Problems can arise with SQL commands if variables or values have single quotes
|
||
// in their names. These functions are a replace these quote with the tilde character
|
||
|
||
string SQLEncodeSpecialChars(string sString)
|
||
{
|
||
if (FindSubString(sString, "'") == -1) // not found
|
||
return sString;
|
||
|
||
int i;
|
||
string sReturn = "";
|
||
string sChar;
|
||
|
||
// Loop over every character and replace special characters
|
||
for (i = 0; i < GetStringLength(sString); i++)
|
||
{
|
||
sChar = GetSubString(sString, i, 1);
|
||
if (sChar == "'")
|
||
sReturn += "~";
|
||
else
|
||
sReturn += sChar;
|
||
}
|
||
return sReturn;
|
||
}
|
||
|
||
string SQLDecodeSpecialChars(string sString)
|
||
{
|
||
if (FindSubString(sString, "~") == -1) // not found
|
||
return sString;
|
||
|
||
int i;
|
||
string sReturn = "";
|
||
string sChar;
|
||
|
||
// Loop over every character and replace special characters
|
||
for (i = 0; i < GetStringLength(sString); i++)
|
||
{
|
||
sChar = GetSubString(sString, i, 1);
|
||
if (sChar == "~")
|
||
sReturn += "'";
|
||
else
|
||
sReturn += sChar;
|
||
}
|
||
return sReturn;
|
||
}
|
||
|