root/cafu/trunk/CaWE/GameConfig.cpp

Revision 455, 11.3 KB (checked in by Carsten, 4 months ago)

Updated copyright banners (in C++ files).

Line 
1/*
2=================================================================================
3This file is part of Cafu, the open-source game engine and graphics engine
4for multiplayer, cross-platform, real-time 3D action.
5Copyright (C) 2002-2012 Carsten Fuchs Software.
6
7Cafu is free software: you can redistribute it and/or modify it under the terms
8of the GNU General Public License as published by the Free Software Foundation,
9either version 3 of the License, or (at your option) any later version.
10
11Cafu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13PURPOSE. See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with Cafu. If not, see <http://www.gnu.org/licenses/>.
17
18For support and more information about Cafu, visit us at <http://www.cafu.de>.
19=================================================================================
20*/
21
22#include "GameConfig.hpp"
23#include "EntityClass.hpp"
24#include "FileSys/FileMan.hpp"
25#include "wx/fileconf.h"
26
27extern "C"
28{
29    #include <lua.h>
30    #include <lualib.h>
31    #include <lauxlib.h>
32}
33
34
35GameConfigT::GameConfigT(wxFileConfig& CfgFile, const wxString& Name_, const wxString& ModDir_)
36    : Name(Name_),
37      ModDir(ModDir_),
38      m_MatMan(*this),
39      m_ModelMan(),
40      m_GuiResources(m_ModelMan),
41      m_MaxMapCoord(8192)
42{
43    // The next line doesn't work with wx 2.6.4, it always returns the default value 1.0.
44 // DefaultTextureScale =CfgFile.Read("DefaultTextureScale", 1.0);
45    double d;
46    CfgFile.Read("DefaultTextureScale",  &d, 0.25); DefaultTextureScale =d;     // Work-around...
47    CfgFile.Read("DefaultLightmapScale", &d, 16.0); DefaultLightmapScale=d;
48
49    DefaultSolidEntity  =CfgFile.Read("DefaultSolidEntity", "func_wall");
50    DefaultPointEntity  =CfgFile.Read("DefaultPointEntity", "info_player_start");
51    CordonTexture       =CfgFile.Read("CordonTexture", "Textures/generic/_orange");
52
53
54    // Mount the file systems relevant for this MOD.
55    const std::string ModDirSlash(ModDir+"/");
56
57    m_MountedFileSystems.PushBack(cf::FileSys::FileMan->MountFileSystem(cf::FileSys::FS_TYPE_LOCAL_PATH, ModDirSlash, ModDirSlash));
58    m_MountedFileSystems.PushBack(cf::FileSys::FileMan->MountFileSystem(cf::FileSys::FS_TYPE_ZIP_ARCHIVE, ModDirSlash+"Textures/TechDemo.zip", ModDirSlash+"Textures/TechDemo/", "Ca3DE"));
59    m_MountedFileSystems.PushBack(cf::FileSys::FileMan->MountFileSystem(cf::FileSys::FS_TYPE_ZIP_ARCHIVE, ModDirSlash+"Textures/SkyDomes.zip", ModDirSlash+"Textures/SkyDomes/", "Ca3DE"));
60
61
62    // Create a new Lua state.
63    lua_State* LuaState=lua_open();
64
65    try
66    {
67        if (LuaState==NULL) throw InitErrorT();
68
69        lua_pushcfunction(LuaState, luaopen_base);    lua_pushstring(LuaState, "");              lua_call(LuaState, 1, 0);  // Opens the basic library.
70        lua_pushcfunction(LuaState, luaopen_package); lua_pushstring(LuaState, LUA_LOADLIBNAME); lua_call(LuaState, 1, 0);  // Opens the package library.
71        lua_pushcfunction(LuaState, luaopen_table);   lua_pushstring(LuaState, LUA_TABLIBNAME);  lua_call(LuaState, 1, 0);  // Opens the table library.
72        lua_pushcfunction(LuaState, luaopen_io);      lua_pushstring(LuaState, LUA_IOLIBNAME);   lua_call(LuaState, 1, 0);  // Opens the I/O library.
73        lua_pushcfunction(LuaState, luaopen_os);      lua_pushstring(LuaState, LUA_OSLIBNAME);   lua_call(LuaState, 1, 0);  // Opens the OS library.
74        lua_pushcfunction(LuaState, luaopen_string);  lua_pushstring(LuaState, LUA_STRLIBNAME);  lua_call(LuaState, 1, 0);  // Opens the string lib.
75        lua_pushcfunction(LuaState, luaopen_math);    lua_pushstring(LuaState, LUA_MATHLIBNAME); lua_call(LuaState, 1, 0);  // Opens the math lib.
76
77
78        // Load and process the Lua script file with the entity class definitions.
79        if (luaL_loadfile(LuaState, (ModDir+"/EntityClassDefs.lua").c_str())!=0 || lua_pcall(LuaState, 0, 0, 0)!=0)
80        {
81            wxMessageBox("Entity class definitions script could not be processed,\n"+
82                         wxString(lua_tostring(LuaState, -1))+".\n",
83                         "Error while initializing game configuration \""+Name+"\"", wxOK | wxICON_ERROR);
84
85            lua_pop(LuaState, 1);
86            throw InitErrorT();
87        }
88
89        assert(lua_gettop(LuaState)==0);
90
91
92        // Obtain the "Mapsize" information.
93        lua_getglobal(LuaState, "Mapsize");
94
95        if (lua_istable(LuaState, -1))
96        {
97            lua_rawgeti(LuaState, -1, 1);
98            int Min=lua_tointeger(LuaState, -1);
99            lua_pop(LuaState, 1);
100
101            lua_rawgeti(LuaState, -1, 2);
102            int Max=lua_tointeger(LuaState, -1);
103            lua_pop(LuaState, 1);
104
105            if (Min!=0 && Max!=0)
106            {
107                m_MaxMapCoord=std::max(abs(Min), abs(Max));
108            }
109
110            // wxMessageBox(wxString::Format("Found the Mapsize table:    %i,   %i", m_MinMapCoord, m_MaxMapCoord));
111        }
112
113        assert(lua_gettop(LuaState)==1);
114        lua_pop(LuaState, 1);
115
116
117        // Create an EntityClassT instance for each entity class definition in the "EntityClassDefs" table.
118        lua_getglobal(LuaState, "EntityClassDefs");
119        lua_pushnil(LuaState);  // The initial key for the traversal.
120
121        while (lua_next(LuaState, -2)!=0)
122        {
123            // The key is now at stack index -2, the value is at index -1.
124            // Note that in general, the warning from the Lua reference documentation applies:
125            // "While traversing a table, do not call lua_tolstring() directly on a key, unless you know that the key is actually a string."
126            // Fortunately, we know that the key is of type string, and so the called function is free to inspect (but not to modify!)
127            // the two topmost stack values.
128            if (lua_type(LuaState, -2)!=LUA_TSTRING)
129            {
130                wxMessageBox("Non-string entity class name in EntityClassDefs table.\n",
131                    "Error while initializing game configuration \""+Name+"\"", wxOK | wxICON_ERROR);
132                throw InitErrorT();
133            }
134
135            try
136            {
137                m_EntityClasses.PushBack(new EntityClassT(*this, LuaState));
138            }
139            catch (const EntityClassT::InitErrorT&)
140            {
141                // For some reason, the entity class could not be created, and our stack is now in an unknown state
142                // (our lower three elements should still be intact, but any number of elements may be on top).
143                // We could of course try to recover (pop all elements above ours) and continue,
144                // but there is still some risk and there was an error with the script that should be looked into anyway,
145                // so we're just bailing out.
146                throw InitErrorT();
147            }
148
149            // Make sure that the EntityClassT ctor left the stack behind properly.
150            assert(lua_gettop(LuaState)==3);
151
152            // Remove the value, keep the key for the next iteration.
153            lua_pop(LuaState, 1);
154        }
155
156        assert(lua_gettop(LuaState)==1);
157        lua_pop(LuaState, 1);
158    }
159    catch (const InitErrorT&)
160    {
161        // What is done here is of course utterly against all (RAII-related) advice, see
162        // a) Bjarne Stroustrup, "Die C++ Programmiersprache", chapter 14.4.
163        // b) Scott Meyers, "Effective C++, 3rd Edition", item 13 (and 14).
164        // c) http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
165        // Unfortunately, auto_ptr<> is not well suitable here, and I currently see no
166        // easy solution rather than to do it like this.
167
168        // Close the LuaState.
169        if (LuaState!=NULL) lua_close(LuaState);
170
171        // Delete all entity classes.
172        for (unsigned long ECNr=0; ECNr<m_EntityClasses.Size(); ECNr++)
173            delete m_EntityClasses[ECNr];
174
175        // Unmount any mounted file systems.
176        for (unsigned long MFSNr=0; MFSNr<m_MountedFileSystems.Size(); MFSNr++)
177            cf::FileSys::FileMan->Unmount(m_MountedFileSystems[MFSNr]);
178
179        throw;  // Re-throw the caught exception.
180    }
181
182    // Close the LuaState.
183    lua_close(LuaState);
184
185
186    // Output a brief overview of the loaded classes and their variables.
187    // This is for debugging purposes.
188#if 0
189    wxString out;
190
191    for (unsigned long ClassNr=0; ClassNr<m_EntityClasses.Size(); ClassNr++)
192    {
193        const EntityClassT* EC=m_EntityClasses[ClassNr];
194
195        out+=EC->GetName()+": "+EC->GetDescription()+"\n";
196        out+=EC->GetColor().GetAsString(wxC2S_CSS_SYNTAX)+", ["+convertToString(EC->GetBoundingBox().Min).c_str()+", "+convertToString(EC->GetBoundingBox().Max).c_str()+"]\n";
197
198        if (EC->IsSolidClass()) out+="isSolid, ";
199
200        out+="Helpers: ";
201        for (unsigned long HNr=0; HNr<EC->GetHelpers().Size(); HNr++)
202        {
203            const HelperInfoT* HI=EC->GetHelpers()[HNr];
204
205            out+=HI->Name+"(";
206            for (unsigned long PNr=0; PNr<HI->Parameters.Size(); PNr++) out+=HI->Parameters[PNr]+" ";
207            out+=") ";
208        }
209        out+="\n";
210
211        // out+="Vars:\n";
212        for (unsigned long VarNr=0; VarNr<EC->GetVariables().Size(); VarNr++)
213        {
214            const EntClassVarT* Var=EC->GetVariables()[VarNr];
215
216            out+="           "+Var->GetName()+", "+Var->GetLongName()+", "+Var->GetDescription()+wxString::Format("  Type: %i", Var->GetType())+"\n";
217        }
218
219        out+="\n";
220    }
221
222    // wxMessageBox(out, "Entity Classes Overview", wxOK | wxICON_INFORMATION);
223    wxLogDebug(out);
224#endif
225}
226
227
228GameConfigT::~GameConfigT()
229{
230    // Delete all entity classes.
231    for (unsigned long ECNr=0; ECNr<m_EntityClasses.Size(); ECNr++)
232        delete m_EntityClasses[ECNr];
233
234    if (cf::FileSys::FileMan!=NULL)
235    {
236        for (unsigned long MFSNr=0; MFSNr<m_MountedFileSystems.Size(); MFSNr++)
237            cf::FileSys::FileMan->Unmount(m_MountedFileSystems[MFSNr]);
238    }
239
240    m_MountedFileSystems.Clear();
241}
242
243
244const EntityClassT* GameConfigT::FindClass(const wxString& Name) const
245{
246    for (unsigned long ClassNr=0; ClassNr<m_EntityClasses.Size(); ClassNr++)
247        if (m_EntityClasses[ClassNr]->GetName()==Name)
248            return m_EntityClasses[ClassNr];
249
250    return NULL;
251}
252
253
254const CafuModelT* GameConfigT::GetModel(const wxString& FileName, wxString* ErrorMsg) const
255{
256    std::string       Msg;
257    const CafuModelT* Model=m_ModelMan.GetModel(std::string(ModDir + "/" + FileName), &Msg);
258
259    if (ErrorMsg)
260        *ErrorMsg=Msg;
261
262    return Model;
263}
264
265
266BoundingBox3fT GameConfigT::GetMaxMapBB() const
267{
268    const float f=m_MaxMapCoord;
269
270    return BoundingBox3fT(Vector3fT(-f, -f, -f), Vector3fT(f, f, f));
271}
272
273
274void GameConfigT::Save(wxFileConfig& CfgFile) const
275{
276    CfgFile.DeleteGroup(".");
277
278    CfgFile.Write("DefaultTextureScale",  DefaultTextureScale);
279    CfgFile.Write("DefaultLightmapScale", DefaultLightmapScale);
280
281    CfgFile.Write("DefaultSolidEntity", DefaultSolidEntity);
282    CfgFile.Write("DefaultPointEntity", DefaultPointEntity);
283
284    CfgFile.Write("CordonTexture", CordonTexture);
285}
Note: See TracBrowser for help on using the browser.