forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Полезные функции (http://forum.boolean.name/forumdisplay.php?f=17)
-   -   Правильная загрузка конфиг файла (http://forum.boolean.name/showthread.php?t=16621)

burovalex 10.04.2012 11:08

Правильная загрузка конфиг файла
 
Сегодня начал писать загрузку конфигураций и мне понравилось что получилось
Я сделал так, что если какой-нибудь умник залезет править конфиги и накосячит, то файл просто удаляется и пишется новый с дефаулт конфигами :)

PHP код:

Global fileConfig
Global fileConfigError=False
Global graphicsW
Global graphicsH
Global graphicsD
Global graphicsM
Global cameraViewSens#
Const cameraViewSensMin#=0.5
Const cameraViewSensMax#=5
Const cameraViewSensDefault#=2

LoadFileConfig()        ;загрузка файла настроек


Function LoadFileConfig()
fileConfig=OpenFile("config.ini")
    ;-----------
eсли файл есть---------------------------
    If 
fileConfig<>0 Then
    graphicsW
=ReadLine(fileConfig)
    
graphicsH=ReadLine(fileConfig)
    
graphicsD=ReadLine(fileConfig)
    If 
GfxMode3DExists(GraphicsW,GraphicsH,GraphicsD)=False Then fileConfigError=True
    graphicsM
=ReadLine(fileConfig)
    If 
GraphicsM<Or GraphicsM>3 Then fileConfigError=True
    cameraViewSens
#=ReadLine(fileConfig)
    
If cameraViewSens<cameraViewSensMin Or cameraViewSens>cameraViewSensMax Then fileConfigError=True 
    
If fileConfigError=False Then Graphics3D GraphicsW,GraphicsH,GraphicsD,GraphicsM
    
If fileConfigError=True Then DeleteFile fileConfig fileConfig=0
    
EndIf 
    ;-----------
если файла нет---------------------------
    If 
fileConfig=0 Then
    
;считываем все поддерживаемые видео режимы
        
For i=1 To CountGfxModes3D()
        If 
GfxMode3DExists(GfxModeWidth(i),GfxModeHeight(i),GfxModeDepth(i)) Then modeN=modeN+1    
        Next
        Graphics3D GfxModeWidth
(modeN),GfxModeHeight(modeN),GfxModeDepth(modeN),1    ;выставляем самый высокий видео режим
    GraphicsW
=GraphicsWidth()
    
GraphicsH=GraphicsHeight()
    
GraphicsD=GraphicsDepth()
    
GraphicsM=1
    cameraViewSens
=cameraViewSensDefault
    fileConfig
=WriteFile("config.ini")
        
WriteLine(fileConfig,GraphicsW)
        
WriteLine(fileConfig,GraphicsH)
        
WriteLine(fileConfig,GraphicsD)
        
WriteLine(fileConfig,GraphicsM)
        
WriteLine(fileConfig,cameraViewSens)
    EndIf
    ;------------------------------------------------------------
CloseFile fileConfig
End 
Function 


Halk-DS 10.04.2012 13:56

Ответ: Правильная загрузка конфиг файла
 
Кул. :super: Было б круче увидеть набор функций для файла конфигов такого типа:

config.ini
Код:

GrWidth=1024
GrHeight=768
GrDeepth=32
GrMode=2

Я имею в виду, чтоб можно было записать все как выше, а можно было б написать так: (и не было б разницы для программы)

Код:

GrDeepth=32
GrWidth=1024
;бла бла бла - комментарий
GrHeight=768  GrMode=2

А в случае фейла каких либо параметров - генерировать новые.

burovalex 10.04.2012 14:30

Ответ: Правильная загрузка конфиг файла
 
Это просто "длясебятина" )
Мне такая заморочка не нужна.
Тем более такой подход не избавит от правки кода при изменении полей (я про то что все равно придется в коде прописывать откат), короче я к тому что такой подход жизнь особо не облегчит в конфиг файле, а вот загрузчике уровня, где может быть сотни объектов с десятком параметром, без твоей методы не обойтись!
Суть я раскрыл, а кому надо уже доработают :)

impersonalis 10.04.2012 15:03

Ответ: Правильная загрузка конфиг файла
 
что-то типа (код грязненький)
Код:

Const CfgLoader__SEP$="="

Type TOneCfgParam
        Field Name$
        Field Value$
End Type

Function CfgLoader_CreateParam.TOneCfgParam(Name$,Val$)
        ;DebugLog Name+"="+Val
        Local OCP.TOneCfgParam=New TOneCfgParam
        OCP\Name=Name
        OCP\Value=Val
        Return OCP
End Function

Function CfgLoader_GetParam.TOneCfgParam(Name$)
        For OCP.TOneCfgParam=Each TOneCfgParam
                If OCP\Name=Name
                        Return OCP
                EndIf
        Next
        Return Null
End Function

Function CfgLoader_GetParamVal$(Name$)
        Local OCP.TOneCfgParam=CfgLoader_GetParam(Name)
        If OCP=Null
                RuntimeError "Param "+Name+" not found!"
        EndIf
        Return OCP\Value
