diff --git a/Arma2NETMySQLPlugin/Arma2NETMySQLPlugin.cs b/Arma2NETMySQLPlugin/Arma2NETMySQLPlugin.cs index a3ce23f..0703866 100644 --- a/Arma2NETMySQLPlugin/Arma2NETMySQLPlugin.cs +++ b/Arma2NETMySQLPlugin/Arma2NETMySQLPlugin.cs @@ -37,9 +37,9 @@ public override string Invoke(string args, int maxResultSize) Logger.addMessage(Logger.LogType.Info, "Received - Database: " + database + " Procedure: " + procedure + " Parameters: " + parameters.ToString()); - if (MySQL.dbs.SQLProviderExists(database)) + if (SQL.dbs.SQLProviderExists(database)) { - IEnumerable returned = MySQL.dbs.getSQLProvider(database).RunProcedure(procedure, split.ToArray(), maxResultSize); + IEnumerable returned = SQL.dbs.getSQLProvider(database).RunProcedure(procedure, split.ToArray(), maxResultSize); return Format.ObjectAsSqf(returned); } else @@ -64,7 +64,7 @@ public override void Unload() } //the function name for the plugin (called from Arma side) - [AddIn("Arma2NETMySQLCommand", Version = "0.1.0.0", Publisher = "firefly2442", Description = "Runs raw MySQL commands")] + [AddIn("Arma2NETMySQLCommand", Version = "0.1.0.0", Publisher = "firefly2442", Description = "Runs raw MySQL/SQLite commands")] public class Arma2NETMySQLPluginCommand : AddIn { //This method is called when callExtension is used from SQF: @@ -82,9 +82,9 @@ public override string Invoke(string args, int maxResultSize) Logger.addMessage(Logger.LogType.Info, "Received - Database: " + database + " MySQL Command: " + mysql_command.ToString()); - if (MySQL.dbs.SQLProviderExists(database)) + if (SQL.dbs.SQLProviderExists(database)) { - IEnumerable returned = MySQL.dbs.getSQLProvider(database).RunCommand(mysql_command, maxResultSize); + IEnumerable returned = SQL.dbs.getSQLProvider(database).RunCommand(mysql_command, maxResultSize); return Format.ObjectAsSqf(returned); } else diff --git a/Arma2NETMySQLPlugin/Arma2NETMySQLPlugin.csproj b/Arma2NETMySQLPlugin/Arma2NETMySQLPlugin.csproj index bc6290b..a2b85ea 100644 --- a/Arma2NETMySQLPlugin/Arma2NETMySQLPlugin.csproj +++ b/Arma2NETMySQLPlugin/Arma2NETMySQLPlugin.csproj @@ -40,6 +40,10 @@ + + False + ..\..\..\..\..\..\Program Files\System.Data.SQLite\2010\bin\System.Data.SQLite.dll + @@ -48,11 +52,13 @@ + + - + diff --git a/Arma2NETMySQLPlugin/DatabaseObject.cs b/Arma2NETMySQLPlugin/DatabaseObject.cs index 8f04c2b..1d888be 100644 --- a/Arma2NETMySQLPlugin/DatabaseObject.cs +++ b/Arma2NETMySQLPlugin/DatabaseObject.cs @@ -3,32 +3,49 @@ using System.Linq; using System.Text; + namespace Arma2NETMySQLPlugin { class DatabaseObject { + public string type; public string databasename; public string ipaddress; public string username; public string password; public string port; - public MySQL mysql_connection; + public SQL sql_connection; - public DatabaseObject(string name, string ip, string p, string user, string pass) + public DatabaseObject(params string[] values) { //Constructor - databasename = name; - ipaddress = ip; - port = p; - username = user; - password = pass; + type = values[0]; + databasename = values[1]; + if (values.Length == 6) { + ipaddress = values[2]; + port = values[3]; + username = values[4]; + password = values[5]; + } - mysql_connection = new MySQL(); - mysql_connection.OpenConnection(getFormattedConnectionString()); + if (type == "mysql") + { + sql_connection = new MySQL(); + sql_connection.OpenConnection(getMySQLFormattedConnectionString()); + } + else if (type == "sqlite") + { + sql_connection = new SQLite(); + sql_connection.OpenConnection(databasename); + } + else + { + Logger.addMessage(Logger.LogType.Error, "Database type does not match one of the supported types."); + } } - private string getFormattedConnectionString() + private string getMySQLFormattedConnectionString() { //With new (6.5.4) versions of the MySQL Connector, it was throwing an error when running the stored procedures: //Unable to retrieve stored procedure metadata for routine. Either grant SELECT privilege to mysql.proc for this user or use "check parameters=false" with your connection string. diff --git a/Arma2NETMySQLPlugin/Databases.cs b/Arma2NETMySQLPlugin/Databases.cs index b7a4165..baac760 100644 --- a/Arma2NETMySQLPlugin/Databases.cs +++ b/Arma2NETMySQLPlugin/Databases.cs @@ -6,7 +6,7 @@ namespace Arma2NETMySQLPlugin { - class Databases + public class Databases { private List databaseList = new List(); @@ -16,12 +16,13 @@ public Databases() //Load the database names, ip, port, usernames, passwords, and so on from file string line; - if (!File.Exists("Databases.txt")) + var databasesFileLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Arma2MySQL/Databases.txt"); + if (!File.Exists(databasesFileLocation)) { Logger.addMessage(Logger.LogType.Error, "Unable to find the Databases.txt file, are you sure it's there?"); } - StreamReader sr = File.OpenText("Databases.txt"); + StreamReader sr = File.OpenText(databasesFileLocation); line = sr.ReadLine(); while (line != null) { @@ -30,10 +31,18 @@ public Databases() { //Separate out the information string[] split = line.Split(','); - if (split.Length == 5) + if (split.Length == 6) { - Logger.addMessage(Logger.LogType.Info, "Database: " + split[0] + " IPAddress: " + split[1] + " Port: " + split[2] + " Username: " + split[3] + " Password: NotShownForSecurityReasons"); - DatabaseObject temp = new DatabaseObject(split[0], split[1], split[2], split[3], split[4]); + split[0] = split[0].ToLower(); + Logger.addMessage(Logger.LogType.Info, "Type: " + split[0] + " Database: " + split[1] + " IPAddress: " + split[2] + " Port: " + split[3] + " Username: " + split[4] + " Password: NotShownForSecurityReasons"); + DatabaseObject temp = new DatabaseObject(new string[6] {split[0], split[1], split[2], split[3], split[4], split[5]}); + databaseList.Add(temp); + } + else if (split.Length == 2) + { + split[0] = split[0].ToLower(); + Logger.addMessage(Logger.LogType.Info, "Type: " + split[0] + " Database: " + split[1]); + DatabaseObject temp = new DatabaseObject(new string[2] {split[0], split[1]}); databaseList.Add(temp); } else if (line.Contains(",")) @@ -55,7 +64,7 @@ public void shutdown() { for (int i = 0; i < databaseList.Count(); i++) { - databaseList[i].mysql_connection.CloseConnection(); + databaseList[i].sql_connection.CloseConnection(); } } @@ -71,13 +80,13 @@ public bool SQLProviderExists(string dbname) return false; } - public MySQL getSQLProvider(string dbname) + public SQL getSQLProvider(string dbname) { for (int i = 0; i < databaseList.Count(); i++) { if (databaseList[i].databasename == dbname) { - return databaseList[i].mysql_connection; + return databaseList[i].sql_connection; } } return null; diff --git a/Arma2NETMySQLPlugin/Logger.cs b/Arma2NETMySQLPlugin/Logger.cs index 9c4c1dd..6e0c6ad 100644 --- a/Arma2NETMySQLPlugin/Logger.cs +++ b/Arma2NETMySQLPlugin/Logger.cs @@ -33,16 +33,16 @@ public Logger() if (State == loggerState.Stopped) { //check to see if the logs folder exists, if not create it - if (!System.IO.Directory.Exists("logs")) - { - System.IO.Directory.CreateDirectory("logs"); + var logDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Arma2MySQL/logs/"); + if (!System.IO.Directory.Exists(logDir)) { + System.IO.Directory.CreateDirectory(logDir); } //Setup file streams DateTime dateValue = new DateTime(); dateValue = DateTime.Now; - string relativepath = Path.Combine("logs", dateValue.ToString("MM-dd-yyyy_HH-mm-ss") + ".log"); - fs = new FileStream(relativepath, FileMode.Append); + string fullpath = Path.Combine(logDir, dateValue.ToString("MM-dd-yyyy_HH-mm-ss") + ".log"); + fs = new FileStream(fullpath, FileMode.Append); sw = new StreamWriter(fs); state = loggerState.Started; diff --git a/Arma2NETMySQLPlugin/MySQL.cs b/Arma2NETMySQLPlugin/MySQL.cs index f89c7e0..67becab 100644 --- a/Arma2NETMySQLPlugin/MySQL.cs +++ b/Arma2NETMySQLPlugin/MySQL.cs @@ -2,25 +2,22 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using System.Threading; using MySql.Data.MySqlClient; -using Arma2Net.AddInProxy; +using System.Threading; namespace Arma2NETMySQLPlugin { - class MySQL + public class MySQL : SQL { - private object getCommandSync = new object(); private MySqlConnection connection; - - public static Databases dbs = null; + private object getCommandSync = new object(); public MySQL() { - //constructor + // Default constructor for the derived class } - public void OpenConnection(string connectionString) + public override void OpenConnection(string connectionString) { // if there is no connection if (connection == null) @@ -43,17 +40,17 @@ public void OpenConnection(string connectionString) } catch (Exception ex) { - Logger.addMessage(Logger.LogType.Info, "Unable to open connection to database, trying again in 10 seconds." + ex.ToString()); + Logger.addMessage(Logger.LogType.Info, "Unable to open connection to MySQL database, trying again in 10 seconds." + ex.ToString()); Thread.Sleep(10000); } } } - public void CloseConnection() + public override void CloseConnection() { if (connection != null) { - while (connection.State == System.Data.ConnectionState.Executing || connection.State == System.Data.ConnectionState.Fetching) ; + while (connection.State == System.Data.ConnectionState.Executing || connection.State == System.Data.ConnectionState.Fetching); if (connection.State != System.Data.ConnectionState.Closed) { @@ -63,7 +60,23 @@ public void CloseConnection() } } - public IEnumerable RunProcedure(string procedure, string[] parameters, int maxResultSize) + private MySqlCommand GetCommand(string procedureName) + { + MySqlCommand cmd = null; + // only one request at a time. + lock (getCommandSync) + { + // create the command + cmd = new MySqlCommand(); + cmd.CommandType = System.Data.CommandType.StoredProcedure; + cmd.Connection = connection; + cmd.CommandText = procedureName; + cmd.Prepare(); + } + return cmd; + } + + public override IEnumerable RunProcedure(string procedure, string[] parameters, int maxResultSize) { //Logger.addMessage(Logger.LogType.Info, "Started RunProcedure"); if (connection != null && connection.State == System.Data.ConnectionState.Open && procedure != null) @@ -92,7 +105,7 @@ public IEnumerable RunProcedure(string procedure, string[] parameter yield break; } - public IEnumerable RunCommand(string mysql_command, int maxResultSize) + public override IEnumerable RunCommand(string mysql_command, int maxResultSize) { //Logger.addMessage(Logger.LogType.Info, "Started RunCommand"); if (connection != null && connection.State == System.Data.ConnectionState.Open && mysql_command != null) @@ -145,55 +158,23 @@ private string[][] RunOnDatabase(MySqlCommand command, int maxResultSize) //convert into the array which we'll have to pass back string[][] string_array = new string[max_array_rows][]; - for (int i = 0; i < max_array_rows; i++) { + for (int i = 0; i < max_array_rows; i++) + { string_array[i] = to_return[i].ToArray(); } - /* - * callExtension is the method that is used by Arma2NET to pass information between itself and Arma2 - * callExtension has a size limit for the max amount of data that can be passed: - * http://community.bistudio.com/wiki/Extensions#A_few_technical_considerations - * The limit is 4 Kilobytes - * One character = one byte - * The Wiki notes that this size limit could change through future patches. - * https://dev-heaven.net/issues/25915 - * - * Arma2NET has a long output addin method that does the following: - * "From version 1.5, Arma2NET supports plugins requiring the maximum result size as an argument to the Run method. - * You can use this to ensure that a plugin won't return a result that is too long for Arma 2 to handle." - * - * In Arma2NET, 4095 characters is the limit - * The last character is reserved for null - * - */ - string formatted = Format.ObjectAsSqf(string_array); - int size = Encoding.UTF8.GetByteCount(formatted.ToCharArray()); - //Logger.addMessage(Logger.LogType.Info, "Size length: " + size); - if (size > maxResultSize) { - return new string[][] { new [] {"TooLong"} }; - } else { + if (validLength(string_array, maxResultSize) == false) + { + return new string[][] { new[] { "TooLong" } }; + } + else + { return string_array; } } } //Logger.addMessage(Logger.LogType.Info, "Returning error from RunProcedure"); - return new string[][] { new [] { "Error" } }; - } - - private MySqlCommand GetCommand(string procedureName) - { - MySqlCommand cmd = null; - // only one request at a time. - lock (getCommandSync) - { - // create the command - cmd = new MySqlCommand(); - cmd.CommandType = System.Data.CommandType.StoredProcedure; - cmd.Connection = connection; - cmd.CommandText = procedureName; - cmd.Prepare(); - } - return cmd; + return new string[][] { new[] { "Error" } }; } } } diff --git a/Arma2NETMySQLPlugin/SQL.cs b/Arma2NETMySQLPlugin/SQL.cs new file mode 100644 index 0000000..3230e1f --- /dev/null +++ b/Arma2NETMySQLPlugin/SQL.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Arma2Net.AddInProxy; + +namespace Arma2NETMySQLPlugin +{ + public abstract class SQL + { + public static Databases dbs = null; + + public SQL() + { + //constructor + } + + public abstract void OpenConnection(string connectionString); + public abstract void CloseConnection(); + + public abstract IEnumerable RunProcedure(string procedure, string[] parameters, int maxResultSize); + public abstract IEnumerable RunCommand(string sql_command, int maxResultSize); + + + protected Boolean validLength(string[][] check, int max_length) + { + /* + * callExtension is the method that is used by Arma2NET to pass information between itself and Arma2 + * callExtension has a size limit for the max amount of data that can be passed: + * http://community.bistudio.com/wiki/Extensions#A_few_technical_considerations + * The limit is 4 Kilobytes + * One character = one byte + * The Wiki notes that this size limit could change through future patches. + * https://dev-heaven.net/issues/25915 + * + * Arma2NET has a long output addin method that does the following: + * "From version 1.5, Arma2NET supports plugins requiring the maximum result size as an argument to the Run method. + * You can use this to ensure that a plugin won't return a result that is too long for Arma 2 to handle." + * + * In Arma2NET, 4095 characters is the limit + * The last character is reserved for null + * + */ + string formatted = Format.ObjectAsSqf(check); + int size = Encoding.UTF8.GetByteCount(formatted.ToCharArray()); + //Logger.addMessage(Logger.LogType.Info, "Size length: " + size); + if (size > max_length) { + return false; + } else { + return true; + } + } + } +} diff --git a/Arma2NETMySQLPlugin/SQLite.cs b/Arma2NETMySQLPlugin/SQLite.cs new file mode 100644 index 0000000..6c5c82f --- /dev/null +++ b/Arma2NETMySQLPlugin/SQLite.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data.SQLite; +using System.Data; +using System.IO; + +namespace Arma2NETMySQLPlugin +{ + public class SQLite : SQL + { + private SQLiteConnection sqlite_connection; + private string sqliteDatabaseLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Arma2MySQL/sqlite/"); + + public SQLite() + { + // Default constructor for the derived class + + //check to see if the sqlite folder exists, if not create it + if (!System.IO.Directory.Exists(sqliteDatabaseLocation)) { + System.IO.Directory.CreateDirectory(sqliteDatabaseLocation); + } + } + + public override void OpenConnection(string databasename) + { + try + { + // if there is no connection + if (sqlite_connection == null) + { + sqlite_connection = new SQLiteConnection("Data Source=" + sqliteDatabaseLocation + databasename + ".sqlite"); + } + + sqlite_connection.Open(); + } + catch (Exception ex) + { + Logger.addMessage(Logger.LogType.Error, "Unable to open connection to SQLite database." + ex.ToString()); + } + } + + public override void CloseConnection() + { + if (sqlite_connection != null) + { + try + { + sqlite_connection.Close(); + sqlite_connection = null; + } + catch (Exception ex) + { + Logger.addMessage(Logger.LogType.Error, "Unable to close SQLite connection." + ex.ToString()); + } + } + } + + public override IEnumerable RunProcedure(string procedure, string[] parameters, int maxResultSize) + { + Logger.addMessage(Logger.LogType.Error, "SQLite cannot run stored procedures."); + return null; + } + + public override IEnumerable RunCommand(string sql_command, int maxResultSize) + { + //SQLite example code: + //http://www.dreamincode.net/forums/topic/157830-using-sqlite-with-c%23/ + + DataTable dt = new DataTable(); + try + { + SQLiteCommand mycommand = new SQLiteCommand(sqlite_connection); + mycommand.CommandText = sql_command; + SQLiteDataReader reader = mycommand.ExecuteReader(); + dt.Load(reader); + reader.Close(); + } + catch (Exception ex) + { + Logger.addMessage(Logger.LogType.Error, "Unable to run SQLite command." + ex.ToString()); + } + + //convert datatable to array + string[][] string_array = new string[dt.Rows.Count][]; + for (int i = 0; i < dt.Rows.Count; i++) + { + DataRow row = dt.Rows[i]; + string_array[i] = row.ItemArray.Select(j => j.ToString()).ToArray(); + } + + + if (validLength(string_array, maxResultSize) == false) + { + yield return new string[][] { new[] { "TooLong" } }; + } + else + { + yield return string_array; + } + } + } +} diff --git a/Arma2NETMySQLPlugin/Startup.cs b/Arma2NETMySQLPlugin/Startup.cs index ab335c1..5cc32f4 100644 --- a/Arma2NETMySQLPlugin/Startup.cs +++ b/Arma2NETMySQLPlugin/Startup.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Text; using Arma2Net.AddInProxy; +using System.IO; namespace Arma2NETMySQLPlugin { @@ -15,6 +16,13 @@ public static void StartupConnection() { if (started_up == false) { + //create appdata folder if it doesn't already exist + var appDataLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Arma2MySQL"); + //check to see if the Arma2MySQL folder exists, if not create it + if (!System.IO.Directory.Exists(appDataLocation)) { + System.IO.Directory.CreateDirectory(appDataLocation); + } + //Start up logging logger_object = new Logger(); @@ -34,7 +42,7 @@ public static void StartupConnection() //Load in Databases.txt file //This also sets up the SQLProvider associated with the database Logger.addMessage(Logger.LogType.Info, "Loading databases..."); - MySQL.dbs = new Databases(); + SQL.dbs = new Databases(); //set mutex so we know we've started everything up started_up = true; @@ -44,7 +52,7 @@ public static void StartupConnection() public static void Unload() { Logger.addMessage(Logger.LogType.Info, "Unloading plugin."); - MySQL.dbs.shutdown(); + SQL.dbs.shutdown(); Logger.Stop(); Startup.started_up = false; } diff --git a/Databases.txt b/Databases.txt index ae25c4d..ab57bef 100644 --- a/Databases.txt +++ b/Databases.txt @@ -2,9 +2,13 @@ # Any line starting with a "#" is considered a comment # Make sure each of your database connections doesn't have a "#" in front! # Put each database connection you want on a separate line +# The databasename MUST be unique! # For an example, see the following -#databasename,ipaddress,port,username,password +#databasetype,databasename,ipaddress,port,username,password # -#arma,127.0.0.1,3306,armausername,secret +#mysql,arma,127.0.0.1,3306,armausername,secret +#sqlite,weaponslite -weapons,192.168.1.105,3306,arma,123 \ No newline at end of file +mysql,weapons,192.168.1.105,3306,arma,123 + +sqlite,weaponslite \ No newline at end of file diff --git a/ReadMe.html b/ReadMe.html index e238c76..cfd0c55 100644 --- a/ReadMe.html +++ b/ReadMe.html @@ -32,9 +32,10 @@

