Antares
Spell Reviewer
- Joined
- Dec 13, 2009
- Messages
- 982
As far as I can tell, you're not yielding any coroutines in your code or using Require, so the wrap in OnInit.root seems superfluous?
if Debug and Debug.beginFile then Debug.beginFile("LogUtils") end
--[[
LogUtils v1.0.1 by Tomotz
This library provides a log file for the game.
Features beyond what FileIO offers:
- Log is saved to a memory buffer, allowing you to write to the file over and over again without losing the old data.
- Writing lines to the log only when the game is in replay to reduce performance impact
- Maximum log length - when reached, will open a new log file (and memory buffer) to avoid long writes
- Adds the player id to the log name to allow multiple logs from a single game on the same computer (for map testing)
Interface:
LogWrite(line)
Appends a line to the current log file (also flushes everything in the memory buffer to the file)
LogWriteNoFlush(line)
Appends a line to the memory buffer without writing it to the file.
This should only be used if you know you will eventually use a LogWrite to flush this line
LogWriteNoFlushReplay(line)
LogWriteReplay(line)
These functions are the same as the ones above, except they will only write the line when a replay of the game is played.
Note that the normal variants of these functions will write in both replay and normal modes.
These functions should be used when you worry about game performace impact. If you write many/very long lines to
the log, it might hurt performance
Installation instructions:
Copy the code to your map.
Credits:
TriggerHappy GameStatus (Replay Detection) https://www.hiveworkshop.com/threads/gamestatus-replay-detection.293176/
* A big block of code was taken from there to allow detecting that the game is run in replay mode.
Requires:
FileIO (lua) by Trokkin - https://www.hiveworkshop.com/threads/fileio-lua-optimized.347049/
TotalInitialization by Bribe - https://www.hiveworkshop.com/threads/total-initialization.317099/
Updated: 24 Dec 2024
--]]
do
LIBRARY_LogUtils = true
local SCOPE_PREFIX = "LogUtils_" ---@type string requires TotalInitialization, FileIO
-- Configurations:
-- Base name for the log files.
-- The logs are saved to Documents\Warcraft III\CustomMapData
-- the relative path where the log files are kept. Should end with \\
local RAW_LOG_PATH = "Savegames\\TestMap\\"
-- Raw name for the log file. Will append the player index to the start on any mode, and "replay" to the end on replay mode.
-- Will also add the log index (in case there are multiple log files in the same run) and .txt to the end
local RAW_LOG_NAME = "last_game_log"
-- The maximum length of the memory buffer. If too long, writes to the log file can take a long time
-- (as the whole buffer is flushed on every write) and hinder performances
local MAX_BUFF_LEN = 50000 ---@type integer -- Theoretically, FileIO supports 999999
-- Maximum number of log files that will be created in a single game (will stop logging if threshold was reached)
local MAX_FILES = 10 ---@type integer
-- Same as MAX_FILES, but for replay logs
local MAX_FILESREPLAY = 50 ---@type integer
-- If true, will try writing the map name to the long on init (using TRIGSTR_001)
local WRITE_MAP_NAME = true ---@type boolean
-- Useful globals that tells you if the game is offline (single player I think), online or replay.
-- The first 3 are constants and should not be changed
GAME_STATUS_OFFLINE = 0 ---@type integer
GAME_STATUS_ONLINE = 1 ---@type integer
GAME_STATUS_REPLAY = 2 ---@type integer
GameStatus = 0 ---@type integer -- one of GAME_STATUS_OFFLINE, GAME_STATUS_ONLINE, GAME_STATUS_REPLAY
-- Local variables for internal use
local LogFileName ---@type string
local WriteBuffer = "\n" ---@type string
local FileIdx = 0 ---@type integer
local IsFlashed = true ---@type boolean
---@param text string
local function WriteAndFlush(text)
if (FileIdx < MAX_FILES) or ((GameStatus == GAME_STATUS_REPLAY) and (FileIdx < MAX_FILESREPLAY)) then
FileIO.Save(LogFileName, text)
end
end
local function CreateNewLogFile()
LogFileName = RAW_LOG_PATH .. GetPlayerId(GetLocalPlayer()) .. "_" .. RAW_LOG_NAME .. "_"
if GameStatus == GAME_STATUS_REPLAY then
LogFileName = LogFileName .. "replay_"
end
LogFileName = LogFileName .. tostring(FileIdx) .. ".txt"
FileIdx = FileIdx + 1
WriteAndFlush("\nLog file is empty")
end
-- sets GameStatus variable which decides if game is online, offline or replay
local function SetGameStatus()
local firstPlayer ---@type player
local u ---@type unit
local selected ---@type boolean
-- find an actual player
firstPlayer = Player(0)
while not ((GetPlayerController(firstPlayer) == MAP_CONTROL_USER and GetPlayerSlotState(firstPlayer) == PLAYER_SLOT_STATE_PLAYING)) do
firstPlayer = Player(GetPlayerId(firstPlayer) + 1)
end
-- force the player to select a dummy unit
u = CreateUnit(firstPlayer, FourCC('hfoo'), 0, 0, 0)
SelectUnit(u, true)
selected = IsUnitSelected(u, firstPlayer)
RemoveUnit(u)
if (selected) then
-- detect if replay or offline game
if (ReloadGameCachesFromDisk()) then
GameStatus = GAME_STATUS_OFFLINE
else
GameStatus = GAME_STATUS_REPLAY
end
else
-- if the unit wasn't selected instantly, the game is online
GameStatus = GAME_STATUS_ONLINE
end
end
local function init()
SetGameStatus()
CreateNewLogFile()
-- write map name to log
if WRITE_MAP_NAME then
LogWrite(GetLocalizedString("TRIGSTR_001"))
end
end
-- Writes a line to the WriteBuffer to be logged
---@param line string
function LogWriteNoFlush(line)
local full_line = line .. "\n" ---@type string
if StringLength(WriteBuffer) + StringLength(full_line) > MAX_BUFF_LEN then
if not IsFlashed then
WriteAndFlush(WriteBuffer)
end
CreateNewLogFile()
WriteBuffer = full_line
else
WriteBuffer = WriteBuffer .. full_line
end
IsFlashed = false
end
-- Writes a line to the WriteBuffer to be logged only in replay mode
---@param line string
function LogWriteNoFlushReplay(line)
if GameStatus == GAME_STATUS_REPLAY then
LogWriteNoFlush(line)
end
end
-- Writes a line to the current log
---@param line string
function LogWrite(line)
LogWriteNoFlush(line)
WriteAndFlush(WriteBuffer)
IsFlashed = true
end
-- Writes a line to the log only in replay mode
---@param line string
function LogWriteReplay(line)
if GameStatus == GAME_STATUS_REPLAY then
LogWrite(line)
end
end
OnInit(init)
end
if Debug and Debug.endFile then Debug.endFile() end