Добавлен ScorpioT1000,
опубликован
Алгоритмы, Наработки и Способности
Способ реализации:
cJass
Тип:
Наработка
Думаю многие помнят небольшую, но очень полезную библиотечку от Doc которая помогала сохранять дебаг логи на хард по средствам прелоада и библиотечку от Скорпи, которая помогала контролировать в коде соблюдение различных условий.
Думаю, те кто пользовались, остались довольны, как и я.
Так вот, недавно Faion малость усовершенствовал первую, а скорпи присоединил вторую. Надеюсь, док и faion будут не против.
Так вот, недавно Faion малость усовершенствовал первую, а скорпи присоединил вторую. Надеюсь, док и faion будут не против.
В результате получилось отличное средство от геморроя и немного от фаталов!
Инструкции
// Instructions:
//
// Пишет информацию об условии в лог, если условие ВЫПОЛНИЛОСЬ:
// IFDEBUG( ARGUMENT )
//
// Пишет информацию в лог, если условие НЕ ВЫПОЛНЕНО и УНИЧТОЖАЕТ весь текущий поток:
// ASSERT( ARGUMENT )
//
// Пишет информацию об условии в лог, если условие ВЫПОЛНИЛОСЬ и выходит из функции со значением, указанным во втором аргументе:
// IFDEBUG( ARGUMENT, RET )
//
// Заметка: Если функция ничего не возвращает, но вы в любом случае хотите её остановить, используйте пробел, как: IFDEBUG(u == null, );
// Заметка: Лог пишется только в режиме отладки JNGP - "Debug Mode".
Code
// Instructions:
//
// Writes log if the condition is satisfied:
// IFDEBUG( ARGUMENT )
//
// Writes log if the condition is NOT satisfied and TERMINATES its thread:
// ASSERT( ARGUMENT )
//
// Writes log if the condition is satisfied and returns value from the second argument:
// IFDEBUG( ARGUMENT, RET )
//
// Note: If the function returns nothing but you wanna stop it anyway, use the space like: IFDEBUG(u == null, );
// Note: Log is written only in JNGP "Debug Mode".
// Configuration:
#define
{
Debug = true
private SavePath = NS_SNW_LOGS\\Logs
private PerformanceSavePath = NS_SNW_LOGS\\PerformanceLogs
private SaveOnHardDrive = true
private HardDriveLetter = C
private AutoSaveLog = true
private LogSavePeriod = 5.0
}
// by Faion, 2012
// by DoctorGester (Doc), 2011
library DebugLog initializer DebugLogInit
{
public bool EnableLogging = true
private string array DebugLog
private string array PerformanceDebugLog
private int CurrentString = 0
private int miliSeconds = 0
private int Seconds = 0
private int Minutes = 0
private int Hours = 0
private constant int StringLimit = 200
private int pastVal = 0;
private int PerformanceString = 0
void PerformanceLogAdd()
{
if (!EnableLogging)
{
return
}
string min = I2S(Minutes)
string sec = I2S(Seconds)
string msec = I2S(miliSeconds)
if (Minutes < 10)
{
min = "0" + min
}
if (Seconds < 10)
{
sec = "0" + sec
}
if (miliSeconds < 10)
{
msec = "0" + msec
}
location loc = Location(0,0);
int hId = GetHandleId(loc);
RemoveLocation(loc);
loc = null;
PerformanceDebugLog[PerformanceString] = PerformanceDebugLog[PerformanceString] + ("[" + I2S(Hours)+":" + min + ":" + sec + ":" + msec + "] " + I2S(hId-0x100000) + "\n")
if (StringLength(PerformanceDebugLog[PerformanceString]) >= StringLimit)
{
PerformanceString++
}
}
void PerformanceLogUpdate()
{
if (!EnableLogging)
{
return
}
PreloadGenClear()
PreloadGenStart()
int i = 0
while (i <= PerformanceString)
{
Preload("\")\n" + PerformanceDebugLog[i] + "\n(\"")
i++
}
#if SaveOnHardDrive
PreloadGenEnd(`HardDriveLetter` + ":\\" + `PerformanceSavePath` + ".txt")
#else
PreloadGenEnd("\\" + `PerformanceSavePath` + ".txt")
#endif
}
void LogAdd(string s)
{
if (!EnableLogging)
{
return
}
string min = I2S(Minutes)
string sec = I2S(Seconds)
string msec = I2S(miliSeconds)
if (Minutes < 10)
{
min = "0" + min
}
if (Seconds < 10)
{
sec = "0" + sec
}
if (miliSeconds < 10)
{
msec = "0" + msec
}
DebugLog[CurrentString] = DebugLog[CurrentString] + ("[" + I2S(Hours)+":" + min + ":" + sec + ":" + msec + "] " + s + "\n")
if (StringLength(DebugLog[CurrentString]) >= StringLimit)
{
CurrentString++
}
}
void LogClear()
{
int i = 0
while (i <= CurrentString)
{
DebugLog[i] = ""
i++
}
CurrentString = 0
}
void LogUpdate()
{
if (!EnableLogging)
{
return
}
PreloadGenClear()
PreloadGenStart()
int i = 0
while (i <= CurrentString)
{
Preload("\")\n" + DebugLog[i] + "\n(\"")
i++
}
#if SaveOnHardDrive
PreloadGenEnd(`HardDriveLetter` + ":\\" + `SavePath` + ".txt")
#else
PreloadGenEnd("\\" + `SavePath` + ".txt")
#endif
}
private void DebugLogOnTimer()
{
miliSeconds++
if (miliSeconds > 99)
{
miliSeconds = 0
Seconds++
if (Seconds > 59)
{
Seconds = 0
Minutes++
if (Minutes > 59)
{
Minutes = 0
Hours++
}
}
}
}
private void DebugLogInit()
{
#if AutoSaveLog
TimerStart(CreateTimer(), LogSavePeriod, true, function LogUpdate)
TimerStart(CreateTimer(), LogSavePeriod, true, function PerformanceLogUpdate)
#endif
TimerStart(CreateTimer(), 0.01, true, function DebugLogOnTimer)
TimerStart(CreateTimer(), 0.10, true, function PerformanceLogAdd)
LogAdd("By FaionBezarius. Last compilation: " + `DATE` + " " + `TIME`)
#if Debug
BJDebugMsg("By FaionBezarius. Last compilation: " + `DATE` + " " + `TIME`)
#endif
}
// by ScorpioT1000, 2009
// powered by AdicHelper(cJass.xgm.ru)
#define private assert_color = "FF404040"
nothing Ifdebug_debug_msg(string message, integer whichPlayer) {
LogAdd("|c"+assert_color+"Debug: "+message+"|r")
}
#define private DMSGFUNC = Ifdebug_debug_msg
#define IFDEBUGF(ARG,DEST_PLAYER) =
#define IFDEBUGFA(ARG,DEST_PLAYER) = {
if(ARG) {
} else {
I2R(2/0)
}
}
#define IFDEBUGR(ARG,WHATRET,DEST_PLAYER) = {
if(ARG) {
return WHATRET
}
}
#if DEBUG == 1
#setdef IFDEBUGF(ARG,DEST_PLAYER) = {
if(ARG) {
DMSGFUNC(`FUNCNAME` + ": " + `ARG`,DEST_PLAYER)
}
}
#setdef IFDEBUGFA(ARG,DEST_PLAYER) = {
if(ARG) {
} else {
DMSGFUNC(`FUNCNAME` + ": " + `ARG` + " failed",DEST_PLAYER)
I2R(2/0)
}
}
#setdef IFDEBUGR(ARG,WHATRET,DEST_PLAYER) = {
if(ARG) {
DMSGFUNC(`FUNCNAME` + ": " + `ARG`,DEST_PLAYER)
return WHATRET
}
}
#endif
//overloading
#define {
ASSERT(ARGUMENT) = IFDEBUGFA(ARGUMENT, -1)
IFDEBUG(ARGUMENT) = IFDEBUGF(ARGUMENT, -1) // with condition to all players
IFDEBUG(ARGUMENT,RET) = IFDEBUGR(ARGUMENT,RET, -1) // with condition and return to all players
IFDEBUGP(ARGUMENT,DEST_PLAYER) = IFDEBUGF(A,DEST_PLAYER) // with condition to one player
IFDEBUGP(ARGUMENT,RET,DEST_PLAYER) = IFDEBUGF(A,RET,DEST_PLAYER) // with condition and return to one players
}
}
Примеры
// функция остановится и в лог будет записано, что выполнено условие "u == null" в функции "foo"
function foo takes unit u returns nothing
IFDEBUG(u == null, )
KillUnit(u)
endfunction
// если не будет выполнено условие "x > 0", будет остановлена вся цепочка вызывавших ее функций и в логе будет запись об этой функции и условии
function xab takes integer a, integer b, integer c returns integer
local integer x = a * b * c
ASSERT(x > 0)
return SquareRoot(x)
endfunction
// вернет false если хотябы один из юнитов равен null, запишет всё в лог
function bvc takes nothing returns boolean
local unit u = GetTriggerUnit()
local unit t = GetSpellTargetUnit()
IFDEBUG(u == 0 or t == null, false)
// ...
return true
endfunction
Вот для тех, кто хочет понять истинный смысл: это просто - ты вставляешь этот код ВЕЗДЕ, во всех функциях и т.п. Естественно, доводишь до того состояния, чтобы ни одной ошибки не выходило. И когда проводишь рефакторинг, т.е. меняешь что-то внутри, меняешь логику или просто добавляешь функционал, проводишь ручные тесты и видишь ошибки - их легко исправить, сразу ясно, где и что случилось.
Это полный выигрыш перед вашими if () then BJDebugMsg("АЛАЛАЛААЛМАМА").
Т.е. выигрыш в том, что ты оставляешь эти проверки постоянно, а не на время. Тут сразу и префиксы есть и всё красиво написано.
Это полный выигрыш перед вашими if () then BJDebugMsg("АЛАЛАЛААЛМАМА").
Т.е. выигрыш в том, что ты оставляешь эти проверки постоянно, а не на время. Тут сразу и префиксы есть и всё красиво написано.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.
Забавно, но в ск2 это стандартная функция.
Отредактирован alexprey
Идея в общем то забавная, но не вижу в ней толкового смысла
убило вот что
Отредактирован ScorpioT1000
YellowStar, шёл бы ты отсюда, пастушок.
1000 итераций цикла, и это затраты перейдут в микро. По сравнению со сравнением это настолько мало, что можно пренебречь этой фигней. И вообще если так трестись из-за наносекунд может тогда весь код писать на чистом jass с ручной оптимизацией и обусфикацией?
Отредактирован ScorpioT1000
Кстати в идеале на jass надо длину имен функций и переменных минимизировать, особенно массивы, вот почему обфускаторы всегда мастхев =)
Т.е. выигрыш в том, что ты оставляешь эти проверки постоянно, а не на время. Тут сразу и префиксы есть и всё красиво написано.