diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..327d8cc7 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,32 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": ["${default}"], + "defines": [], + "macFrameworkPath": [ + "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks" + ], + "compilerPath": "/opt/local/bin/clang", + "compilerArgs": ["-g"], + "cStandard": "gnu11", + "cppStandard": "gnu++14", + "browse": { + "path": [ + "/opt/local/include", + "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include" + ] + } + }, + { + "name": "Linux", + "includePath": ["${default}"], + "defines": ["XDG_ROOT"], + "compilerPath": "/usr/bin/gcc", + "compilerArgs": ["-ggdb"], + "cStandard": "gnu11", + "cppStandard": "gnu++14" + } + ], + "version": 4 +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..82ce041f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,89 @@ +{ + "configurations": [ + { + "MIMode": "gdb", + "args": [], + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "name": "(gdb) Launch (Linux Debug)", + "preLaunchTask": "Compile (Debug Linux x64)", + "program": "${workspaceFolder}/bin/linux-amd64-librw_gl3_glfw-oal/Debug/re3", + "request": "launch", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "ignoreFailures": true, + "text": "-enable-pretty-printing" + } + ], + "stopAtEntry": false, + "targetArchitecture": "x64", + "type": "cppdbg" + }, + { + "MIMode": "gdb", + "args": [], + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "name": "(gdb) Launch (Linux Release)", + "preLaunchTask": "Compile (Release Linux x64)", + "program": "${workspaceFolder}/bin/linux-amd64-librw_gl3_glfw-oal/Release/re3", + "request": "launch", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "ignoreFailures": true, + "text": "-enable-pretty-printing" + } + ], + "stopAtEntry": false, + "targetArchitecture": "x64", + "type": "cppdbg" + }, + { + "MIMode": "lldb", + "args": [], + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "name": "(lldb) Launch (macOS Debug)", + "preLaunchTask": "Compile (Debug macOS x64)", + "program": "${workspaceFolder}/bin/macosx-amd64-librw_gl3_glfw-oal/Debug/re3.app", + "request": "launch", + "setupCommands": [ + { + "description": "Enable pretty-printing for lldb", + "ignoreFailures": true, + "text": "-enable-pretty-printing" + } + ], + "stopAtEntry": false, + "targetArchitecture": "x64", + "type": "cppdbg" + }, + { + "MIMode": "lldb", + "args": [], + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "name": "(lldb) Launch (macOS Release)", + "preLaunchTask": "Compile (Release macOS x64)", + "program": "${workspaceFolder}/bin/macosx-amd64-librw_gl3_glfw-oal/Release/re3.app", + "request": "launch", + "setupCommands": [ + { + "description": "Enable pretty-printing for lldb", + "ignoreFailures": true, + "text": "-enable-pretty-printing" + } + ], + "stopAtEntry": false, + "targetArchitecture": "x64", + "type": "cppdbg" + } + ], + "version": "0.2.0" +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..10cb5627 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,30 @@ +{ + "C_Cpp.default.cStandard": "gnu11", + "C_Cpp.default.cppStandard": "gnu++14", + "C_Cpp.default.includePath": [ + "src/animation", + "src/audio", + "src/control", + "src/core", + "src/entities", + "src/extras", + "src/fakerw", + "src/math", + "src/modelinfo", + "src/objects", + "src/peds", + "src/render", + "src/rw", + "src/save", + "src/skel", + "src/text", + "src/vehicles", + "src/weapons", + "vendor/librw" + ], + "C_Cpp.vcFormat.indent.gotoLabels": "leftmostColumn", + "C_Cpp.vcFormat.space.pointerReferenceAlignment": "right", + "cSpell.enabled": false, + "files.trimFinalNewlines": false, + "files.trimTrailingWhitespace": false +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..0f610d5f --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,95 @@ +{ + "tasks": [ + { + "args": ["--with-librw", "gmake2"], + "command": "./premake5Linux", + "label": "Premake (Linux)", + "problemMatcher": "$gcc", + "type": "shell" + }, + { + "args": ["--with-librw", "gmake2"], + "command": "premake5", + "label": "Premake (macOS)", + "problemMatcher": "$gcc", + "type": "shell" + }, + { + "args": [ + "-j5", + "config=debug_linux-amd64-librw_gl3_glfw-oal", + "verbose=1" + ], + "command": "make", + "dependsOn": "Premake (Linux)", + "group": { + "isDefault": true, + "kind": "build" + }, + "label": "Compile (Debug Linux x64)", + "options": { + "cwd": "${workspaceFolder}/build" + }, + "problemMatcher": "$gcc", + "type": "shell" + }, + { + "args": [ + "-j5", + "config=release_linux-amd64-librw_gl3_glfw-oal", + "verbose=1" + ], + "command": "make", + "dependsOn": "Premake (Linux)", + "group": { + "isDefault": true, + "kind": "build" + }, + "label": "Compile (Release Linux x64)", + "options": { + "cwd": "${workspaceFolder}/build" + }, + "problemMatcher": "$gcc", + "type": "shell" + }, + { + "args": [ + "-j5", + "config=debug_macosx-amd64-librw_gl3_glfw-oal", + "verbose=1" + ], + "command": "make", + "dependsOn": "Premake (macOS)", + "group": { + "isDefault": true, + "kind": "build" + }, + "label": "Compile (Debug macOS x64)", + "options": { + "cwd": "${workspaceFolder}/build" + }, + "problemMatcher": "$gcc", + "type": "shell" + }, + { + "args": [ + "-j5", + "config=release_macosx-amd64-librw_gl3_glfw-oal", + "verbose=1" + ], + "command": "make", + "dependsOn": "Premake (macOS)", + "group": { + "isDefault": true, + "kind": "build" + }, + "label": "Compile (Release macOS x64)", + "options": { + "cwd": "${workspaceFolder}/build" + }, + "problemMatcher": "$gcc", + "type": "shell" + } + ], + "version": "2.0.0" +} diff --git a/CODING_STYLE.md b/CODING_STYLE.md new file mode 100644 index 00000000..b8be02bc --- /dev/null +++ b/CODING_STYLE.md @@ -0,0 +1,107 @@ +# Coding style + +I started writing in [Plan 9 style](http://man.cat-v.org/plan_9/6/style), +but realize that this is not the most popular style, so I'm willing to compromise. +Try not to deviate too much so the code will look similar across the whole project. + +To give examples, these two styles (or anything in between) are fine: + +``` +type +functionname(args) +{ + if(a == b){ + s1; + s2; + }else{ + s3; + s4; + } + if(x != y) + s5; +} + +type functionname(args) +{ + if (a == b) { + s1; + s2; + } else { + s3; + s4; + } + if (x != y) + s5; +} +``` + +This one (or anything more extreme) is heavily discouraged: + +``` +type functionname ( args ) +{ + if ( a == b ) + { + s1; + s2; + } + else + { + s3; + s4; + } + if ( x != y ) + { + s5; + } +} +``` + +i.e. + +* Put the brace on the same line as control statements + +* Put the brace on the next line after function definitions and structs/classes + +* Put an `else` on the same line with the braces + +* Don't put braces around single statements + +* Put the function return type on a separate line + +* Indent with TABS + +As for the less cosmetic choices, here are some guidelines how the code should look: + +* Don't use magic numbers where the original source code would have had an enum or similar. +Even if you don't know the exact meaning it's better to call something `FOOBAR_TYPE_4` than just `4`, +since `4` will be used in other places and you can't easily see where else the enum value is used. + +* Don't just copy paste code from IDA, make it look nice + +* Use the right types. In particular: + + * don't use types like `__int16`, we have `int16` for that + + * don't use `unsigned`, we have typedefs for that + + * don't use `char` for anything but actual characters, use `int8`, `uint8` or `bool` + + * don't even think about using win32 types (`BYTE`, `WORD`, &c.) unless you're writing win32 specific code + + * declare pointers like `int *ptr;`, not `int* ptr;` + +* As for variable names, the original gta source code was not written in a uniform style, +but here are some observations: + + * many variables employ a form of hungarian notation, i.e.: + + * `m_` may be used for class member variables (mostly those that are considered private) + + * `ms_` for (mostly private) static members + + * `f` is a float, `i` or `n` is an integer, `b` is a boolean, `a` is an array + + * do *not* use `dw` for `DWORD` or so, we're not programming win32 + +* Generally, try to make the code look as if R* could have written it diff --git a/README.md b/README.md index 9cb48c25..1bfe74d2 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,7 @@ such that we have a working game at all times. ## Preparing the environment for building -- Clone the repo. -- Run `git submodule init` and `git submodule update`. +- Clone the repo using the argument `--recursive`. - Point GTA_III_RE_DIR environment variable to GTA3 root folder. - Run premake - On Windows: one of the `premake-vsXXXX.cmd` variants on root folder @@ -36,6 +35,7 @@ such that we have a working game at all times. > :information_source: **Did you notice librw?** re3 uses completely homebrew RenderWare-replacement rendering engine; [librw](https://github.com/aap/librw/). librw comes as submodule of re3, but you also can use LIBRW enviorenment variable to specify path to your own librw. ## Contributing +Please read the [Coding Style](https://github.com/GTAmodding/re3/blob/master/CODING_STYLE.md) Document ### Unreversed / incomplete classes (at least the ones we know) The following classes have only unused or practically unused code left: @@ -44,110 +44,3 @@ CCullZone - only mobile stuff CCullZones - only mobile stuff ``` -### Coding style - -I started writing in [Plan 9 style](http://man.cat-v.org/plan_9/6/style), -but realize that this is not the most popular style, so I'm willing to compromise. -Try not to deviate too much so the code will look similar across the whole project. - -To give examples, these two styles (or anything in between) are fine: - -``` -type -functionname(args) -{ - if(a == b){ - s1; - s2; - }else{ - s3; - s4; - } - if(x != y) - s5; -} - -type functionname(args) -{ - if (a == b) { - s1; - s2; - } else { - s3; - s4; - } - if (x != y) - s5; -} -``` - -This one (or anything more extreme) is heavily discouraged: - -``` -type functionname ( args ) -{ - if ( a == b ) - { - s1; - s2; - } - else - { - s3; - s4; - } - if ( x != y ) - { - s5; - } -} -``` - -i.e. - -* Put the brace on the same line as control statements - -* Put the brace on the next line after function definitions and structs/classes - -* Put an `else` on the same line with the braces - -* Don't put braces around single statements - -* Put the function return type on a separate line - -* Indent with TABS - -As for the less cosmetic choices, here are some guidelines how the code should look: - -* Don't use magic numbers where the original source code would have had an enum or similar. -Even if you don't know the exact meaning it's better to call something `FOOBAR_TYPE_4` than just `4`, -since `4` will be used in other places and you can't easily see where else the enum value is used. - -* Don't just copy paste code from IDA, make it look nice - -* Use the right types. In particular: - - * don't use types like `__int16`, we have `int16` for that - - * don't use `unsigned`, we have typedefs for that - - * don't use `char` for anything but actual characters, use `int8`, `uint8` or `bool` - - * don't even think about using win32 types (`BYTE`, `WORD`, &c.) unless you're writing win32 specific code - - * declare pointers like `int *ptr;`, not `int* ptr;` - -* As for variable names, the original gta source code was not written in a uniform style, -but here are some observations: - - * many variables employ a form of hungarian notation, i.e.: - - * `m_` may be used for class member variables (mostly those that are considered private) - - * `ms_` for (mostly private) static members - - * `f` is a float, `i` or `n` is an integer, `b` is a boolean, `a` is an array - - * do *not* use `dw` for `DWORD` or so, we're not programming win32 - -* Generally, try to make the code look as if R* could have written it diff --git a/premake5.lua b/premake5.lua index fb408fe0..334c9c53 100644 --- a/premake5.lua +++ b/premake5.lua @@ -185,7 +185,7 @@ project "librw" includedirs {"/usr/local/include" } libdirs { "/opt/local/lib" } libdirs { "/usr/local/lib" } - + filter "platforms:*RW34*" flags { "ExcludeFromBuild" } filter {} diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp index 74c4f006..93098d6d 100644 --- a/src/control/CarCtrl.cpp +++ b/src/control/CarCtrl.cpp @@ -3075,7 +3075,7 @@ void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle* pVehicle) void CCarCtrl::JoinCarWithRoadSystem(CVehicle* pVehicle) { pVehicle->AutoPilot.m_nPrevRouteNode = pVehicle->AutoPilot.m_nCurrentRouteNode = pVehicle->AutoPilot.m_nNextRouteNode = 0; - pVehicle->AutoPilot.m_nCurrentRouteNode = pVehicle->AutoPilot.m_nPreviousPathNodeInfo = pVehicle->AutoPilot.m_nNextPathNodeInfo = 0; + pVehicle->AutoPilot.m_nCurrentPathNodeInfo = pVehicle->AutoPilot.m_nPreviousPathNodeInfo = pVehicle->AutoPilot.m_nNextPathNodeInfo = 0; int nodeId = ThePaths.FindNodeClosestToCoorsFavourDirection(pVehicle->GetPosition(), 0, pVehicle->GetForward().x, pVehicle->GetForward().y); CPathNode* pNode = &ThePaths.m_pathNodes[nodeId]; int prevNodeId = -1; diff --git a/src/control/Darkel.cpp b/src/control/Darkel.cpp index 75d27e26..1191e8ad 100644 --- a/src/control/Darkel.cpp +++ b/src/control/Darkel.cpp @@ -14,6 +14,9 @@ #include "Text.h" #include "Vehicle.h" #include "GameLogic.h" +#ifdef FIX_BUGS +#include "Replay.h" +#endif #define FRENZY_ANY_PED -1 #define FRENZY_ANY_CAR -2 @@ -62,6 +65,10 @@ CDarkel::CalcFade(uint32 time, uint32 start, uint32 end) void CDarkel::DrawMessages() { +#ifdef FIX_BUGS + if (CReplay::IsPlayingBack()) + return; +#endif switch (Status) { case KILLFRENZY_ONGOING: { @@ -167,6 +174,10 @@ CDarkel::ReadStatus() void CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle) { +#ifdef FIX_BUGS + if (CReplay::IsPlayingBack()) + return; +#endif if (FrenzyOnGoing()) { int32 model = vehicle->GetModelIndex(); if (ModelToKill == FRENZY_ANY_CAR || ModelToKill == model || ModelToKill2 == model || ModelToKill3 == model || ModelToKill4 == model) { @@ -181,6 +192,10 @@ CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle) void CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapon, bool headshot) { +#ifdef FIX_BUGS + if (CReplay::IsPlayingBack()) + return; +#endif if (FrenzyOnGoing() && (weapon == WeaponType || weapon == WEAPONTYPE_EXPLOSION || weapon == WEAPONTYPE_UZI_DRIVEBY && WeaponType == WEAPONTYPE_UZI @@ -206,6 +221,10 @@ CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapon, bool headshot) void CDarkel::RegisterKillNotByPlayer(CPed* victim, eWeaponType weapontype) { +#ifdef FIX_BUGS + if (CReplay::IsPlayingBack()) + return; +#endif CStats::PeopleKilledByOthers++; } @@ -299,6 +318,11 @@ CDarkel::StartFrenzy(eWeaponType weaponType, int32 time, uint16 kill, int32 mode void CDarkel::Update() { +#ifdef FIX_BUGS + if (CReplay::IsPlayingBack()) + return; +#endif + if (Status != KILLFRENZY_ONGOING) return; diff --git a/src/core/config.h b/src/core/config.h index 475a63f8..f85232ed 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -248,6 +248,9 @@ enum Config { #if !defined(RW_GL3) && defined(_WIN32) #define XINPUT #endif +#if !defined(_WIN32) && !defined(__SWITCH__) +#define DONT_TRUST_RECOGNIZED_JOYSTICKS // Then we'll only rely on GLFW gamepad DB, and expect user to enter Controller->Detect joysticks if his joystick isn't on that list. +#endif #define DETECT_PAD_INPUT_SWITCH // Adds automatic switch of pad related stuff between controller and kb/m #define KANGAROO_CHEAT #define RESTORE_ALLCARSHELI_CHEAT @@ -323,4 +326,4 @@ enum Config { #undef NO_ISLAND_LOADING #define PC_PARTICLE #define VC_PED_PORTS // To not process collisions always. But should be tested if that's really beneficial -#endif \ No newline at end of file +#endif diff --git a/src/extras/ini_parser.hpp b/src/extras/ini_parser.hpp new file mode 100644 index 00000000..99acf1ee --- /dev/null +++ b/src/extras/ini_parser.hpp @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2013-2015 Denilson das Mercês Amorim + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + */ +#ifndef LINB_INI_PARSER_HPP +#define LINB_INI_PARSER_HPP + +/* + * STL-like INI Container + */ + +#include // for std::string +#include // for std::map +#include // for std::FILE +#include // for std::find_if +#include // for std::function + +namespace linb +{ + template< + class CharT = char, /* Not compatible with other type here, since we're using C streams */ + class StringType = std::basic_string, + class KeyContainer = std::map, + class SectionContainer = std::map + > class basic_ini + { + public: + typedef CharT char_type; + typedef StringType string_type; + typedef KeyContainer key_container; + typedef SectionContainer section_container; + + // Typedef container values types + typedef typename section_container::value_type value_type; + typedef typename section_container::key_type key_type; + typedef typename section_container::mapped_type mapped_type; + + // Typedef common types + typedef typename section_container::size_type size_type; + typedef typename section_container::difference_type difference_type; + + // Typedef iterators + typedef typename section_container::iterator iterator; + typedef typename section_container::const_iterator const_iterator; + typedef typename section_container::reverse_iterator reverse_iterator; + typedef typename section_container::const_reverse_iterator const_reverse_iterator; + + // typedef References and pointers + typedef typename section_container::reference reference; + typedef typename section_container::const_reference const_reference; + typedef typename section_container::pointer pointer; + typedef typename section_container::const_pointer const_pointer; + + private: + section_container data; + + public: + + basic_ini() + { } + + basic_ini(const char_type* filename) + { this->read_file(filename); } + + /* Iterator methods */ + iterator begin() + { return data.begin(); } + const_iterator begin() const + { return data.begin(); } + iterator end() + { return data.end(); } + const_iterator end() const + { return data.end(); } + const_iterator cbegin() const + { return data.cbegin(); } + const_iterator cend() const + { return data.cend(); } + + /* Reverse iterator methods */ + reverse_iterator rbegin() + { return data.rbegin(); } + const_reverse_iterator rbegin() const + { return data.rbegin(); } + reverse_iterator rend() + { return data.rend(); } + const_reverse_iterator rend() const + { return data.rend(); } + const_reverse_iterator crbegin() const + { return data.crbegin(); } + const_reverse_iterator crend() const + { return data.crend(); } + + /* Acessing index methods */ + mapped_type& operator[](const string_type& sect) + { return data[sect]; } + mapped_type& operator[](string_type&& sect) + { return data[std::forward(sect)]; } + mapped_type& at( const string_type& sect) + { return data.at(sect); } + const mapped_type& at(const string_type& sect) const + { return data.at(sect); } + + /* Capacity information */ + bool empty() const + { return data.empty(); } + size_type size() const + { return data.size(); } + size_type max_size() const + { return data.max_size(); } + + /* Modifiers */ + void clear() + { return data.clear(); } + + /* Lookup */ + size_type count(const string_type& sect) + { return data.count(sect); } + iterator find(const string_type& sect) + { return data.find(sect); } + + /* Gets a value from the specified section & key, default_value is returned if the sect & key doesn't exist */ + string_type get(const string_type& sect, const key_type& key, const string_type& default_value) + { + auto it = this->find(sect); + if(it != this->end()) + { + auto itv = it->second.find(key); + if(itv != it->second.end()) + return itv->second; + } + return default_value; + } + + /* Sets the value of a value in the ini */ + void set(const string_type& sect, const key_type& key, const string_type& value) + { + (*this)[sect][key] = value; // no emplace since overwrite! + } + + /* Too lazy to continue this container... If you need more methods, just add it */ + + +#if 1 + bool read_file(const char_type* filename) + { + /* Using C stream in a STL-like container, funny? + */ + if(FILE* f = fopen(filename, "r")) + { + key_container* keys = nullptr; + char_type buf[2048]; + string_type line; + string_type key; + string_type value; + string_type null_string; + size_type pos; + + // Trims an string + auto trim = [](string_type& s, bool trimLeft, bool trimRight) -> string_type& + { + if(s.size()) + { + // Ignore UTF-8 BOM + while(s.size() >= 3 && s[0] == (char)(0xEF) && s[1] == (char)(0xBB) && s[2] == (char)(0xBF)) + s.erase(s.begin(), s.begin() + 3); + + if(trimLeft) + s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::function(::isspace)))); + if(trimRight) + s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::function(::isspace))).base(), s.end()); + } + return s; + }; + + // Start parsing + while(fgets(buf, sizeof(buf), f)) + { + // What a thing, reading into a char buffer and then putting in the string... + line = buf; + + // Find comment and remove anything after it from the line + if((pos = line.find_first_of(';')) != line.npos) + line.erase(pos); + + // Trim the string, and if it gets empty, skip this line + if(trim(line, true, true).empty()) + continue; + + // Find section name + if(line.front() == '[' && line.back() == ']') + { + pos = line.length() - 1; //line.find_first_of(']'); + if(pos != line.npos) + { + trim(key.assign(line, 1, pos-1), true, true); + keys = &data[std::move(key)]; // Create section + } + else + keys = nullptr; + } + else + { + // Find key and value positions + pos = line.find_first_of('='); + if(pos == line.npos) + { + // There's only the key + key = line; // No need for trim, line is already trimmed + value.clear(); + } + else + { + // There's the key and the value + trim(key.assign(line, 0, pos), false, true); // trim the right + trim(value.assign(line, pos + 1, line.npos), true, false); // trim the left + } + + // Put the key/value into the current keys object, or into the section "" if no section has been found + #if __cplusplus >= 201103L || _MSC_VER >= 1800 + (keys ? *keys : data[null_string]).emplace(std::move(key), std::move(value)); + #else + (keys ? *keys : data[null_string])[key] = value; + key.clear(); value.clear(); + #endif + } + } + + fclose(f); + return true; + } + return false; + } + + /* + * Dumps the content of this container into an ini file + */ + bool write_file(const char_type* filename) + { + if(FILE* f = fopen(filename, "w")) + { + bool first = true; + for(auto& sec : this->data) + { + fprintf(f, first? "[%s]\n" : "\n[%s]\n", sec.first.c_str()); + first = false; + for(auto& kv : sec.second) + { + if(kv.second.empty()) + fprintf(f, "%s\n", kv.first.c_str()); + else + fprintf(f, "%s = %s\n", kv.first.c_str(), kv.second.c_str()); + } + } + fclose(f); + return true; + } + return false; + } + + + /* + */ + bool load_file(const char_type* filename) + { + return read_file(filename); + } + + bool load_file(const StringType& filename) + { + return load_file(filename.c_str()); + } + + bool write_file(const StringType& filename) + { + return write_file(filename.c_str()); + } +#endif + + + + }; + + + /* Use default basic_ini + * + * Limitations: + * * Not unicode aware + * * Case sensitive + * * Sections must have unique keys + */ + typedef basic_ini<> ini; +} + +#endif + diff --git a/src/skel/crossplatform.cpp b/src/skel/crossplatform.cpp index 6188992d..452ad9fa 100644 --- a/src/skel/crossplatform.cpp +++ b/src/skel/crossplatform.cpp @@ -84,6 +84,16 @@ void FileTimeToSystemTime(time_t* writeTime, SYSTEMTIME* out) { } #endif +// Because wchar length differs between platforms. +wchar* +AllocUnicode(const char* src) +{ + wchar *dst = (wchar*)malloc(strlen(src)*2 + 2); + wchar *i = dst; + while((*i++ = (unsigned char)*src++) != '\0'); + return dst; +} + // Funcs/features from Windows that we need on other platforms #ifndef _WIN32 char *strupr(char *s) { diff --git a/src/skel/crossplatform.h b/src/skel/crossplatform.h index 69600385..1635781b 100644 --- a/src/skel/crossplatform.h +++ b/src/skel/crossplatform.h @@ -67,6 +67,10 @@ void CapturePad(RwInt32 padID); void joysChangeCB(int jid, int event); #endif +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS +extern char gSelectedJoystickName[128]; +#endif + enum eGameState { GS_START_UP = 0, diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index 0f520cad..08e5c021 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -41,7 +41,6 @@ #include "AnimViewer.h" #include "Font.h" - #define MAX_SUBSYSTEMS (16) @@ -92,6 +91,11 @@ long _dwOperatingSystemVersion; #include #include #endif + +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS +char gSelectedJoystickName[128] = ""; +#endif + /* ***************************************************************************** */ @@ -429,6 +433,10 @@ psInitialize(void) _dwOperatingSystemVersion = OS_WIN95; } } +#else + _dwOperatingSystemVersion = OS_WINXP; // To fool other classes +#endif + #ifndef PS2_MENU @@ -438,6 +446,8 @@ psInitialize(void) #endif + +#ifdef _WIN32 MEMORYSTATUS memstats; GlobalMemoryStatus(&memstats); @@ -445,17 +455,22 @@ psInitialize(void) debug("Physical memory size %u\n", memstats.dwTotalPhys); debug("Available physical memory %u\n", memstats.dwAvailPhys); +#elif defined (__APPLE__) + uint64_t size = 0; + uint64_t page_size = 0; + size_t uint64_len = sizeof(uint64_t); + size_t ull_len = sizeof(unsigned long long); + sysctl((int[]){CTL_HW, HW_PAGESIZE}, 2, &page_size, &ull_len, NULL, 0); + sysctl((int[]){CTL_HW, HW_MEMSIZE}, 2, &size, &uint64_len, NULL, 0); + vm_statistics_data_t vm_stat; + mach_msg_type_number_t count = HOST_VM_INFO_COUNT; + host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_stat, &count); + _dwMemAvailPhys = (uint64_t)(vm_stat.free_count * page_size); + debug("Physical memory size %llu\n", _dwMemAvailPhys); + debug("Available physical memory %llu\n", size); #else - -#ifndef PS2_MENU - -#ifdef GTA3_1_1_PATCH - FrontEndMenuManager.LoadSettings(); -#endif - -#endif #ifndef __APPLE__ - struct sysinfo systemInfo; + struct sysinfo systemInfo; sysinfo(&systemInfo); _dwMemAvailPhys = systemInfo.freeram; debug("Physical memory size %u\n", systemInfo.totalram); @@ -476,7 +491,8 @@ psInitialize(void) #endif _dwOperatingSystemVersion = OS_WINXP; // To fool other classes #endif - TheText.Unload(); + + TheText.Unload(); return TRUE; } @@ -843,35 +859,26 @@ void joysChangeCB(int jid, int event); bool IsThisJoystickBlacklisted(int i) { +#ifndef DONT_TRUST_RECOGNIZED_JOYSTICKS + return false; +#else if (glfwJoystickIsGamepad(i)) return false; const char* joyname = glfwGetJoystickName(i); - // this is just a keyboard and mouse - // Microsoft Microsoft® 2.4GHz Transceiver v8.0 Consumer Control - // Microsoft Microsoft® 2.4GHz Transceiver v8.0 System Control - if (strstr(joyname, "2.4GHz Transceiver")) - return true; - // COMPANY USB Device System Control - // COMPANY USB Device Consumer Control - if (strstr(joyname, "COMPANY USB")) - return true; - // i.e. Synaptics TM2438-005 - if (strstr(joyname, "Synaptics ")) - return true; - // i.e. ELAN Touchscreen - if (strstr(joyname, "ELAN ")) - return true; - // i.e. Primax Electronics, Ltd HP Wireless Keyboard Mouse Kit Consumer Control - if (strstr(joyname, "Keyboard")) - return true; + if (strncmp(joyname, gSelectedJoystickName, strlen(gSelectedJoystickName)) == 0) + return false; - return false; + return true; +#endif } void _InputInitialiseJoys() { + PSGLOBAL(joy1id) = -1; + PSGLOBAL(joy2id) = -1; + for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) { if (glfwJoystickPresent(i) && !IsThisJoystickBlacklisted(i)) { if (PSGLOBAL(joy1id) == -1) @@ -886,6 +893,9 @@ void _InputInitialiseJoys() if (PSGLOBAL(joy1id) != -1) { int count; glfwGetJoystickButtons(PSGLOBAL(joy1id), &count); +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS + strcpy(gSelectedJoystickName, glfwGetJoystickName(PSGLOBAL(joy1id))); +#endif ControlsManager.InitDefaultControlConfigJoyPad(count); } } @@ -2104,18 +2114,19 @@ void CapturePad(RwInt32 padID) void joysChangeCB(int jid, int event) { - if (event == GLFW_CONNECTED && !IsThisJoystickBlacklisted(jid)) - { - if (PSGLOBAL(joy1id) == -1) + if (event == GLFW_CONNECTED && !IsThisJoystickBlacklisted(jid)) { + if (PSGLOBAL(joy1id) == -1) { PSGLOBAL(joy1id) = jid; - else if (PSGLOBAL(joy2id) == -1) +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS + strcpy(gSelectedJoystickName, glfwGetJoystickName(jid)); +#endif + } else if (PSGLOBAL(joy2id) == -1) PSGLOBAL(joy2id) = jid; - } - else if (event == GLFW_DISCONNECTED) - { - if (PSGLOBAL(joy1id) == jid) + + } else if (event == GLFW_DISCONNECTED) { + if (PSGLOBAL(joy1id) == jid) { PSGLOBAL(joy1id) = -1; - else if (PSGLOBAL(joy2id) == jid) + } else if (PSGLOBAL(joy2id) == jid) PSGLOBAL(joy2id) = -1; } } diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index b98d5710..1d1037af 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -3414,4 +3414,4 @@ int strncasecmp(const char *str1, const char *str2, size_t len) return _strnicmp(str1, str2, len); } #endif -#endif \ No newline at end of file +#endif diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index 6e86dbe4..994f3c99 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -1303,7 +1303,7 @@ CVehicle::InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage } } #ifdef FIX_BUGS // removing dumb case when shooting police car in player's own garage gives wanted level - if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed() && !bHasBeenOwnedByPlayer) + if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed() && damagedBy != nil && !bHasBeenOwnedByPlayer) #else if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed()) #endif