diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_getMissionHash.sqf b/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_getMissionHash.sqf deleted file mode 100644 index e9b29e6..0000000 --- a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_getMissionHash.sqf +++ /dev/null @@ -1,2 +0,0 @@ -params [["_value", "", [""]]]; -("AttendanceTracker" callExtension ["getMissionHash", _value]) select 0; \ No newline at end of file diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_timestamp.sqf b/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_timestamp.sqf deleted file mode 100644 index 19f8fb3..0000000 --- a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_timestamp.sqf +++ /dev/null @@ -1 +0,0 @@ -(parseSimpleArray ("AttendanceTracker" callExtension "getTimestamp")) select 0; \ No newline at end of file diff --git a/@AttendanceTracker.7z b/@AttendanceTracker.7z new file mode 100644 index 0000000..78fa082 Binary files /dev/null and b/@AttendanceTracker.7z differ diff --git a/@17thAttendanceTracker/addons/AttendanceTracker.pbo b/@AttendanceTracker/addons/AttendanceTracker.pbo similarity index 91% rename from @17thAttendanceTracker/addons/AttendanceTracker.pbo rename to @AttendanceTracker/addons/AttendanceTracker.pbo index ec8fe03..2ce3d4e 100644 Binary files a/@17thAttendanceTracker/addons/AttendanceTracker.pbo and b/@AttendanceTracker/addons/AttendanceTracker.pbo differ diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/config.cpp b/@AttendanceTracker/addons/AttendanceTracker/config.cpp similarity index 100% rename from @17thAttendanceTracker/addons/AttendanceTracker/config.cpp rename to @AttendanceTracker/addons/AttendanceTracker/config.cpp diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_callbackHandler.sqf b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_callbackHandler.sqf similarity index 78% rename from @17thAttendanceTracker/addons/AttendanceTracker/functions/fn_callbackHandler.sqf rename to @AttendanceTracker/addons/AttendanceTracker/functions/fn_callbackHandler.sqf index 7404ded..860ba44 100644 --- a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_callbackHandler.sqf +++ b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_callbackHandler.sqf @@ -43,16 +43,25 @@ addMissionEventHandler ["ExtensionCallback", { missionNamespace setVariable ["AttendanceTracker_DBConnected", true]; // log mission info and get back the row Id to send with future messages - private _response = "AttendanceTracker" callExtension ["logMission", [ - [AttendanceTracker getVariable ["missionContext", createHashMap]] call CBA_fnc_encodeJSON - ]]; - AttendanceTracker_missionId = parseNumber _response; - + private _response = "AttendanceTracker" callExtension [ + "logMission", + [ + [AttendanceTracker getVariable ["missionContext", createHashMap]] call CBA_fnc_encodeJSON + ] + ]; // log world info - private _response = "AttendanceTracker" callExtension ["logWorld", [ - [call attendanceTracker_fnc_getWorldInfo] call CBA_fnc_encodeJSON - ]]; + private _response = "AttendanceTracker" callExtension [ + "logWorld", + [ + [(call attendanceTracker_fnc_getWorldInfo)] call CBA_fnc_encodeJSON + ] + ]; + }; + }; + case "writeMissionInfo": { + if (_response#0 == "MISSION_ID") then { + AttendanceTracker_missionId = parseNumber _response; }; }; case "writeAttendance": { diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_connectDB.sqf b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_connectDB.sqf similarity index 100% rename from @17thAttendanceTracker/addons/AttendanceTracker/functions/fn_connectDB.sqf rename to @AttendanceTracker/addons/AttendanceTracker/functions/fn_connectDB.sqf diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_eventHandlers.sqf b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_eventHandlers.sqf similarity index 100% rename from @17thAttendanceTracker/addons/AttendanceTracker/functions/fn_eventHandlers.sqf rename to @AttendanceTracker/addons/AttendanceTracker/functions/fn_eventHandlers.sqf diff --git a/@AttendanceTracker/addons/AttendanceTracker/functions/fn_getMissionHash.sqf b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_getMissionHash.sqf new file mode 100644 index 0000000..b1cf10a --- /dev/null +++ b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_getMissionHash.sqf @@ -0,0 +1 @@ +(parseSimpleArray ("AttendanceTracker" callExtension "getMissionHash")) select 0; \ No newline at end of file diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_getWorldInfo.sqf b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_getWorldInfo.sqf similarity index 84% rename from @17thAttendanceTracker/addons/AttendanceTracker/functions/fn_getWorldInfo.sqf rename to @AttendanceTracker/addons/AttendanceTracker/functions/fn_getWorldInfo.sqf index 33d0856..28b0c55 100644 --- a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_getWorldInfo.sqf +++ b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_getWorldInfo.sqf @@ -14,7 +14,7 @@ _workshopID = ''; } foreach getLoadedModsInfo; // [_name, _author, _workshopID]; -[ +_return = createHashMapFromArray [ ["author", _author], ["workshopID", _workshopID], ["displayName", _name], @@ -23,4 +23,6 @@ _workshopID = ''; ["worldSize", worldSize], ["latitude", getNumber( _world >> "latitude" )], ["longitude", getNumber( _world >> "longitude" )] -]; \ No newline at end of file +]; +diag_log format ["Attendance Tracker: WorldInfo is: %1", _return]; +_return diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_log.sqf b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_log.sqf similarity index 100% rename from @17thAttendanceTracker/addons/AttendanceTracker/functions/fn_log.sqf rename to @AttendanceTracker/addons/AttendanceTracker/functions/fn_log.sqf diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_logMissionEvent.sqf b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_logMissionEvent.sqf similarity index 100% rename from @17thAttendanceTracker/addons/AttendanceTracker/functions/fn_logMissionEvent.sqf rename to @AttendanceTracker/addons/AttendanceTracker/functions/fn_logMissionEvent.sqf diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_logServerEvent.sqf b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_logServerEvent.sqf similarity index 100% rename from @17thAttendanceTracker/addons/AttendanceTracker/functions/fn_logServerEvent.sqf rename to @AttendanceTracker/addons/AttendanceTracker/functions/fn_logServerEvent.sqf diff --git a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_postInit.sqf b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_postInit.sqf similarity index 80% rename from @17thAttendanceTracker/addons/AttendanceTracker/functions/fn_postInit.sqf rename to @AttendanceTracker/addons/AttendanceTracker/functions/fn_postInit.sqf index 8cf03ec..e635bb4 100644 --- a/@17thAttendanceTracker/addons/AttendanceTracker/functions/fn_postInit.sqf +++ b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_postInit.sqf @@ -2,7 +2,9 @@ AttendanceTracker = false call CBA_fnc_createNamespace; AttendanceTracker_missionStartTimestamp = call attendanceTracker_fnc_timestamp; -AttendanceTracker_missionHash = [AttendanceTracker_missionStartTimestamp] call attendanceTracker_fnc_getMissionHash; +diag_log format ["AttendanceTracker: Mission started at %1", AttendanceTracker_missionStartTimestamp]; +AttendanceTracker_missionHash = call attendanceTracker_fnc_getMissionHash; +diag_log format ["AttendanceTracker: Mission hash is %1", AttendanceTracker_missionHash]; AttendanceTracker setVariable ["missionContext", createHashMapFromArray [ ["missionName", missionName], diff --git a/@AttendanceTracker/addons/AttendanceTracker/functions/fn_timestamp.sqf b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_timestamp.sqf new file mode 100644 index 0000000..e53f794 --- /dev/null +++ b/@AttendanceTracker/addons/AttendanceTracker/functions/fn_timestamp.sqf @@ -0,0 +1,24 @@ +// (parseSimpleArray ("AttendanceTracker" callExtension "getTimestamp")) select 0; + +// need date for MySQL in format 2006-01-02 15:04:05 + +systemTimeUTC params [ + "_year", + "_month", + "_day", + "_hour", + "_minute", + "_second" + "_millisecond" +]; + +format[ + "%1-%2-%3 %4:%5:%6", + _year, + _month, + _day, + _hour, + _minute, + _second +]; + diff --git a/@17thAttendanceTracker/config.example.json b/@AttendanceTracker/config.example.json similarity index 100% rename from @17thAttendanceTracker/config.example.json rename to @AttendanceTracker/config.example.json diff --git a/@AttendanceTracker/config.json b/@AttendanceTracker/config.json new file mode 100644 index 0000000..2358f51 --- /dev/null +++ b/@AttendanceTracker/config.json @@ -0,0 +1,7 @@ +{ + "mysqlHost": "127.0.0.1", + "mysqlPort": 12730, + "mysqlUser": "root", + "mysqlPassword": "i&Lz8A3RuPcY5b326ALXgjl", + "mysqlDatabase": "testdb" +} \ No newline at end of file diff --git a/@17thAttendanceTracker/mod.cpp b/@AttendanceTracker/mod.cpp similarity index 100% rename from @17thAttendanceTracker/mod.cpp rename to @AttendanceTracker/mod.cpp diff --git a/README.md b/README.md index 0cb1612..6519283 100644 --- a/README.md +++ b/README.md @@ -9,58 +9,65 @@ Create a database with a name of your choosing. Then, run the following SQL comm ```sql -- a3server.attendancelog definition -CREATE TABLE `attendancelog` ( - `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=0 DEFAULT CHARSET=utf8mb3; +CREATE TABLE `attendance` ( + `id` INT(11) NOT NULL AUTO_INCREMENT, + `join_time` DATETIME NULL DEFAULT NULL, + `disconnect_time` DATETIME NULL DEFAULT NULL, + `mission_hash` VARCHAR(100) NULL DEFAULT '' 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', + PRIMARY KEY (`id`) USING BTREE +) +COLLATE='utf8mb3_general_ci' +ENGINE=InnoDB +AUTO_INCREMENT=5868 +; + -- 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; + `id` INT(11) NOT NULL AUTO_INCREMENT, + `mission_name` VARCHAR(100) NOT NULL COLLATE 'utf8mb3_general_ci', + `mission_name_source` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', + `briefing_name` 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) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', + `server_profile` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', + `mission_start` DATETIME NULL DEFAULT NULL, + `mission_hash` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', + PRIMARY KEY (`id`) USING BTREE +) +COLLATE='utf8mb3_general_ci' +ENGINE=InnoDB +; + -- 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; + `id` INT(11) NOT NULL AUTO_INCREMENT, + `author` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', + `display_name` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', + `world_name` VARCHAR(100) NOT NULL COLLATE 'utf8mb3_general_ci', + `world_name_original` VARCHAR(100) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', + `world_size` INT(11) NULL DEFAULT NULL, + `latitude` FLOAT NULL DEFAULT NULL, + `longitude` FLOAT NULL DEFAULT NULL, + `workshop_id` VARCHAR(50) NULL DEFAULT NULL COLLATE 'utf8mb3_general_ci', + PRIMARY KEY (`id`) USING BTREE +) +COLLATE='utf8mb3_general_ci' +ENGINE=InnoDB +AUTO_INCREMENT=2 +; ``` diff --git a/extension/@17thAttendanceTracker/config.example.json b/extension/@AttendanceTracker/config.example.json similarity index 100% rename from extension/@17thAttendanceTracker/config.example.json rename to extension/@AttendanceTracker/config.example.json diff --git a/extension/AttendanceTracker_x64.dll b/extension/AttendanceTracker_x64.dll index 586b556..fe528f5 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 f75d166..e53ce27 100644 --- a/extension/main.go +++ b/extension/main.go @@ -16,6 +16,8 @@ import ( "fmt" "log" "os" + "path" + "runtime" "strconv" "strings" "time" @@ -108,11 +110,11 @@ func loadConfig() { writeLog(functionName, `["Config loaded", "INFO"]`) } -func getMissionHash(time string) string { +func getMissionHash() string { functionName := "getMissionHash" // get md5 hash of string // https://stackoverflow.com/questions/2377881/how-to-get-a-md5-hash-from-a-string-in-golang - hash := md5.Sum([]byte(time)) + hash := md5.Sum([]byte(time.Now().Format("2006-01-02 15:04:05"))) // convert to string hashString := fmt.Sprintf("%x", hash) @@ -176,9 +178,11 @@ type WorldInfo struct { func writeWorldInfo(worldInfo string) { functionName := "writeWorldInfo" + writeLog(functionName, fmt.Sprintf(`["%s", "DEBUG"]`, worldInfo)) // worldInfo is json, parse it var wi WorldInfo - err := json.Unmarshal([]byte(worldInfo), &wi) + fixedString := fixEscapeQuotes(trimQuotes(worldInfo)) + err := json.Unmarshal([]byte(fixedString), &wi) if err != nil { writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err)) return @@ -256,9 +260,11 @@ type MissionInfo struct { func writeMissionInfo(missionInfo string) { functionName := "writeMissionInfo" + writeLog(functionName, fmt.Sprintf(`["%s", "DEBUG"]`, missionInfo)) // missionInfo is json, parse it var mi MissionInfo - err := json.Unmarshal([]byte(missionInfo), &mi) + fixedString := fixEscapeQuotes(trimQuotes(missionInfo)) + err := json.Unmarshal([]byte(fixedString), &mi) if err != nil { writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err)) return @@ -286,7 +292,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.MissionStart, mi.MissionHash) + res, err := stmt.Exec(mi.MissionName, mi.BriefingName, mi.MissionNameSource, mi.OnLoadName, mi.Author, mi.ServerName, mi.ServerProfile, mi.MissionStart, mi.MissionHash) if err != nil { writeLog(functionName, fmt.Sprintf(`["%s", "ERROR"]`, err)) return @@ -297,6 +303,7 @@ func writeMissionInfo(missionInfo string) { return } writeLog(functionName, fmt.Sprintf(`["Mission inserted with ID %d", "INFO"]`, lastID)) + writeLog(functionName, fmt.Sprintf(`["MISSION_ID", "%d"]`, lastID)) } type AttendanceLogItem struct { @@ -332,13 +339,11 @@ func writeAttendance(data string) { return } - // // send to DB - result, err := db.ExecContext( context.Background(), fmt.Sprintf( - `INSERT INTO %s (join_time, disconnect_time, event_type, player_id, player_uid, profile_name, steam_name, is_jip, role_description, mission_hash) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, + `INSERT INTO %s (join_time, event_type, player_id, player_uid, profile_name, steam_name, is_jip, role_description, mission_hash) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, ATTENDANCE_TABLE, ), now, @@ -364,7 +369,7 @@ func writeAttendance(data string) { } writeLog(functionName, fmt.Sprintf(`["Saved attendance for %s to row id %d", "INFO"]`, event.ProfileName, id)) - writeLog(functionName, fmt.Sprintf(`["ATT_LOG", ["%s", %d]]`, event.PlayerId, id)) + writeLog(functionName, fmt.Sprintf(`["ATT_LOG", ["%s", "%d"]]`, event.PlayerId, id)) } @@ -469,12 +474,6 @@ 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 @@ -502,9 +501,10 @@ func callBackExample() { } } -func getTimestamp() int64 { +func getTimestamp() string { // get the current unix timestamp in nanoseconds - return time.Now().UnixNano() + // return time.Now().Local().Unix() + return time.Now().Format("2006-01-02 15:04:05") } func trimQuotes(s string) string { @@ -526,6 +526,9 @@ func writeLog(functionName string, data string) { defer C.free(unsafe.Pointer(statusParam)) runExtensionCallback(statusName, statusFunction, statusParam) + // get calling function & line + _, file, line, _ := runtime.Caller(1) + log.Printf(`%s:%d: %s`, path.Base(file), line, data) log.Printf(`%s: %s`, functionName, data) } @@ -542,12 +545,12 @@ func goRVExtension(output *C.char, outputsize C.size_t, input *C.char) { case "getDir": temp = getDir() case "getTimestamp": - time := getTimestamp() - temp = fmt.Sprintf(`["%s"]`, strconv.FormatInt(time, 10)) + temp = fmt.Sprintf(`["%s"]`, getTimestamp()) case "connectDB": go connectDB() temp = fmt.Sprintf(`["%s"]`, "Connecting to DB") - + case "getMissionHash": + temp = fmt.Sprintf(`["%s"]`, getMissionHash()) default: temp = fmt.Sprintf(`["%s"]`, "Unknown Function") }