Contents

  • Arma2NETMySQL Plugin Example Mission
  • -

    This program acts as an intermediary between Arma2 and a MySQL database. It currently only supports MySQL. It uses the +

    This program acts as an intermediary between Arma2 and a MySQL or SQLite database. It uses the Arma2NET wrapper system. It is written in C#. The program has to be run on the -same system as your Arma2 server, however, the MySQL database can be either local or remote.

    +same system as your Arma2 server, however, the MySQL database can be either local or remote. The SQLite database runs on the +local machine.

    History:

    This program has had a long history. Initially, the program used JayArma2Lib because DLL injections were the only way to @@ -61,9 +62,15 @@

    Contents

    To run the application:
    • You need a Windows server. (see known issues)
    • -
    • A MySQL server and database setup
    • +
    • One of the following:
    • +
    • MySQL Connector for .NET The program has been successfully tested with version 6.5.4
    • +
    • Precompiled Binaries of SQLite + for 32-bit Windows (.NET Framework 4.0) The program has been successfully tested with version 1.0.81.0
    • Microsoft .NET Framework 4 Client Profile
    • Arma2OA Beta version 87640 or later (full client or dedicated server)
      • @@ -75,6 +82,16 @@

        Contents

        How To Use Arma2NETMySQL

        +

        Arma2NETMySQL keeps all files, folders, and sqlite databases that it needs in one location in appdata. The file +structure should match the following (note that you will need to create these folders if they don't exist):

        + +
        C:\Users\Yourname\AppData\Local\Arma2MySQL\
        +
        C:\Users\Yourname\AppData\Local\Arma2MySQL\Databases.txt
        +
        C:\Users\Yourname\AppData\Local\Arma2MySQL\sqlite\
        +
        C:\Users\Yourname\AppData\Local\Arma2MySQL\logs\
        + +

        This location is for Windows 7/Vista, if you're running an older version, this location will probably be different.

        +
        • Edit the Databases.txt file (requires separate lines for each database, even if they're on the same host).
          • @@ -83,8 +100,8 @@

            Contents

            and only has access to a single database. We do not recommend connecting to the database as the root user. This is generally a really bad choice because this user has full access. We will not be responsible if something gets deleted! -
          • Put the Databases.txt file in your Arma2 root folder. For example, in my Steam install, I have it here: -
            E:\Program Files\Steam\steamapps\common\arma 2 operation arrowhead\Databases.txt
            +
          • Put the Databases.txt file in the appdata Arma2MySQL folder: +
            C:\Users\Yourname\AppData\Local\Arma2MySQL\Databases.txt
        • There are two ways to run MySQL queries with this plugin. One is using MySQL stored procedures and the other @@ -121,6 +138,30 @@

          Contents

          to create manually. Note that the call names are different between running stored procedures versus straight queries.
        +
      • There is one way to run SQLite queries with this plugin.
      • +
          +
        1. Setup database:
        2. +
            +
          • Databases need to be in your appdata sqlite folder:
          • +
            C:\Users\Yourname\AppData\Local\Arma2MySQL\sqlite\
            +
          • And they need to have the following filename ending:
          • +
            .sqlite
            +
          • So, for example you might have:
          • +
            C:\Users\Yourname\AppData\Local\Arma2MySQL\sqlite\weaponslite.sqlite
            +
          • Make sure your database name matches the name in the Databases.txt file (minus the .sqlite ending of course).
          • +
          • If you need a client for creating and managing SQLite databases, + this Firefox plugin is quite nice.
          • +
          +
        3. Straight queries:
        4. +
            +
          • This is similar to what you're probably used to. Commands like: +
            SELECT * FROM table WHERE name = 'user'
          • +
          • Your SQF code will look something like this: +
            _selectTest = "Arma2Net.Unmanaged" callExtension "Arma2NETMySQLCommand ['weaponslite', 'SELECT * FROM users LIMIT 3']";
            + In this example, "weaponslite" is the database name. The next portion is the entire SQLite command which you will need + to create manually.
          • +
          +
      • Run Arma2 and add @Arma2NET as a mod. For example your command line parameters (for the server which connects to the database):
        -mod=expansion\beta;expansion\beta\expansion;@Arma2NET

        This plugin doesn't require any other third party mods like ACE or CBA. But, they do have some nice utility functions @@ -139,21 +180,23 @@

        Contents

        Arma2NETMySQL Plugin uses the callExtension function, however, there are some technical considerations as part of this.

        -

        Returning results has a limit of 4095 characters. If you try to run a MySQL query that will return a result longer than 4095 characters, +

        Returning results has a limit of 4095 characters. If you try to run a query that will return a result longer than 4095 characters, it will return the string "TooLong". Then you know you will need to limit the number of results that are returned. In MySQL, -you can use the limit parameter. This is a limitation of +you can use the limit parameter, or in SQLite, +the limit parameter. This is a limitation of Arma2 so don't ask for this to be fixed.

        Troubleshooting

        -

        If you are getting a returned result of "Error" in Arma2, this means there's something wrong with your MySQL query. Check +

        If you are getting a returned result of "Error" in Arma2, this means there's something wrong with your query. Check the logs to track down the problem.

        -

        Stuck? First check the "logs" folder. The plugin creates a new log file each time it's run. Go into your root Arma2 folder where -the executable is, then find the "logs" folder. If there are errors or things, they will show up there. If you don't have -a logs folder or it's empty, this is a sign the plugin isn't running. Try the second step:

        -

        Arma2NET also stores log files which are located here:

        C:\Users\Yourname\AppData\Local\Arma2NET
        +

        Stuck? First check the "logs" folder. The plugin creates a new log file each time it's run. Go into your appdata folder and +then find the "logs" folder. If there are errors or things, they will show up there. +

        C:\Users\Yourname\AppData\Local\Arma2MySQL\logs\
        +If you don't have a logs folder or it's empty, this is a sign the plugin isn't running. Try the second step:

        +

        Arma2NET also stores log files which are located here:

        C:\Users\Yourname\AppData\Local\Arma2NET\
        This will tell you if the plugin is loading appropriately. If it's not, check your launcher and make sure that is all correct.

        -

        You can also check the RPT files generated by Arma 2. These are located here:

        C:\Users\Yourname\AppData\Local\ArmA 2 OA
        +

        You can also check the RPT files generated by Arma 2. These are located here:

        C:\Users\Yourname\AppData\Local\ArmA 2 OA\
        These can get very long so scroll all the way to the bottom to see the latest run. This will tell you if you have an error in your SQF scripting code or other such problems. Note, these path locations are for Windows 7 (and Vista?) and may be different for other versions of Windows.