diff --git a/cont/base/springcontent/gamedata/modrules.lua b/cont/base/springcontent/gamedata/modrules.lua index 71e5d68170e..8894dc12e56 100644 --- a/cont/base/springcontent/gamedata/modrules.lua +++ b/cont/base/springcontent/gamedata/modrules.lua @@ -46,7 +46,7 @@ end if (not (haveRules or haveSensors)) then - return false + return {} end diff --git a/cont/base/springcontent/gamedata/sounds.lua b/cont/base/springcontent/gamedata/sounds.lua index 81310ecbc35..bce25ab388d 100644 --- a/cont/base/springcontent/gamedata/sounds.lua +++ b/cont/base/springcontent/gamedata/sounds.lua @@ -1,7 +1,10 @@ ---- Valid entries used by engine: IncomingChat, MultiSelect, MapPoint ---- other than that, you can give it any name and access it like before with filenames local Sounds = { SoundItems = { + --[[ + -- these four entries are played by the engine for corresponding events + -- the referenced .wav files are *not* supplied by base content, change + -- them if uncommenting an entry + -- any other name is free to use; sounds can also be referred to by file IncomingChat = { --- always play on the front speaker(s) file = "sounds/beep4.wav", @@ -13,12 +16,18 @@ local Sounds = { in3d = "false", }, MapPoint = { - --- respect where the point was set, but don't attuenuate in distace - --- also, when moving the camera, don't pitch it + --- respect where point was set, but don't attenuate over distance + --- also, when moving the camera, don't apply any pitch shift file = "sounds/beep6.wav", rolloff = 0, dopplerscale = 0, }, + FailedCommand = { + file = "sounds/beep3.wav", + }, + --]] + + ExampleSound = { --- some things you can do with this file @@ -43,7 +52,7 @@ local Sounds = { --- dopplerscale = 0 completely disables the effect dopplerscale = 1, - --- when lots of sounds are played, sounds with lwoer priority are more likely to get cut off + --- when lots of sounds are played, sounds with lower priority are more likely to get cut off --- priority > 0 will never be cut of (priorities can be negative) priority = 0, @@ -63,9 +72,6 @@ local Sounds = { --- you can loop it for X miliseconds looptime = 0, }, - FailedCommand = { - file = "sounds/beep3.wav", - }, default = { --- new since 89.0 diff --git a/rts/Lua/LuaParser.cpp b/rts/Lua/LuaParser.cpp index 1d914e65876..3f754f624af 100644 --- a/rts/Lua/LuaParser.cpp +++ b/rts/Lua/LuaParser.cpp @@ -24,6 +24,7 @@ #include "System/FileSystem/FileHandler.h" #include "System/Misc/SpringTime.h" #include "System/ContainerUtil.h" +#include "System/TimeProfiler.h" #include "System/ScopedFPUSettings.h" #include "System/StringUtil.h" @@ -65,9 +66,7 @@ LuaParser::LuaParser(const std::string& _fileName, const std::string& _fileModes } LuaParser::LuaParser(const std::string& _textChunk, const std::string& _accessModes, const boolean& synced, const boolean& setup) - : fileName("") - , fileModes("") - , textChunk(_textChunk) + : textChunk(_textChunk) , accessModes(_accessModes) , D(false, false) @@ -196,12 +195,11 @@ void LuaParser::SetupEnv(bool isSyncedCtxt, bool isDefsParser) bool LuaParser::Execute() { if (!IsValid()) { - errorLog = "could not initialize LUA library"; + errorLog = "could not initialize Lua library"; return false; } - rootRef = LUA_NOREF; - + assert(rootRef == LUA_NOREF); assert(initDepth == 0); initDepth = -1; @@ -213,26 +211,30 @@ bool LuaParser::Execute() codeLabel = "text chunk"; } else if (!fileName.empty()) { - codeLabel = fileName; - CFileHandler fh(fileName, fileModes); + CFileHandler fh(codeLabel = fileName, fileModes); + if (!fh.LoadStringData(code)) { errorLog = "could not open file: " + fileName; + LUA_CLOSE(&L); return false; } } else { errorLog = "invalid format or empty file"; + LUA_CLOSE(&L); return false; } - int error = luaL_loadbuffer(L, code.c_str(), code.size(), codeLabel.c_str()); + char errorBuf[4096] = {0}; + int errorNum = 0; - if (error != 0) { - errorLog = lua_tostring(L, -1); - LOG_L(L_ERROR, "%i, %s, %s", error, codeLabel.c_str(), errorLog.c_str()); + if ((errorNum = luaL_loadbuffer(L, code.c_str(), code.size(), codeLabel.c_str())) != 0) { + SNPRINTF(errorBuf, sizeof(errorBuf), "[loadbuf] error %d (\"%s\") in %s", errorNum, lua_tostring(L, -1), codeLabel.c_str()); LUA_CLOSE(&L); + + errorLog = errorBuf; return false; } @@ -242,21 +244,33 @@ bool LuaParser::Execute() // do not signal floating point exceptions in user Lua code ScopedDisableFpuExceptions fe; - error = lua_pcall(L, 0, 1, 0); - if (error != 0) { - errorLog = lua_tostring(L, -1); - LOG_L(L_ERROR, "%i, %s, %s", error, fileName.c_str(), errorLog.c_str()); + if ((errorNum = lua_pcall(L, 0, 1, 0)) != 0) { + SNPRINTF(errorBuf, sizeof(errorBuf), "[pcall] error %d (\"%s\") in %s", errorNum, lua_tostring(L, -1), fileName.c_str()); LUA_CLOSE(&L); + + errorLog = errorBuf; return false; } + #if 0 if (!lua_istable(L, 1)) { - errorLog = "missing return table from " + fileName; - LOG_L(L_ERROR, "missing return table from %s", fileName.c_str()); + errorLog = "no return table from " + fileName; + LUA_CLOSE(&L); return false; } + #else + // make not returning a table (which may or may not be intentional) + // equivalent to returning an empty one; leave it to callers whether + // they consider this an error + if (!lua_istable(L, 1)) { + lua_pop(L, lua_gettop(L)); + lua_newtable(L); + + errorLog = "no return table from " + fileName; + } + #endif if (lowerKeys) LuaUtils::LowerKeys(L, 1); @@ -266,8 +280,8 @@ bool LuaParser::Execute() rootRef = luaL_ref(L, LUA_REGISTRYINDEX); lua_settop(L, 0); - valid = true; - return true; + + return (valid = true); } @@ -473,24 +487,27 @@ void LuaParser::AddString(int key, const std::string& value) int LuaParser::TimeCheck(lua_State* L) { + #if (!defined(UNITSYNC) && !defined(DEDICATED)) if (!lua_isstring(L, 1) || !lua_isfunction(L, 2)) luaL_error(L, "Invalid arguments to TimeCheck('string', func, ...)"); - const std::string name = lua_tostring(L, 1); - lua_remove(L, 1); + { + ScopedOnceTimer timer(lua_tostring(L, 1)); - const spring_time startTime = spring_gettime(); + lua_remove(L, 1); - if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) { - const std::string errmsg = lua_tostring(L, -1); - lua_pop(L, 1); - luaL_error(L, errmsg.c_str()); - } + if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) { + const std::string errmsg = lua_tostring(L, -1); - const spring_time endTime = spring_gettime(); + lua_pop(L, 1); + luaL_error(L, errmsg.c_str()); + } + } - LOG("%s %ldms", name.c_str(), (long int) spring_tomsecs(endTime - startTime)); return lua_gettop(L); + #else + return 0; + #endif } diff --git a/rts/Lua/LuaParser.h b/rts/Lua/LuaParser.h index 8e33f098f36..4de1d8b77da 100644 --- a/rts/Lua/LuaParser.h +++ b/rts/Lua/LuaParser.h @@ -127,7 +127,8 @@ class LuaParser { void SetupLua(bool isSyncedCtxt, bool isDefsParser); bool Execute(); - bool IsValid() const { return (L != nullptr); } + bool IsValid() const { return (L != nullptr); } // true if nothing failed during Execute + bool NoTable() const { return (errorLog.find("no return table") == 0); } // parser is still valid if true LuaTable GetRoot(); LuaTable SubTableExpr(const std::string& expr) { diff --git a/rts/Lua/LuaUnsyncedCtrl.cpp b/rts/Lua/LuaUnsyncedCtrl.cpp index 931abd5cb56..f873d436ced 100644 --- a/rts/Lua/LuaUnsyncedCtrl.cpp +++ b/rts/Lua/LuaUnsyncedCtrl.cpp @@ -529,46 +529,54 @@ int LuaUnsyncedCtrl::PlaySoundFile(lua_State* L) } } - // last argument (with and without pos/speed arguments) is the optional `sfx channel` - IAudioChannel** channel = &Channels::General; + // last argument (with and without pos/speed arguments) is the optional channel + IAudioChannel* channel = Channels::General; if (args >= index) { if (lua_isstring(L, index)) { - string channelStr = lua_tostring(L, index); - StringToLowerInPlace(channelStr); - - if (channelStr == "battle" || channelStr == "sfx") { - channel = &Channels::Battle; - } - else if (channelStr == "unitreply" || channelStr == "voice") { - channel = &Channels::UnitReply; - } - else if (channelStr == "userinterface" || channelStr == "ui") { - channel = &Channels::UserInterface; + switch (hashString(lua_tostring(L, index))) { + case hashString("Battle"): + case hashString("battle"): + case hashString("SFX" ): + case hashString("sfx" ): { + channel = Channels::Battle; + } break; + + case hashString("UnitReply"): + case hashString("unitreply"): + case hashString("Voice" ): + case hashString("voice" ): { + channel = Channels::UnitReply; + } break; + + case hashString("UserInterface"): + case hashString("userinterface"): + case hashString("UI" ): + case hashString("ui" ): { + channel = Channels::UserInterface; + } break; + + default: { + } break; } } else if (lua_isnumber(L, index)) { - const int channelNum = lua_toint(L, index); - - if (channelNum == 1) { - channel = &Channels::Battle; - } - else if (channelNum == 2) { - channel = &Channels::UnitReply; - } - else if (channelNum == 3) { - channel = &Channels::UserInterface; + switch (lua_toint(L, index)) { + case 1: { channel = Channels::Battle ; } break; + case 2: { channel = Channels::UnitReply ; } break; + case 3: { channel = Channels::UserInterface; } break; + default: { } break; } } } if (index >= 6) { if (index >= 9) { - channel[0]->PlaySample(soundID, pos, speed, volume); + channel->PlaySample(soundID, pos, speed, volume); } else { - channel[0]->PlaySample(soundID, pos, volume); + channel->PlaySample(soundID, pos, volume); } } else - channel[0]->PlaySample(soundID, volume); + channel->PlaySample(soundID, volume); } if (!CLuaHandle::GetHandleSynced(L)) { diff --git a/rts/Sim/Misc/ModInfo.cpp b/rts/Sim/Misc/ModInfo.cpp index 42a4397eaa7..f43f9b23f36 100644 --- a/rts/Sim/Misc/ModInfo.cpp +++ b/rts/Sim/Misc/ModInfo.cpp @@ -100,7 +100,6 @@ void CModInfo::Init(const std::string& modFileName) description = md.GetDescription(); } - // initialize the parser LuaParser parser("gamedata/modrules.lua", SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP); // customize the defs environment parser.GetTable("Spring"); @@ -109,7 +108,7 @@ void CModInfo::Init(const std::string& modFileName) parser.Execute(); if (!parser.IsValid()) - LOG_L(L_ERROR, "Failed loading mod-rules, using defaults; error: %s", parser.GetErrorLog().c_str()); + LOG_L(L_ERROR, "[ModInfo::%s] error \"%s\" loading mod-rules, using defaults", __func__, parser.GetErrorLog().c_str()); const LuaTable& root = parser.GetRoot();