diff --git a/@17thAttendanceTracker/addons/AttendanceTracker.pbo b/@17thAttendanceTracker/addons/AttendanceTracker.pbo index f4781c4..0b0a605 100644 Binary files a/@17thAttendanceTracker/addons/AttendanceTracker.pbo and b/@17thAttendanceTracker/addons/AttendanceTracker.pbo differ diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/config.cpp b/@17thAttendanceTracker/addons/AttendanceTracker/config.cpp index b191b30..5f908e4 100644 --- a/@17thAttendanceTracker/addons/AttendanceTracker/config.cpp +++ b/@17thAttendanceTracker/addons/AttendanceTracker/config.cpp @@ -21,6 +21,7 @@ class CfgFunctions { class logMissionEvent {}; class logServerEvent {}; class timestamp {}; + class getHash {}; }; }; }; \ No newline at end of file diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_getMissionHash.sqf b/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_getMissionHash.sqf new file mode 100644 index 0000000..e9b29e6 --- /dev/null +++ b/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_getMissionHash.sqf @@ -0,0 +1,2 @@ +params [["_value", "", [""]]]; +("AttendanceTracker" callExtension ["getMissionHash", _value]) select 0; \ No newline at end of file diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_getWorldInfo.sqf b/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_getWorldInfo.sqf index 75bc7d7..33d0856 100644 --- a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_getWorldInfo.sqf +++ b/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_getWorldInfo.sqf @@ -14,10 +14,13 @@ _workshopID = ''; } foreach getLoadedModsInfo; // [_name, _author, _workshopID]; - [ - ["worldName", _name], ["author", _author], + ["workshopID", _workshopID], + ["displayName", _name], + ["worldName", toLower worldName], + ["worldNameOriginal", _name], ["worldSize", worldSize], - ["workshopID", _workshopID] + ["latitude", getNumber( _world >> "latitude" )], + ["longitude", getNumber( _world >> "longitude" )] ]; \ No newline at end of file diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_postInit.sqf b/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_postInit.sqf index f9fe4bd..8cf03ec 100644 --- a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_postInit.sqf +++ b/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_postInit.sqf @@ -2,7 +2,7 @@ AttendanceTracker = false call CBA_fnc_createNamespace; AttendanceTracker_missionStartTimestamp = call attendanceTracker_fnc_timestamp; -AttendanceTracker_missionHash = "AttendanceTracker" callExtension ["getMissionHash", AttendanceTracker_missionStartTimestamp]; +AttendanceTracker_missionHash = [AttendanceTracker_missionStartTimestamp] call attendanceTracker_fnc_getMissionHash; AttendanceTracker setVariable ["missionContext", createHashMapFromArray [ ["missionName", missionName], diff --git a/README.md b/README.md index 0cbbef2..183512a 100644 --- a/README.md +++ b/README.md @@ -7,31 +7,61 @@ Create a database with a name of your choosing. Then, run the following SQL command against it to create a table. ```sql +-- a3server.attendancelog definition + CREATE TABLE `attendancelog` ( - `id` INT(11) NOT NULL AUTO_INCREMENT, - `timestamp` DATETIME NOT NULL, - `event_hash` VARCHAR(100) NOT NULL DEFAULT md5(concat(`server_name`,`mission_name`,`author`,`mission_start`)) COLLATE 'utf8mb3_general_ci', - `event_type` VARCHAR(100) NOT NULL COLLATE 'utf8mb3_general_ci', - `player_id` VARCHAR(30) NOT NULL COLLATE 'utf8mb3_general_ci', - `player_uid` VARCHAR(100) NOT NULL COLLATE 'utf8mb3_general_ci', - `profile_name` VARCHAR(100) NOT NULL COLLATE 'utf8mb3_general_ci', - `steam_name` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', - `is_jip` TINYINT(4) NULL DEFAULT NULL, - `role_description` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', - `mission_start` DATETIME NOT NULL, - `mission_name` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', - `briefing_name` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', - `mission_name_source` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', - `on_load_name` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', - `author` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', - `server_name` VARCHAR(100) NOT NULL COLLATE 'utf8mb3_general_ci', - `server_profile` VARCHAR(100) NOT NULL COLLATE 'utf8mb3_general_ci', - PRIMARY KEY (`id`) USING BTREE -) -COLLATE='utf8mb3_general_ci' -ENGINE=InnoDB -AUTO_INCREMENT=383 -; + `id` int(11) NOT NULL AUTO_INCREMENT, + `timestamp` datetime NOT NULL, + `event_hash` varchar(100) NOT NULL, + `event_type` varchar(100) NOT NULL, + `player_id` varchar(30) NOT NULL, + `player_uid` varchar(100) NOT NULL, + `profile_name` varchar(100) NOT NULL, + `steam_name` varchar(100) DEFAULT NULL, + `is_jip` tinyint(4) DEFAULT NULL, + `role_description` varchar(100) DEFAULT NULL, + `mission_start` datetime NOT NULL, + `mission_name` varchar(100) DEFAULT NULL, + `briefing_name` varchar(100) DEFAULT NULL, + `mission_name_source` varchar(100) DEFAULT NULL, + `on_load_name` varchar(100) DEFAULT NULL, + `author` varchar(100) DEFAULT NULL, + `server_name` varchar(100) NOT NULL, + `server_profile` varchar(100) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2713 DEFAULT CHARSET=utf8mb3; + +-- a3server.`missions` definition + +CREATE TABLE `missions` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `mission_name` varchar(100) NOT NULL, + `mission_name_source` varchar(100) DEFAULT NULL, + `briefing_name` varchar(100) DEFAULT NULL, + `on_load_name` varchar(100) DEFAULT NULL, + `author` varchar(100) DEFAULT NULL, + `server_name` varchar(100) DEFAULT NULL, + `server_profile` varchar(100) DEFAULT NULL, + `mission_start` datetime DEFAULT NULL, + `mission_hash` varchar(100) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3; + + +-- a3server.`worlds` definition + +CREATE TABLE `worlds` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `author` varchar(100) DEFAULT NULL, + `display_name` varchar(100) DEFAULT NULL, + `world_name` varchar(100) NOT NULL, + `world_name_original` varchar(100) DEFAULT NULL, + `world_size` int(11) DEFAULT NULL, + `latitude` float DEFAULT NULL, + `longitude` float DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb3; + ``` -Finally, copy `config.example.json` to `config.json` and update it with your database credentials. \ No newline at end of file +Finally, copy `config.example.json` to `config.json` and update it with your database credentials. diff --git a/extension/AttendanceTracker_x64.dll b/extension/AttendanceTracker_x64.dll index f84d35e..9169ea6 100644 Binary files a/extension/AttendanceTracker_x64.dll and b/extension/AttendanceTracker_x64.dll differ diff --git a/extension/main.go b/extension/main.go index f31640e..1d62a69 100644 --- a/extension/main.go +++ b/extension/main.go @@ -160,10 +160,14 @@ func connectDB() string { } type WorldInfo struct { - WorldName string `json:"worldName"` - Author string `json:"author"` - WorldSize int `json:"worldSize"` - WorkshopID string `json:"workshopID"` + Author string `json:"author"` + WorkshopID string `json:"workshopID"` + DisplayName string `json:"displayName"` + WorldName string `json:"worldName"` + WorldNameOriginal string `json:"worldNameOriginal"` + WorldSize int `json:"worldSize"` + Latitude float32 `json:"latitude"` + Longitude float32 `json:"longitude"` } func writeWorldInfo(worldInfo string) { @@ -176,7 +180,7 @@ func writeWorldInfo(worldInfo string) { return } // write to log - writeLog(functionName, fmt.Sprintf(`["WorldName:%s Author:%s WorldSize:%d WorkshopID:%s", "INFO"]`, wi.WorldName, wi.Author, wi.WorldSize, wi.WorkshopID)) + writeLog(functionName, fmt.Sprintf(`["Author:%s WorkshopID:%s DisplayName:%s WorldName:%s WorldNameOriginal:%s WorldSize:%d Latitude:%f Longitude:%f", "INFO"]`, wi.Author, wi.WorkshopID, wi.DisplayName, wi.WorldName, wi.WorldNameOriginal, wi.WorldSize, wi.Latitude, wi.Longitude)) // write to database // check if world exists @@ -185,13 +189,13 @@ func writeWorldInfo(worldInfo string) { if err != nil { if err == sql.ErrNoRows { // world does not exist, insert it - stmt, err := db.Prepare("INSERT INTO worlds (world_name, author, world_size, workshop_id) VALUES (?, ?, ?, ?)") + stmt, err := db.Prepare("INSERT INTO worlds (author, workshop_id, display_name, world_name, world_name_original, world_size, latitude, longitude) VALUES (?, ?, ?, ?, ?, ?, ?, ?)") if err != nil { writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err)) return } defer stmt.Close() - res, err := stmt.Exec(wi.WorldName, wi.Author, wi.WorldSize, wi.WorkshopID) + res, err := stmt.Exec(wi.Author, wi.WorkshopID, wi.DisplayName, wi.WorldName, wi.WorldNameOriginal, wi.WorldSize, wi.Latitude, wi.Longitude) if err != nil { writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err)) return @@ -208,13 +212,13 @@ func writeWorldInfo(worldInfo string) { } } else { // world exists, update it - stmt, err := db.Prepare("UPDATE worlds SET world_name = ?, author = ?, world_size = ? WHERE id = ?") + stmt, err := db.Prepare("UPDATE worlds SET author = ?, workshop_id = ?, display_name = ?, world_name = ?, world_name_original = ?, world_size = ?, latitude = ?, longitude = ? WHERE id = ?") if err != nil { writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err)) return } defer stmt.Close() - res, err := stmt.Exec(wi.WorldName, wi.Author, wi.WorldSize, worldID) + res, err := stmt.Exec(wi.Author, wi.WorkshopID, wi.DisplayName, wi.WorldName, wi.WorldNameOriginal, wi.WorldSize, wi.Latitude, wi.Longitude, worldID) if err != nil { writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err)) return @@ -269,7 +273,7 @@ func writeMissionInfo(missionInfo string) { return } defer stmt.Close() - res, err := stmt.Exec(mi.MissionName, mi.BriefingName, mi.MissionNameSource, mi.OnLoadName, mi.Author, mi.ServerName, mi.ServerProfile, t, mi.MissionHash) + res, err := stmt.Exec(mi.MissionName, mi.BriefingName, mi.MissionNameSource, mi.OnLoadName, mi.Author, mi.ServerName, mi.ServerProfile, t, mi.MissionStart, mi.MissionHash) if err != nil { writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err)) return @@ -315,7 +319,7 @@ func writeAttendance(data string) { // send to DB - result, err := db.ExecContext(context.Background(), `INSERT INTO AttendanceLog (timestamp, event_type, player_id, player_uid, profile_name, steam_name, is_jip, role_description, mission_hash) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, + result, err := db.ExecContext(context.Background(), `INSERT INTO AttendanceLog (event_time, event_type, player_id, player_uid, profile_name, steam_name, is_jip, role_description, mission_hash) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, now, event.EventType, event.PlayerId, @@ -384,6 +388,12 @@ func goRVExtensionArgs(output *C.char, outputsize C.size_t, input *C.char, argv if argc == 1 { go writeWorldInfo(out[0]) } + case "getMissionHash": + { + if argc == 1 { + go getMissionHash(out[0]) + } + } } // Return a result to Arma