End Function

Function CfgLoader_ParseParam.TOneCfgParam(OneLine$)
        Local I%=Instr(OneLine,CfgLoader__SEP,1)
        Local Name$=Left(OneLine,I-1)
        Local Value$=Right(OneLine,Len(OneLine)-I)
        Return CfgLoader_CreateParam(Name,Value)
End Function

Function CfgLoader_LoadCfgFromFile(FileName$)
        Local File%=ReadFile(FileName)
        If File=False
                RuntimeError "File "+FileName+" not found!"
        EndIf
        Local OneLine$
        While Not Eof(File)
                OneLine=ReadLine(File)
                CfgLoader_ParseParam(OneLine)
        Wend
        CloseFile(File)
End Function

Цитата:

Сообщение от cfg.txt
WinXSize=800
WinYSize=600

Код:

CfgLoader_LoadCfgFromFile("cfg.txt")
Global WinXSize%=Int(CfgLoader_GetParamVal("WinXSize"))
Global WinYSize%=Int(CfgLoader_GetParamVal("WinYSize"))


burovalex 10.04.2012 16:34

Ответ: Правильная загрузка конфиг файла
 
Прикольно!
Мне до такого еще далеко...
Объясните пожалуста, зачем нужна точка в функции CfgLoader_ParseParam.TOneCfgParam(OneLine$)
Т.е. функция пишется специально для этого типа?

И еще, я сейчас пишу загрузчик уровня, прокоментируйте пожалуста какие недостатки и подводные камни могут быть

PHP код:

Function LoadLevel(levelName)
sx#=0.0
sy#=0.0
sz#=0.0
Select levelName
Case levelNameMain
file
=OpenFile("main.lev")
End Select

While Not Eof(file)
s$=ReadLine(file)
;
ищет объект
If StrLeft(s,"ground")=True Then sEntity=CreateTerrain(256)
If 
StrLeft(s,"tree")=True Then tree.tree=New tree tree\entity=LoadMesh("tree.b3d")
;
ищет параметр
If StrLeft(s,"x")=True Then MoveEntity sEntity,FloatRight(s),0,0
If StrLeft(s,"y")=True Then MoveEntity sEntity,0,FloatRight(s),0
If StrLeft(s,"z")=True Then MoveEntity sEntity,0,0,FloatRight(s)
Wend 
CloseFile file
End 
Function

Function 
StrLeft%(Str1$,Str2$)
If 
Left(Str1,Len(Str2))=Str2 Then Return True 
End 
Function

Function 
FloatRight#(S$)
s=Trim(s)
ReadThis%=True
res
$=""
tmp$=""
For i=0 To Len(S)-1
    simbol
$=Mid(S,Len(s)-i,1)
    If 
ReadThis=True
        
If (Asc(simbol)>=48 And Asc(simbol)<=57) Or simbol="." Then
        res
=simbol+res    
        
Else
        
ReadThis=False
        
EndIf
    EndIf
Next
Return Float(res)
End Function 


Жека 11.04.2012 05:48

Ответ: Правильная загрузка конфиг файла
 
Цитата:

Сообщение от burovalex (Сообщение 225057)
Прикольно!
Мне до такого еще далеко...
Объясните пожалуста, зачем нужна точка в функции CfgLoader_ParseParam.TOneCfgParam(OneLine$)
Т.е. функция пишется специально для этого типа?

После имени любой функции нужно ставить тип возвращаемого ей значения, или ничего не ставить, если не нужно ничего возвращать:
Код:

MyIntegerFunction%()  - для интовых якобы можно не ставить, оно по умолчанию int
MyFloatFunction#()
MyStringFunction$()

Т.к. пользовательские типы данных определяются через точку:
Код:

myTypeVariable.MyTypeName = new MyTypeName
то чтобы вернуть из функции пользовательский тип, нужно через точку указать его после имени функции.
Вышеуказанная функция возвращает в качестве результата данные типа TOneCfgParam.
Цитата:

Сообщение от burovalex (Сообщение 225057)
И еще, я сейчас пишу загрузчик уровня, прокоментируйте пожалуста какие недостатки и подводные камни могут быть

Мне более удобным кажется хранение уровня в структурированном виде типа такого:
Код:

tree {
model="models\tree1.3ds"
scale=x#,y#,z#
position=x#,y#,z#
rotation=x#,y#,z#
и любые параметры тут
}

По такому формату ты проверяешь текущую считанную строку на совпадение с "tree {" и далее пробуешь выцепить все возможные параметры, которые может иметь дерево, пока не дойдёшь до строки, содержащей "}" - на этом перестаёшь дереву что-то искать, начинаешь искать новые ключевые слова: "слово[i] {", и т.д.

Названия параметров отделены от значений символом "=", поэтому считанную строку разбиваешь на две - до равно и после (в блице функция Instr). Значения могут содержать несколько значений, разделить их можно запятой (как выше для x,y,z) или точкой с запятой или ещё чем-нибудь. По этому символу разобьёшь строку и получишь все параметры.

