From 8c43857b739566be1e59d61aec192ef63e77cbb1 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sat, 8 Sep 2012 16:08:29 +0000 Subject: Added the ItemToString() and ItemTypeToString() functions. Ref.: http://forum.mc-server.org/showthread.php?tid=434&pid=4506#pid4506 git-svn-id: http://mc-server.googlecode.com/svn/trunk@847 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- iniFile/iniFile.cpp | 147 +++++++++++++++++++++++++----------------- source/Bindings.cpp | 168 +++++++++++++++++++++++++++++++++++++++++++++++- source/Bindings.h | 2 +- source/BlockID.cpp | 181 ++++++++++++++++++++++++++++++++++++++++++---------- source/BlockID.h | 8 ++- 5 files changed, 411 insertions(+), 95 deletions(-) diff --git a/iniFile/iniFile.cpp b/iniFile/iniFile.cpp index 530c05178..76f71284f 100644 --- a/iniFile/iniFile.cpp +++ b/iniFile/iniFile.cpp @@ -52,68 +52,97 @@ cIniFile::cIniFile( const string iniPath) bool cIniFile::ReadFile() { - // Normally you would use ifstream, but the SGI CC compiler has - // a few bugs with ifstream. So ... fstream used. - fstream f; - string line; - string keyname, valuename, value; - string::size_type pLeft, pRight; - - f.open( (FILE_IO_PREFIX + path).c_str(), ios::in); - if ( f.fail()) - return false; + // Normally you would use ifstream, but the SGI CC compiler has + // a few bugs with ifstream. So ... fstream used. + fstream f; + string line; + string keyname, valuename, value; + string::size_type pLeft, pRight; + + f.open( (FILE_IO_PREFIX + path).c_str(), ios::in); + if ( f.fail()) + return false; + + while (getline( f, line)) + { + // To be compatible with Win32, check for existence of '\r'. + // Win32 files have the '\r' and Unix files don't at the end of a line. + // Note that the '\r' will be written to INI files from + // Unix so that the created INI file can be read under Win32 + // without change. + unsigned int lineLength = line.length(); + if (lineLength == 0) + { + continue; + } + if ( line[lineLength - 1] == '\r') + { + line = line.substr( 0, lineLength - 1); + } + + if (line.length() == 0) + { + continue; + } + + // Check that the user hasn't opened a binary file by checking the first + // character of each line! + if ( !isprint( line[0])) + { + printf( "Failing on char %d\n", line[0]); + f.close(); + return false; + } + if (( pLeft = line.find_first_of(";#[=")) == string::npos) + { + continue; + } + + switch ( line[pLeft]) + { + case '[': + { + if ( + ((pRight = line.find_last_of("]")) != string::npos) && + (pRight > pLeft) + ) + { + keyname = line.substr( pLeft + 1, pRight - pLeft - 1); + AddKeyName( keyname); + } + break; + } + + case '=': + { + valuename = line.substr( 0, pLeft); + value = line.substr( pLeft + 1); + SetValue( keyname, valuename, value); + break; + } + + case ';': + case '#': + { + if (names.size() == 0) + { + HeaderComment( line.substr( pLeft + 1)); + } + else + { + KeyComment( keyname, line.substr( pLeft + 1)); + } + break; + } + } // switch (line[pLeft]) + } // while (getline()) - while( getline( f, line)) { - // To be compatible with Win32, check for existence of '\r'. - // Win32 files have the '\r' and Unix files don't at the end of a line. - // Note that the '\r' will be written to INI files from - // Unix so that the created INI file can be read under Win32 - // without change. - unsigned int lineLength = line.length(); - if(lineLength == 0) continue; - if ( line[lineLength - 1] == '\r') - line = line.substr( 0, lineLength - 1); - - if ( line.length()) { - // Check that the user hasn't opened a binary file by checking the first - // character of each line! - if ( !isprint( line[0])) { - printf( "Failing on char %d\n", line[0]); f.close(); - return false; - } - if (( pLeft = line.find_first_of(";#[=")) != string::npos) { - switch ( line[pLeft]) { - case '[': - if ((pRight = line.find_last_of("]")) != string::npos && - pRight > pLeft) { - keyname = line.substr( pLeft + 1, pRight - pLeft - 1); - AddKeyName( keyname); - } - break; - - case '=': - valuename = line.substr( 0, pLeft); - value = line.substr( pLeft + 1); - SetValue( keyname, valuename, value); - break; - - case ';': - case '#': - if ( !names.size()) - HeaderComment( line.substr( pLeft + 1)); - else - KeyComment( keyname, line.substr( pLeft + 1)); - break; + if (names.size() > 0) + { + return true; } - } - } - } - - f.close(); - if ( names.size()) - return true; - return false; + return false; } diff --git a/source/Bindings.cpp b/source/Bindings.cpp index c77abd5da..de07e1207 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 09/02/12 15:53:59. +** Generated automatically by tolua++-1.0.92 on 09/08/12 18:04:37. */ #ifndef __cplusplus @@ -2597,6 +2597,64 @@ static int tolua_AllToLua_StringToItem00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* function: ItemToString */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_ItemToString00 +static int tolua_AllToLua_ItemToString00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + (tolua_isvaluenil(tolua_S,1,&tolua_err) || !tolua_isusertype(tolua_S,1,"const cItem",0,&tolua_err)) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cItem* a_Item = ((const cItem*) tolua_tousertype(tolua_S,1,0)); + { + AString tolua_ret = (AString) ItemToString(*a_Item); + tolua_pushcppstring(tolua_S,(const char*)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'ItemToString'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* function: ItemTypeToString */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_ItemTypeToString00 +static int tolua_AllToLua_ItemTypeToString00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isnumber(tolua_S,1,0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + short a_ItemType = ((short) tolua_tonumber(tolua_S,1,0)); + { + AString tolua_ret = (AString) ItemTypeToString(a_ItemType); + tolua_pushcppstring(tolua_S,(const char*)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'ItemTypeToString'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* get function: g_BlockLightValue */ #ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockLightValue static int tolua_get_AllToLua_g_BlockLightValue(lua_State* tolua_S) @@ -8422,6 +8480,43 @@ static int tolua_AllToLua_cPlugin_OnWeatherChanged00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: OnHandshake of class cPlugin */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlugin_OnHandshake00 +static int tolua_AllToLua_cPlugin_OnHandshake00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cPlugin",0,&tolua_err) || + !tolua_isusertype(tolua_S,2,"cClientHandle",0,&tolua_err) || + !tolua_iscppstring(tolua_S,3,0,&tolua_err) || + !tolua_isnoobj(tolua_S,4,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cPlugin* self = (cPlugin*) tolua_tousertype(tolua_S,1,0); + cClientHandle* a_Client = ((cClientHandle*) tolua_tousertype(tolua_S,2,0)); + const AString a_Username = ((const AString) tolua_tocppstring(tolua_S,3,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'OnHandshake'", NULL); +#endif + { + bool tolua_ret = (bool) self->OnHandshake(a_Client,a_Username); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + tolua_pushcppstring(tolua_S,(const char*)a_Username); + } + } + return 2; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'OnHandshake'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: GetName of class cPlugin */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cPlugin_GetName00 static int tolua_AllToLua_cPlugin_GetName00(lua_State* tolua_S) @@ -8973,6 +9068,18 @@ public: } else { return ( bool ) cPlugin:: OnWeatherChanged(a_World); }; + }; + bool OnHandshake( cClientHandle* a_Client, const AString& a_Username) { + if (push_method("OnHandshake", tolua_AllToLua_cPlugin_OnHandshake00)) { + tolua_pushusertype(lua_state, (void*)a_Client, "cClientHandle"); + tolua_pushcppstring(lua_state, (const char*)a_Username); + ToluaBase::dbcall(lua_state, 3, 1); + bool tolua_ret = ( bool )tolua_toboolean(lua_state, -1, 0); + lua_pop(lua_state, 1); + return tolua_ret; + } else { + return ( bool ) cPlugin:: OnHandshake(a_Client,a_Username); + }; }; void SetName( const AString& a_Name) { if (push_method("SetName", tolua_AllToLua_cPlugin_SetName00)) { @@ -9048,6 +9155,9 @@ public: }; bool cPlugin__OnWeatherChanged( cWorld* a_World) { return ( bool )cPlugin::OnWeatherChanged(a_World); + }; + bool cPlugin__OnHandshake( cClientHandle* a_Client, const AString& a_Username) { + return ( bool )cPlugin::OnHandshake(a_Client,a_Username); }; void cPlugin__SetName( const AString& a_Name) { return ( void )cPlugin::SetName(a_Name); @@ -9939,6 +10049,43 @@ static int tolua_AllToLua_Lua__cPlugin_cPlugin__OnWeatherChanged00(lua_State* to } #endif //#ifndef TOLUA_DISABLE +/* method: cPlugin__OnHandshake of class Lua__cPlugin */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_Lua__cPlugin_cPlugin__OnHandshake00 +static int tolua_AllToLua_Lua__cPlugin_cPlugin__OnHandshake00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"Lua__cPlugin",0,&tolua_err) || + !tolua_isusertype(tolua_S,2,"cClientHandle",0,&tolua_err) || + !tolua_iscppstring(tolua_S,3,0,&tolua_err) || + !tolua_isnoobj(tolua_S,4,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + Lua__cPlugin* self = (Lua__cPlugin*) tolua_tousertype(tolua_S,1,0); + cClientHandle* a_Client = ((cClientHandle*) tolua_tousertype(tolua_S,2,0)); + const AString a_Username = ((const AString) tolua_tocppstring(tolua_S,3,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'cPlugin__OnHandshake'", NULL); +#endif + { + bool tolua_ret = (bool) self->cPlugin__OnHandshake(a_Client,a_Username); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + tolua_pushcppstring(tolua_S,(const char*)a_Username); + } + } + return 2; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'cPlugin__OnHandshake'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: cPlugin__SetName of class Lua__cPlugin */ #ifndef TOLUA_DISABLE_tolua_AllToLua_Lua__cPlugin_cPlugin__SetName00 static int tolua_AllToLua_Lua__cPlugin_cPlugin__SetName00(lua_State* tolua_S) @@ -10501,6 +10648,18 @@ public: } else { return ( bool ) cPlugin_NewLua:: OnWeatherChanged(a_World); }; + }; + bool OnHandshake( cClientHandle* a_Client, const AString& a_Username) { + if (push_method("OnHandshake", tolua_AllToLua_cPlugin_OnHandshake00)) { + tolua_pushusertype(lua_state, (void*)a_Client, "cClientHandle"); + tolua_pushcppstring(lua_state, (const char*)a_Username); + ToluaBase::dbcall(lua_state, 3, 1); + bool tolua_ret = ( bool )tolua_toboolean(lua_state, -1, 0); + lua_pop(lua_state, 1); + return tolua_ret; + } else { + return ( bool ) cPlugin_NewLua:: OnHandshake(a_Client,a_Username); + }; }; void SetName( const AString& a_Name) { if (push_method("SetName", tolua_AllToLua_cPlugin_SetName00)) { @@ -10579,6 +10738,9 @@ public: }; bool cPlugin_NewLua__OnWeatherChanged( cWorld* a_World) { return ( bool )cPlugin_NewLua::OnWeatherChanged(a_World); + }; + bool cPlugin_NewLua__OnHandshake( cClientHandle* a_Client, const AString& a_Username) { + return ( bool )cPlugin_NewLua::OnHandshake(a_Client,a_Username); }; void cPlugin_NewLua__SetName( const AString& a_Name) { return ( void )cPlugin_NewLua::SetName(a_Name); @@ -21351,6 +21513,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"E_META_SPAWN_EGG_IRON_GOLEM",E_META_SPAWN_EGG_IRON_GOLEM); tolua_function(tolua_S,"BlockStringToType",tolua_AllToLua_BlockStringToType00); tolua_function(tolua_S,"StringToItem",tolua_AllToLua_StringToItem00); + tolua_function(tolua_S,"ItemToString",tolua_AllToLua_ItemToString00); + tolua_function(tolua_S,"ItemTypeToString",tolua_AllToLua_ItemTypeToString00); tolua_array(tolua_S,"g_BlockLightValue",tolua_get_AllToLua_g_BlockLightValue,tolua_set_AllToLua_g_BlockLightValue); tolua_array(tolua_S,"g_BlockSpreadLightFalloff",tolua_get_AllToLua_g_BlockSpreadLightFalloff,tolua_set_AllToLua_g_BlockSpreadLightFalloff); tolua_array(tolua_S,"g_BlockTransparent",tolua_get_AllToLua_g_BlockTransparent,tolua_set_AllToLua_g_BlockTransparent); @@ -21647,6 +21811,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"OnUpdatedSign",tolua_AllToLua_cPlugin_OnUpdatedSign00); tolua_function(tolua_S,"OnUpdatingSign",tolua_AllToLua_cPlugin_OnUpdatingSign00); tolua_function(tolua_S,"OnWeatherChanged",tolua_AllToLua_cPlugin_OnWeatherChanged00); + tolua_function(tolua_S,"OnHandshake",tolua_AllToLua_cPlugin_OnHandshake00); tolua_function(tolua_S,"GetName",tolua_AllToLua_cPlugin_GetName00); tolua_function(tolua_S,"SetName",tolua_AllToLua_cPlugin_SetName00); tolua_function(tolua_S,"GetVersion",tolua_AllToLua_cPlugin_GetVersion00); @@ -21688,6 +21853,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"cPlugin__OnUpdatedSign",tolua_AllToLua_Lua__cPlugin_cPlugin__OnUpdatedSign00); tolua_function(tolua_S,"cPlugin__OnUpdatingSign",tolua_AllToLua_Lua__cPlugin_cPlugin__OnUpdatingSign00); tolua_function(tolua_S,"cPlugin__OnWeatherChanged",tolua_AllToLua_Lua__cPlugin_cPlugin__OnWeatherChanged00); + tolua_function(tolua_S,"cPlugin__OnHandshake",tolua_AllToLua_Lua__cPlugin_cPlugin__OnHandshake00); tolua_function(tolua_S,"cPlugin__SetName",tolua_AllToLua_Lua__cPlugin_cPlugin__SetName00); tolua_function(tolua_S,"new",tolua_AllToLua_Lua__cPlugin_new00); tolua_function(tolua_S,"new_local",tolua_AllToLua_Lua__cPlugin_new00_local); diff --git a/source/Bindings.h b/source/Bindings.h index b6d879e29..fa5d54c5c 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 09/02/12 15:53:59. +** Generated automatically by tolua++-1.0.92 on 09/08/12 18:04:38. */ /* Exported function */ diff --git a/source/BlockID.cpp b/source/BlockID.cpp index 7a4b28b14..a326d25d6 100644 --- a/source/BlockID.cpp +++ b/source/BlockID.cpp @@ -26,24 +26,128 @@ bool g_BlockRequiresSpecialTool[256]; class cBlockIDMap { + typedef std::map > ItemMap; + public: - cBlockIDMap(void) : m_Ini("items.ini") + cBlockIDMap(void) { - m_Ini.ReadFile(); + cIniFile Ini("items.ini"); + if (!Ini.ReadFile()) + { + return; + } + long KeyID = Ini.FindKey("Items"); + if (KeyID == cIniFile::noID) + { + return; + } + unsigned NumValues = Ini.GetNumValues(KeyID); + for (unsigned i = 0; i < NumValues; i++) + { + AString Name = Ini.ValueName(KeyID, i); + if (Name.empty()) + { + continue; + } + AString Value = Ini.GetValue(KeyID, i); + AddToMap(Name, Value); + } // for i - Ini.Values[] } + int Resolve(const AString & a_ItemName) { - return m_Ini.GetValueI("Items", a_ItemName, -1); + ItemMap::iterator itr = m_Map.find(a_ItemName); + if (itr == m_Map.end()) + { + return -1; + } + return itr->second.first; + } + + + bool ResolveItem(const AString & a_ItemName, cItem & a_Item) + { + ItemMap::iterator itr = m_Map.find(a_ItemName); + if (itr != m_Map.end()) + { + a_Item.m_ItemType = itr->second.first; + a_Item.m_ItemDamage = itr->second.second; + return true; + } + + // Not a resolvable string, try pure numbers: "45:6", "45^6" etc. + AStringVector Split = StringSplit(a_ItemName, ":"); + if (Split.size() == 1) + { + Split = StringSplit(a_ItemName, "^"); + } + if (Split.empty()) + { + return false; + } + a_Item.m_ItemType = (short)atoi(Split[0].c_str()); + if ((a_Item.m_ItemType == 0) && (Split[0] != "0")) + { + // Parsing the number failed + return false; + } + if (Split.size() < 2) + { + return true; + } + a_Item.m_ItemDamage = atoi(Split[1].c_str()); + if ((a_Item.m_ItemDamage == 0) && (Split[1] != "0")) + { + // Parsing the number failed + return false; + } + + return true; } - AString ResolveString(const AString & a_ItemName) + + AString Desolve(short a_ItemType, short a_ItemDamage) { - return m_Ini.GetValue("Items", a_ItemName, ""); + for (ItemMap::iterator itr = m_Map.begin(), end = m_Map.end(); itr != end; ++itr) + { + if ((itr->second.first == a_ItemType) && (itr->second.second == a_ItemDamage)) + { + return itr->first; + } + } // for itr - m_Map[] + AString res; + if (a_ItemDamage == -1) + { + Printf(res, "%d", a_ItemType); + } + else + { + Printf(res, "%d:%d", a_ItemType, a_ItemDamage); + } + return res; } + protected: - cIniFile m_Ini; + ItemMap m_Map; + + + void AddToMap(const AString & a_Name, const AString & a_Value) + { + AStringVector Split = StringSplit(a_Value, ":"); + if (Split.size() == 1) + { + Split = StringSplit(a_Value, "^"); + } + if (Split.empty()) + { + return; + } + short ItemType = (short)atoi(Split[0].c_str()); + short ItemDamage = (Split.size() > 1) ? (short)atoi(Split[1].c_str()) : -1; + m_Map[a_Name] = std::make_pair(ItemType, ItemDamage); + } } ; @@ -56,6 +160,25 @@ static cBlockIDMap gsBlockIDMap; +/* +// Quick self-test: +class Tester +{ +public: + Tester(void) + { + cItem Item; + gsBlockIDMap.ResolveItem("charcoal", Item); + AString Charcoal = gsBlockIDMap.Desolve(Item.m_ItemType, Item.m_ItemDamage); + ASSERT(Charcoal == "charcoal"); + } +} test; +//*/ + + + + + BLOCKTYPE BlockStringToType(const AString & a_BlockTypeString) { int res = atoi(a_BlockTypeString.c_str()); @@ -73,33 +196,25 @@ BLOCKTYPE BlockStringToType(const AString & a_BlockTypeString) bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item) { - AString Resolved = TrimString(gsBlockIDMap.ResolveString(TrimString(a_ItemTypeString))); - AString txt = (!Resolved.empty()) ? Resolved : a_ItemTypeString; - AStringVector Split = StringSplit(txt, ":"); - if (Split.size() == 1) - { - Split = StringSplit(txt, "^"); - } - if (Split.empty()) - { - return false; - } - a_Item.m_ItemID = (ENUM_ITEM_ID)atoi(Split[0].c_str()); - if ((a_Item.m_ItemID == 0) && (Split[0] != "0")) - { - // Parsing the number failed - return false; - } - if (Split.size() > 1) - { - a_Item.m_ItemHealth = atoi(Split[1].c_str()); - if ((a_Item.m_ItemHealth == 0) && (Split[1] != "0")) - { - // Parsing the number failed - return false; - } - } - return true; + return gsBlockIDMap.ResolveItem(TrimString(a_ItemTypeString), a_Item); +} + + + + + +AString ItemToString(const cItem & a_Item) +{ + return gsBlockIDMap.Desolve(a_Item.m_ItemType, a_Item.m_ItemDamage); +} + + + + + +AString ItemTypeToString(short a_ItemType) +{ + return gsBlockIDMap.Desolve(a_ItemType, -1); } diff --git a/source/BlockID.h b/source/BlockID.h index a66e7f026..5833a6d1d 100644 --- a/source/BlockID.h +++ b/source/BlockID.h @@ -631,6 +631,12 @@ extern BLOCKTYPE BlockStringToType(const AString & a_BlockTypeString); // tolua /// Translates an itemtype string into an item. Takes either a number, number^number, number:number or an items.ini alias as input. Returns true if successful. extern bool StringToItem(const AString & a_ItemTypeString, cItem & a_Item); // tolua_export +/// Translates a full item into a string. If the ItemType is not recognized, the ItemType number is output into the string. +extern AString ItemToString(const cItem & a_Item); // tolua_export + +/// Translates itemtype into a string. If the type is not recognized, the itemtype number is output into the string. +extern AString ItemTypeToString(short a_ItemType); // tolua_export + /// Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns -1 on failure. extern EMCSBiome StringToBiome(const AString & a_BiomeString); @@ -645,7 +651,7 @@ extern bool g_BlockTransparent[256]; extern bool g_BlockOneHitDig[256]; extern bool g_BlockPistonBreakable[256]; extern bool g_BlockIsSnowable[256]; -extern bool g_BlockRequiresSpecialTool[256]; +extern bool g_BlockRequiresSpecialTool[256]; -- cgit v1.2.3