Сохранять такую структуру данных можно сразу из редактора карт.

По коду твоему.
Вместо такого:
Код:

Select levelName
Case levelNameMain
file=OpenFile("main.lev")
End Select

While Not Eof(file)

я бы написал такое:
Код:

Local fileName$ = ""
Select levelName
Case levelNameMain
fileName = "main.lev"
End Select

If(FileType(fileName) <> 1) Then RuntimeError("File "+fileName+" not found. Reinstall program.")
file=OpenFile(fileName)
While Not Eof(file)

Ещё - для перевода строки в число можно писать вот так:
Код:

intVal = Int(str$)
floatVal = Float(str$)

если строка начинается не с числа, то получишь ноль. Поэкспериментируй, передавая разные параметры.

burovalex 11.04.2012 12:05

Ответ: Правильная загрузка конфиг файла
 
Спасибо! Полезно!
Вот только мне не нравится что значения надо будет считывать через запятую, может проще в строку все писать
tree {
positionX=2
positionY=3
positionZ=4
}
В таком варианте нет сложности, т.к. можно узнать позицию объекта, и прочитав строку positionX - выполнить PositionEntity ent,positionX,entityY(ent),entityZ(ent).
А вот с масштабом такое не проканает, потому что нету такой функции типа EntityScaleX() или чтото вроде..
И вот хз че делать

Жека 11.04.2012 13:12

Ответ: Правильная загрузка конфиг файла
 
Зачем разделять? Это только усложнит.
Псевдокод:
Код:

Local entityKind$ ;чтоб знать кому параметры устанавливать, можно int-ом сделать
Local bReadParams% ;флаг - состояние чтения ключевых слов (false) или параметров (true)
Local strLine$, cmdName$,  ;текущая строка, считанная из файла, имя параметра
Local tree.TTree ;ссылка на текущее создаваемое дерево, и так перечисляешь здесь все возможные типы создаваемых объектов. по хорошему тут должен быть тип базового класса, но классов тю-тю в блитце
Local entity% ;можно один указатель на все создаваемые модельки сделать, и его присваивать
Dim cmdParams$(0) ;пустой пока, сюда будем вставлять параметры типа x,y,z. приходится делать глобальный массив, т.к. в блитце нельзя возвращать массив из функций, массивы всегда глобальные. чтоб освободить память пишешь в "любом" месте Dim cmdParams$(0) - размер ноль.
................
strLine = ReadLine(file)
If(bReadParams = False) ;если не параметры, то ключевые слова ищем
        If(strLine = "tree {")
                ;тут создаём например
                tree = New TTree
                entityKind = "tree"
                bReadParams = True ;дальше будем параметры читать
                strLine = ReadLine(file) ;чтоб не пропускать цикл сразу следующую строку читаем
        EndIf
        If(bReadParams = True)
                cmdName = GetCmdName(strLine) ;возвращает значение до символа "=", твоя функция
                If(cmdName = "}") ;параметры кончились
                        If(entityKind = "tree")
                                tree\ent = entity ;присваиваем дереву
                        Else If(.....)
                               
                        EndIf
                        entity = 0 ;временного объекта теперь нет, он стал деревом :)
                Else  ;читаем общие для всех моделек параметры
                        GetCmdParams(strLine, ",") ;твоя функция, разбивает то что после "=" по символу,
                        ;идущему вторым параметром функции, и записывает в массив, размерность массива внутри функции переопределяется в зависимости
                        ;от количества найденных символов-разделителей
                        ;например для параметра "model" массив будет размерностью 1 и содержать путь к модельке (например, ты можешь хоть чё вставить)
                        If(cmdName = "model")
                                entity = LoadMesh(cmdParams(0))
                        EndIf
                        ;
                        If(entity <> 0)
                                Else If(cmdName = "position")
                                        PositionEntity entity,Float(cmdParams(0),Float(cmdParams(1),Float(cmdParams(2)
                                Else If(cmdName = "scale")
                                        ScaleEntity entity,Float(cmdParams(0),Float(cmdParams(1),Float(cmdParams(2)
                                Else
                                        ;и т.д.
                                EndIf
                        EndIf
                        ;плюс проверка наличия индивидуальных параметров, присущих только деревьям (и другим уникальным объектам)
                        If(entityKind = "tree")
                                If(cmdName = "enable_wind") ;воздействует ли ветер
                                        tree\bWindEnable = Int(cmdParams(0))
                                EndIf
                        EndIf
                       
                EndIf
        EndIf
EndIf


burovalex 11.04.2012 16:39

Ответ: Правильная загрузка конфиг файла
 
Прикольно написал!!
Всё доступно и понятно! Спасибо большое!! Буду делать :)

Жека 12.04.2012 05:09

Ответ: Правильная загрузка конфиг файла
 
Как говорится, "Обращайтесь!" :)

DStalk 12.04.2012 07:34

Ответ: Правильная загрузка конфиг файла
 
Вложений: 1
Давно пользуюсь набором функций - не помню кто их автор и где я их взял, но удобно:)


Часовой пояс GMT +4, время: 16:07.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot