diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ab85678..d007c6aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -303,29 +303,6 @@ if(NOT tspp_POPULATED) endif() -################################################################################ -# Fetch the latest "robin-hood-hashing" source code -################################################################################ -FetchContent_Declare( - robin_hood_hashing - GIT_REMOTE_UPDATE_STRATEGY REBASE - GIT_REPOSITORY https://github.com/martinus/robin-hood-hashing.git - GIT_TAG origin/master - GIT_SUBMODULES "" -) - -FetchContent_GetProperties(robin_hood_hashing) -if(NOT robin_hood_hashing_POPULATED) - message(STATUS "Fetching robin-hood-hashing...") - FetchContent_Populate(robin_hood_hashing) - message(STATUS " Source: ${robin_hood_hashing_SOURCE_DIR}") - message(STATUS " Build: ${robin_hood_hashing_BINARY_DIR}") - add_subdirectory(${robin_hood_hashing_SOURCE_DIR} ${robin_hood_hashing_BINARY_DIR}) -else() - message(STATUS "Found robin-hood-hashing.") -endif() - - ################################################################################ # Embed some git version information in the binary. ################################################################################ @@ -548,8 +525,6 @@ else() message(STATUS "Build: Unofficial") endif() -# Use the robin-hood-hashing library containers instead of the std C++ containers. -target_compile_definitions(${PROJECT_NAME} PUBLIC USE_ROBIN_HOOD=1) # # Add/Remove flags required for trying matching pre-compiled game code. @@ -643,10 +618,6 @@ target_link_libraries(${PROJECT_NAME} ${REQUIRED_LIBRARIES}) # Make build check state of git to check for uncommitted changes. add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_check_git) -# Link to the robin-hood-hashing library. -target_link_libraries(${PROJECT_NAME} robin_hood) -add_dependencies(${PROJECT_NAME} robin_hood) - ################################################################################ # Setup project IDE filters. diff --git a/src/extensions/abstract/abstractext.cpp b/src/extensions/abstract/abstractext.cpp new file mode 100644 index 00000000..8733a527 --- /dev/null +++ b/src/extensions/abstract/abstractext.cpp @@ -0,0 +1,257 @@ +/******************************************************************************* +/* O P E N S O U R C E -- V I N I F E R A ** +/******************************************************************************* + * + * @project Vinifera + * + * @file ABSTRACTEXT.CPP + * + * @author CCHyper + * + * @brief Base extension class for all game world objects. + * + * @license Vinifera is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 3 of the License, or (at your option) any later version. + * + * Vinifera is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. + * If not, see . + * + ******************************************************************************/ +#pragma once + +#include "abstractext.h" +#include "tibsun_globals.h" +#include "tibsun_functions.h" +#include "swizzle.h" +#include "vinifera_saveload.h" +#include "extension.h" +#include "debughandler.h" +#include "asserthandler.h" + + +/** + * Class constructor + * + * @author: CCHyper + */ +AbstractClassExtension::AbstractClassExtension(const AbstractClass *this_ptr) : + ThisPtr(this_ptr) +{ + //if (this_ptr) EXT_DEBUG_TRACE("AbstractClassExtension::AbstractClassExtension - 0x%08X\n", (uintptr_t)(ThisPtr)); + //ASSERT(ThisPtr != nullptr); // NULL ThisPtr is valid when performing a Load state operation. +} + + +/** + * Class no-init constructor. + * + * @author: CCHyper + */ +AbstractClassExtension::AbstractClassExtension(const NoInitClass &noinit) +{ + //EXT_DEBUG_TRACE("AbstractClassExtension::AbstractClassExtension(NoInitClass) - 0x%08X\n", (uintptr_t)(ThisPtr)); +} + + +/** + * Class destructor + * + * @author: CCHyper + */ +AbstractClassExtension::~AbstractClassExtension() +{ + //EXT_DEBUG_TRACE("AbstractClassExtension::~AbstractClassExtension - 0x%08X\n", (uintptr_t)(ThisPtr)); + + ThisPtr = nullptr; +} + + +/** + * Retrieves pointers to the supported interfaces on an object. + * + * @author: CCHyper, tomsons26 + */ +LONG AbstractClassExtension::QueryInterface(REFIID riid, LPVOID *ppv) +{ + /** + * Always set out parameter to NULL, validating it first. + */ + if (ppv == nullptr) { + return E_POINTER; + } + *ppv = nullptr; + + if (riid == __uuidof(IUnknown)) { + *ppv = reinterpret_cast(this); + } + + if (riid == __uuidof(IStream)) { + *ppv = reinterpret_cast(this); + } + + if (riid == __uuidof(IPersistStream)) { + *ppv = static_cast(this); + } + + if (*ppv == nullptr) { + return E_NOINTERFACE; + } + + /** + * Increment the reference count and return the pointer. + */ + reinterpret_cast(*ppv)->AddRef(); + + return S_OK; +} + + +/** + * Increments the reference count for an interface pointer to a COM object. + * + * @author: CCHyper + */ +ULONG AbstractClassExtension::AddRef() +{ + //EXT_DEBUG_TRACE("AbstractClassExtension::AddRef - 0x%08X\n", (uintptr_t)(ThisPtr)); + + return 1; +} + + +/** + * Decrements the reference count for an interface on a COM object. + * + * @author: CCHyper + */ +ULONG AbstractClassExtension::Release() +{ + //EXT_DEBUG_TRACE("AbstractClassExtension::Release - 0x%08X\n", (uintptr_t)(ThisPtr)); + + return 1; +} + + +/** + * Determines whether an object has changed since it was last saved to its stream. + * + * @author: CCHyper + */ +HRESULT AbstractClassExtension::IsDirty() +{ + //EXT_DEBUG_TRACE("AbstractClassExtension::IsDirty - 0x%08X\n", (uintptr_t)(ThisPtr)); + + return S_OK; +} + + +/** + * Loads the object from the stream and requests a new pointer to + * the class we extended post-load. + * + * @author: CCHyper, tomsons26 + */ +HRESULT AbstractClassExtension::Internal_Load(IStream *pStm) +{ + //EXT_DEBUG_TRACE("AbstractClassExtension::Internal_Load - 0x%08X\n", (uintptr_t)(ThisPtr)); + + if (!pStm) { + return E_POINTER; + } + + /** + * Load the unique id for this class. + */ + LONG id = 0; + HRESULT hr = pStm->Read(&id, sizeof(LONG), nullptr); + if (FAILED(hr)) { + return hr; + } + + Wstring this_name = Wstring(Extension::Utility::Get_TypeID_Name(this).c_str()) + ":" + Wstring("ThisPtr"); + + /** + * Register this instance to be available for remapping references to. + */ + VINIFERA_SWIZZLE_REGISTER_POINTER(id, this, this_name.Peek_Buffer()); + + /** + * Read this classes binary blob data directly into this instance. + */ + hr = pStm->Read(this, Size_Of(), nullptr); + if (FAILED(hr)) { + return hr; + } + + VINIFERA_SWIZZLE_REQUEST_POINTER_REMAP(ThisPtr, this_name.Peek_Buffer()); + + return hr; +} + + +/** + * Saves the object to the stream. + * + * @author: CCHyper, tomsons26 + */ +HRESULT AbstractClassExtension::Internal_Save(IStream *pStm, BOOL fClearDirty) +{ + //EXT_DEBUG_TRACE("AbstractClassExtension::Internal_Save - 0x%08X\n", (uintptr_t)(ThisPtr)); + + if (!pStm) { + return E_POINTER; + } + + Wstring this_name = Wstring(Extension::Utility::Get_TypeID_Name(this).c_str()) + ":" + Wstring("ThisPtr"); + + /** + * Fetch the save id for this instance. + */ + LONG id; + VINIFERA_SWIZZLE_FETCH_SWIZZLE_ID(this, id, this_name.Peek_Buffer()); + + //DEV_DEBUG_INFO("Writing id = 0x%08X.\n", id); + + HRESULT hr = pStm->Write(&id, sizeof(id), nullptr); + if (FAILED(hr)) { + return hr; + } + + /** + * Write this class instance as a binary blob. + */ + hr = pStm->Write(this, Size_Of(), nullptr); + if (FAILED(hr)) { + return hr; + } + + return hr; +} + + +/** + * Retrieves the size of the stream needed to save the object. + * + * @author: CCHyper, tomsons26 + */ +LONG AbstractClassExtension::GetSizeMax(ULARGE_INTEGER *pcbSize) +{ + //EXT_DEBUG_TRACE("AbstractClassExtension::GetSizeMax - 0x%08X\n", (uintptr_t)(ThisPtr)); + + if (!pcbSize) { + return E_POINTER; + } + + pcbSize->LowPart = Size_Of() + sizeof(uint32_t); // Add size of swizzle "id". + pcbSize->HighPart = 0; + + return S_OK; +} diff --git a/src/extensions/abstract/abstractext.h b/src/extensions/abstract/abstractext.h new file mode 100644 index 00000000..309c7b96 --- /dev/null +++ b/src/extensions/abstract/abstractext.h @@ -0,0 +1,138 @@ +/******************************************************************************* +/* O P E N S O U R C E -- V I N I F E R A ** +/******************************************************************************* + * + * @project Vinifera + * + * @file ABSTRACTEXT.H + * + * @author CCHyper + * + * @brief Base extension class for all game world objects. + * + * @license Vinifera is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 3 of the License, or (at your option) any later version. + * + * Vinifera is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. + * If not, see . + * + ******************************************************************************/ +#pragma once + +#include "always.h" +#include "tibsun_defines.h" +#include "vinifera_defines.h" +#include "noinit.h" + +#include // for IStream + + +class AbstractClass; +class WWCRCEngine; + + +/** + * This class is the base class for all game objects we can extend that have an + * existence on the battlefield. + */ +class AbstractClassExtension : public IPersistStream +{ + public: + /** + * IUnknown + */ + IFACEMETHOD(QueryInterface)(REFIID riid, LPVOID *ppvObj); + IFACEMETHOD_(ULONG, AddRef)(); + IFACEMETHOD_(ULONG, Release)(); + + /** + * IPersistStream + */ + IFACEMETHOD(IsDirty)(); + IFACEMETHOD_(LONG, GetSizeMax)(ULARGE_INTEGER *pcbSize); + + protected: + /** + * #NOTE: + * These two are used as the real base Load/Save, but are not virtual. + * Ensure you call these directly if your class derives from Abstract and + * do not call AbstractClassExtension::Save or Load directly as they + * are pure virtual and must be overridden by the final class! + */ + HRESULT STDMETHODCALLTYPE Internal_Load(IStream *pStm); + HRESULT STDMETHODCALLTYPE Internal_Save(IStream *pStm, BOOL fClearDirty); + + public: + AbstractClassExtension(const AbstractClass *this_ptr); + AbstractClassExtension(const NoInitClass &noinit); + virtual ~AbstractClassExtension(); + + /** + * Return the raw size of class data for save/load purposes. + * + * @note: This must be overridden by the extended class! + */ + virtual int Size_Of() const = 0; + + /** + * Removes the specified target from any targeting and reference trackers. + * + * @note: This must be overridden by the extended class! + */ + virtual void Detach(TARGET target, bool all = true) = 0; + + /** + * Compute a unique crc value for this instance. + * + * @note: This must be overridden by the extended class! + */ + virtual void Compute_CRC(WWCRCEngine &crc) const = 0; + + /** + * Access to the class instance we extend. + */ + virtual AbstractClass *This() const { return const_cast(ThisPtr); } + virtual const AbstractClass *This_Const() const { return ThisPtr; } + + /** + * Access to the extended class instance. + * + * @note: This must be overridden by the extended class! + */ + virtual RTTIType What_Am_I() const = 0; // { return RTTI_ABSTRACT; } + + /** + * Returns the name of this object type. + * + * @note: This must be overridden by the extended class! + */ + virtual const char *Name() const = 0; + + /** + * Returns the full name of this object type. + * + * @note: This must be overridden by the extended class! + */ + virtual const char *Full_Name() const = 0; + + private: + /** + * Pointer to the class we are extending. This provides us with a way of + * quickly referencing the base class without doing a look-up each time. + */ + const AbstractClass *ThisPtr; + + private: + AbstractClassExtension(const AbstractClassExtension &) = delete; + void operator = (const AbstractClassExtension &) = delete; + + public: +}; diff --git a/src/extensions/extension_saveload.h b/src/extensions/abstract/abstractext_hooks.cpp similarity index 71% rename from src/extensions/extension_saveload.h rename to src/extensions/abstract/abstractext_hooks.cpp index 5c22dcc8..bc32e0c2 100644 --- a/src/extensions/extension_saveload.h +++ b/src/extensions/abstract/abstractext_hooks.cpp @@ -4,11 +4,11 @@ * * @project Vinifera * - * @file EXT_SAVELOAD.H + * @file ABSTRACTEXT_HOOKS.CPP * * @author CCHyper * - * @brief Handles the saving and loading of extended class data. + * @brief Contains the hooks for the extended AbstractClass. * * @license Vinifera is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -25,13 +25,24 @@ * If not, see . * ******************************************************************************/ -#pragma once +#include "abstractext_hooks.h" +#include "abstractext_init.h" +#include "extension.h" +#include "fatal.h" +#include "debughandler.h" +#include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" -struct IStream; - -extern unsigned ViniferaSaveGameVersion; - -bool Vinifera_Put_All(IStream *pStm); -bool Vinifera_Load_All(IStream *pStm); +/** + * Main function for patching the hooks. + */ +void AbstractClassExtension_Hooks() +{ + /** + * Initialises the extended class. + */ + AbstractClassExtension_Init(); +} diff --git a/src/extensions/objecttype/objecttypeext_init.h b/src/extensions/abstract/abstractext_hooks.h similarity index 88% rename from src/extensions/objecttype/objecttypeext_init.h rename to src/extensions/abstract/abstractext_hooks.h index 80b98b08..ba1e6a99 100644 --- a/src/extensions/objecttype/objecttypeext_init.h +++ b/src/extensions/abstract/abstractext_hooks.h @@ -4,11 +4,11 @@ * * @project Vinifera * - * @file OBJECTTYPEEXT_INIT.H + * @file ABSTRACTEXT_HOOKS.H * * @author CCHyper * - * @brief Contains the hooks for initialising the extended ObjectTypeClass. + * @brief Contains the hooks for the extended AbstractClass. * * @license Vinifera is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,4 +28,4 @@ #pragma once -void ObjectTypeClassExtension_Init(); +void AbstractClassExtension_Hooks(); diff --git a/src/extensions/abstract/abstractext_init.cpp b/src/extensions/abstract/abstractext_init.cpp new file mode 100644 index 00000000..65500c2f --- /dev/null +++ b/src/extensions/abstract/abstractext_init.cpp @@ -0,0 +1,103 @@ +/******************************************************************************* +/* O P E N S O U R C E -- V I N I F E R A ** +/******************************************************************************* + * + * @project Vinifera + * + * @file ABSTRACTEXT_INIT.CPP + * + * @author CCHyper + * + * @brief Contains the hooks for initialising the extended AbstractClass. + * + * @license Vinifera is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 3 of the License, or (at your option) any later version. + * + * Vinifera is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. + * If not, see . + * + ******************************************************************************/ +#include "abstractext_init.h" +#include "abstract.h" +#include "extension.h" +#include "fatal.h" +#include "asserthandler.h" +#include "debughandler.h" + +#include "hooker.h" +#include "hooker_macros.h" + + +/** + * A fake class for implementing new member functions which allow + * access to the "this" pointer of the intended class. + * + * @note: This must not contain a constructor or destructor. + * + * @note: All functions must not be virtual and must also be prefixed + * with "_" to prevent accidental virtualization. + */ +class AbstractClassExt : public AbstractClass +{ + public: + IFACEMETHOD_(LONG, IsDirty)(); +}; + + +/** + * This patch forces AbstractClass::IsDirty() to return true. + * + * @author: CCHyper + */ +LONG STDMETHODCALLTYPE AbstractClassExt::IsDirty() +{ + return TRUE; +} + + +/** + * This patch clears the DWORD at 0x10 (0x10 is "bool IsDirty") to use the space + * for storing a pointer to the extension class instance for this AbstractClass. + * + * @author: CCHyper + */ +DECLARE_PATCH(_AbstractClass_Constructor_Extension) +{ + _asm { mov eax, ecx } + _asm { xor ecx, ecx } + + _asm { mov [eax+0x8], 0xFFFFFFFF } // ID + _asm { mov [eax+0x0C], ecx } // HeapID + + // AbstractClassExtension * ExtPtr; + _asm { mov [eax+0x10], ecx } // IsDirty, now reused as a extension pointer, so we need to clear the whole DWORD. + + _asm { mov [eax+0x0], 0x006CAA6C } // offset const AbstractClass::`vftable' + _asm { mov [eax+0x4], 0x006CAA54 } // offset const AbstractClass::`vftable' for IRTTITypeInfo + + _asm { retn } +} + + +/** + * Main function for patching the hooks. + */ +void AbstractClassExtension_Init() +{ + Patch_Jump(0x00405E00, &AbstractClassExt::Is_Dirty); + + /** + * Removes the branch from AbstractClass::Internal_Save which clears IsDirty. + */ + Patch_Byte_Range(0x00405CF8, 0x90, 12); + + Patch_Jump(0x00405B50, &_AbstractClass_Constructor_Extension); +} diff --git a/src/extensions/techno/technoext_init.h b/src/extensions/abstract/abstractext_init.h similarity index 93% rename from src/extensions/techno/technoext_init.h rename to src/extensions/abstract/abstractext_init.h index 4cc97beb..09886a36 100644 --- a/src/extensions/techno/technoext_init.h +++ b/src/extensions/abstract/abstractext_init.h @@ -4,11 +4,11 @@ * * @project Vinifera * - * @file TECHNOEXT_INIT.H + * @file ABSTRACTEXT_INIT.H * * @author CCHyper * - * @brief Contains the hooks for initialising the extended TechnoClass. + * @brief Contains the hooks for initialising the extended AbstractClass. * * @license Vinifera is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,4 +28,4 @@ #pragma once -void TechnoClassExtension_Init(); +void AbstractClassExtension_Init(); diff --git a/src/extensions/abstracttype/abstracttypeext.cpp b/src/extensions/abstracttype/abstracttypeext.cpp new file mode 100644 index 00000000..e7308172 --- /dev/null +++ b/src/extensions/abstracttype/abstracttypeext.cpp @@ -0,0 +1,161 @@ +/******************************************************************************* +/* O P E N S O U R C E -- V I N I F E R A ** +/******************************************************************************* + * + * @project Vinifera + * + * @file ABSTRACTTYPEEXT.CPP + * + * @author CCHyper + * + * @brief Base extension class for all type objects. + * + * @license Vinifera is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 3 of the License, or (at your option) any later version. + * + * Vinifera is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. + * If not, see . + * + ******************************************************************************/ +#pragma once + +#include "abstracttypeext.h" +#include "abstracttype.h" +#include "ccini.h" +#include "extension.h" + + +/** + * Class constructor. + * + * @author: CCHyper + */ +AbstractTypeClassExtension::AbstractTypeClassExtension(const AbstractTypeClass *this_ptr) : + AbstractClassExtension(this_ptr), + IniName(), + FullName() +{ + //if (this_ptr) EXT_DEBUG_TRACE("AbstractTypeClassExtension::AbstractTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); +} + + +/** + * Class no-init constructor. + * + * @author: CCHyper + */ +AbstractTypeClassExtension::AbstractTypeClassExtension(const NoInitClass &noinit) : + AbstractClassExtension(noinit) +{ + //EXT_DEBUG_TRACE("AbstractTypeClassExtension::AbstractTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); +} + + +/** + * Class destructor. + * + * @author: CCHyper + */ +AbstractTypeClassExtension::~AbstractTypeClassExtension() +{ + //EXT_DEBUG_TRACE("AbstractTypeClassExtension::~AbstractTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); +} + + +/** + * Initializes an object from the stream where it was saved previously. + * + * @author: CCHyper + */ +HRESULT AbstractTypeClassExtension::Load(IStream *pStm) +{ + //EXT_DEBUG_TRACE("AbstractTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + HRESULT hr = AbstractClassExtension::Internal_Load(pStm); + if (FAILED(hr)) { + return hr; + } + + return hr; +} + + +/** + * Saves an object to the specified stream. + * + * @author: CCHyper + */ +HRESULT AbstractTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) +{ + //EXT_DEBUG_TRACE("AbstractTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + /** + * Store the name strings as raw data, these are used by the load operation. + */ + std::strncpy(IniName, Name(), sizeof(IniName)); + std::strncpy(FullName, Full_Name(), sizeof(FullName)); + + HRESULT hr = AbstractClassExtension::Internal_Save(pStm, fClearDirty); + if (FAILED(hr)) { + return hr; + } + + return hr; +} + + +/** + * Returns the name of this object type. + * + * @author: CCHyper + */ +const char *AbstractTypeClassExtension::Name() const +{ + //EXT_DEBUG_TRACE("AbstractTypeClassExtension::Name - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + const char *name = reinterpret_cast(This())->Name(); + //EXT_DEBUG_INFO("AbstractTypeClassExtension: Name -> %s.\n", name); + return name; +} + + +/** + * Returns the full name of this object type. + * + * @author: CCHyper + */ +const char *AbstractTypeClassExtension::Full_Name() const +{ + //EXT_DEBUG_TRACE("AbstractTypeClassExtension::Full_Name - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + const char *name = reinterpret_cast(This())->Full_Name(); + //EXT_DEBUG_INFO("AbstractTypeClassExtension: Full_Name -> %s.\n", name); + return name; +} + + +/** + * Fetches the extension data from the INI database. + * + * @author: CCHyper + */ +bool AbstractTypeClassExtension::Read_INI(CCINIClass &ini) +{ + //EXT_DEBUG_TRACE("AbstractTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + const char *ini_name = Name(); + + if (!ini.Is_Present(ini_name)) { + return false; + } + + return true; +} diff --git a/src/extensions/abstracttype/abstracttypeext.h b/src/extensions/abstracttype/abstracttypeext.h new file mode 100644 index 00000000..c435548b --- /dev/null +++ b/src/extensions/abstracttype/abstracttypeext.h @@ -0,0 +1,68 @@ +/******************************************************************************* +/* O P E N S O U R C E -- V I N I F E R A ** +/******************************************************************************* + * + * @project Vinifera + * + * @file ABSTRACTTYPEEXT.H + * + * @author CCHyper + * + * @brief Base extension class for all type objects. + * + * @license Vinifera is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 3 of the License, or (at your option) any later version. + * + * Vinifera is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. + * If not, see . + * + ******************************************************************************/ +#pragma once + +#include "abstractext.h" + + +class AbstractTypeClass; +class CCINIClass; + + +class AbstractTypeClassExtension : public AbstractClassExtension +{ + public: + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + AbstractTypeClassExtension(const AbstractTypeClass *this_ptr); + AbstractTypeClassExtension(const NoInitClass &noinit); + virtual ~AbstractTypeClassExtension(); + + virtual const char *Name() const override; + virtual const char *Full_Name() const override; + + virtual bool Read_INI(CCINIClass &ini); + + protected: + /** + * These are only to be accessed for save and load operations! + */ + char IniName[24 + 1]; + char FullName[48 + 1]; + + public: + + private: + AbstractTypeClassExtension(const AbstractTypeClassExtension &) = delete; + void operator = (const AbstractTypeClassExtension &) = delete; +}; diff --git a/src/extensions/aircraft/aircraftext.cpp b/src/extensions/aircraft/aircraftext.cpp index 255b96f8..3c36eac9 100644 --- a/src/extensions/aircraft/aircraftext.cpp +++ b/src/extensions/aircraft/aircraftext.cpp @@ -28,29 +28,22 @@ #include "aircraftext.h" #include "aircraft.h" #include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all AircraftClass extension instances. - */ -ExtensionMap AircraftClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -AircraftClassExtension::AircraftClassExtension(AircraftClass *this_ptr) : - Extension(this_ptr) +AircraftClassExtension::AircraftClassExtension(const AircraftClass *this_ptr) : + FootClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AircraftClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("AircraftClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("AircraftClassExtension::AircraftClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + AircraftExtensions.Add(this); } @@ -60,9 +53,9 @@ AircraftClassExtension::AircraftClassExtension(AircraftClass *this_ptr) : * @author: CCHyper */ AircraftClassExtension::AircraftClassExtension(const NoInitClass &noinit) : - Extension(noinit) + FootClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("AircraftClassExtension::AircraftClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ AircraftClassExtension::AircraftClassExtension(const NoInitClass &noinit) : */ AircraftClassExtension::~AircraftClassExtension() { - //EXT_DEBUG_TRACE("AircraftClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("AircraftClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AircraftClassExtension::~AircraftClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + AircraftExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT AircraftClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("AircraftClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); - IsInitialized = false; + return S_OK; } @@ -87,10 +98,9 @@ AircraftClassExtension::~AircraftClassExtension() */ HRESULT AircraftClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AircraftClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AircraftClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = FootClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT AircraftClassExtension::Load(IStream *pStm) */ HRESULT AircraftClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AircraftClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AircraftClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = FootClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT AircraftClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int AircraftClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AircraftClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AircraftClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int AircraftClassExtension::Size_Of() const */ void AircraftClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AircraftClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AircraftClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,6 +160,5 @@ void AircraftClassExtension::Detach(TARGET target, bool all) */ void AircraftClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AircraftClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AircraftClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } diff --git a/src/extensions/aircraft/aircraftext.h b/src/extensions/aircraft/aircraftext.h index db9a906e..93f0a721 100644 --- a/src/extensions/aircraft/aircraftext.h +++ b/src/extensions/aircraft/aircraftext.h @@ -27,30 +27,41 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "footext.h" +#include "aircraft.h" class AircraftClass; class HouseClass; -class AircraftClassExtension final : public Extension +class DECLSPEC_UUID(UUID_AIRCRAFT_EXTENSION) +AircraftClassExtension final : public FootClassExtension { public: - AircraftClassExtension(AircraftClass *this_ptr); + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + AircraftClassExtension(const AircraftClass *this_ptr = nullptr); AircraftClassExtension(const NoInitClass &noinit); - ~AircraftClassExtension(); + virtual ~AircraftClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + virtual AircraftClass *This() const override { return reinterpret_cast(FootClassExtension::This()); } + virtual const AircraftClass *This_Const() const override { return reinterpret_cast(FootClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_AIRCRAFT; } + public: }; - - -extern ExtensionMap AircraftClassExtensions; diff --git a/src/extensions/aircraft/aircraftext_hooks.cpp b/src/extensions/aircraft/aircraftext_hooks.cpp index b2a58c61..6b020f26 100644 --- a/src/extensions/aircraft/aircraftext_hooks.cpp +++ b/src/extensions/aircraft/aircraftext_hooks.cpp @@ -36,6 +36,7 @@ #include "unittypeext.h" #include "technotype.h" #include "technotypeext.h" +#include "extension.h" #include "voc.h" #include "fatal.h" #include "debughandler.h" @@ -56,7 +57,7 @@ DECLARE_PATCH(_AircraftClass_Mission_Unload_Transport_Detach_Sound_Patch) { GET_REGISTER_STATIC(AircraftClass *, this_ptr, esi); GET_REGISTER_STATIC(FootClass *, passenger, edi); - static TechnoTypeClassExtension *radio_technotypeext; + static TechnoTypeClassExtension *technotypeext; /** * Don't play the passenger leave sound for carryalls. @@ -66,9 +67,9 @@ DECLARE_PATCH(_AircraftClass_Mission_Unload_Transport_Detach_Sound_Patch) /** * Do we have a sound to play when passengers leave us? If so, play it now. */ - radio_technotypeext = TechnoTypeClassExtensions.find(this_ptr->Techno_Type_Class()); - if (radio_technotypeext && radio_technotypeext->LeaveTransportSound != VOC_NONE) { - Sound_Effect(radio_technotypeext->LeaveTransportSound, this_ptr->Coord); + technotypeext = Extension::Fetch(this_ptr->Techno_Type_Class()); + if (technotypeext->LeaveTransportSound != VOC_NONE) { + Sound_Effect(technotypeext->LeaveTransportSound, this_ptr->Coord); } } @@ -166,24 +167,22 @@ DECLARE_PATCH(_AircraftClass_What_Action_Is_Totable_Patch) target_unit = reinterpret_cast(target); /** - * Fetch the unit type extension instance if available. + * Fetch the extension instance. */ - unittypeext = UnitTypeClassExtensions.find(target_unit->Class); - if (unittypeext) { + unittypeext = Extension::Fetch(target_unit->Class); + + /** + * Can this unit be toted/picked up by us? + */ + if (!unittypeext->IsTotable) { /** - * Can this unit be toted/picked up by us? + * If not, then show the "no move" mouse. */ - if (!unittypeext->IsTotable) { - - /** - * If not, then show the "no move" mouse. - */ - action = ACTION_NOMOVE; + action = ACTION_NOMOVE; - goto failed_tote_check; + goto failed_tote_check; - } } } } diff --git a/src/extensions/aircraft/aircraftext_init.cpp b/src/extensions/aircraft/aircraftext_init.cpp index d7df11d4..f7c698a5 100644 --- a/src/extensions/aircraft/aircraftext_init.cpp +++ b/src/extensions/aircraft/aircraftext_init.cpp @@ -29,10 +29,16 @@ #include "aircrafttypeext.h" #include "aircraft.h" #include "aircrafttype.h" +#include "tibsun_globals.h" +#include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" -#include "vinifera_util.h" + +#include "hooker.h" +#include "hooker_macros.h" /** @@ -45,21 +51,20 @@ DECLARE_PATCH(_AircraftClass_Constructor_Patch) { GET_REGISTER_STATIC(AircraftClass *, this_ptr, esi); // Current "this" pointer. - static AircraftClassExtension *exttype_ptr; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = AircraftClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create AircraftClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create AircraftClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create AircraftClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * Stolen bytes here. */ @@ -73,28 +78,6 @@ DECLARE_PATCH(_AircraftClass_Constructor_Patch) } -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_AircraftClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(AircraftClass *, this_ptr, ebx); - GET_STACK_STATIC(const NoInitClass *, noinit, esp, 0x10); - static AircraftClassExtension *ext_ptr; - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov dword ptr [ebx], 0x006CADF8 } // this->vftable = const AircraftClass::`vftable'; - JMP(0x0040EB87); -} - - /** * Patch for including the extended class members in the destruction process. * @@ -109,84 +92,14 @@ DECLARE_PATCH(_AircraftClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - AircraftClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { add esp, 0x8 } - _asm { ret } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_AircraftClass_Detach_Patch) -{ - GET_REGISTER_STATIC(AircraftClass *, this_ptr, esi); - GET_STACK_STATIC(TARGET, target, esp, 0x10); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static AircraftClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = AircraftClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Detach(target, all); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members to the base class crc calculation. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_AircraftClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(AircraftClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static AircraftClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = AircraftClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } + _asm { mov edx, ds:0x007E4058 } // Aircraft.vtble + JMP_REG(eax, 0x0040DBBE); } @@ -196,8 +109,5 @@ DECLARE_PATCH(_AircraftClass_Compute_CRC_Patch) void AircraftClassExtension_Init() { Patch_Jump(0x0040880C, &_AircraftClass_Constructor_Patch); - Patch_Jump(0x0040EB81, &_AircraftClass_NoInit_Constructor_Patch); - Patch_Jump(0x0040DCCA, &_AircraftClass_Destructor_Patch); - Patch_Jump(0x0040EDC5, &_AircraftClass_Detach_Patch); - Patch_Jump(0x0040ED91, &_AircraftClass_Compute_CRC_Patch); + Patch_Jump(0x0040DBB8, &_AircraftClass_Destructor_Patch); } diff --git a/src/extensions/aircrafttype/aircrafttypeext.cpp b/src/extensions/aircrafttype/aircrafttypeext.cpp index 4b31efa3..120b4aad 100644 --- a/src/extensions/aircrafttype/aircrafttypeext.cpp +++ b/src/extensions/aircrafttype/aircrafttypeext.cpp @@ -28,29 +28,22 @@ #include "aircrafttypeext.h" #include "aircrafttype.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all AircraftTypeClass extension instances. - */ -ExtensionMap AircraftTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -AircraftTypeClassExtension::AircraftTypeClassExtension(AircraftTypeClass *this_ptr) : - Extension(this_ptr) +AircraftTypeClassExtension::AircraftTypeClassExtension(const AircraftTypeClass *this_ptr) : + TechnoTypeClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AircraftTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("AircraftTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("AircraftTypeClassExtension::AircraftTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + AircraftTypeExtensions.Add(this); } @@ -60,9 +53,9 @@ AircraftTypeClassExtension::AircraftTypeClassExtension(AircraftTypeClass *this_p * @author: CCHyper */ AircraftTypeClassExtension::AircraftTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + TechnoTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("AircraftTypeClassExtension::AircraftTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ AircraftTypeClassExtension::AircraftTypeClassExtension(const NoInitClass &noinit */ AircraftTypeClassExtension::~AircraftTypeClassExtension() { - //EXT_DEBUG_TRACE("AircraftTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("AircraftTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AircraftTypeClassExtension::~AircraftTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + AircraftTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT AircraftTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("AircraftTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -87,10 +98,9 @@ AircraftTypeClassExtension::~AircraftTypeClassExtension() */ HRESULT AircraftTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AircraftTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AircraftTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = TechnoTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT AircraftTypeClassExtension::Load(IStream *pStm) */ HRESULT AircraftTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AircraftTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AircraftTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = TechnoTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT AircraftTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int AircraftTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AircraftTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AircraftTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int AircraftTypeClassExtension::Size_Of() const */ void AircraftTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AircraftTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AircraftTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,8 +160,7 @@ void AircraftTypeClassExtension::Detach(TARGET target, bool all) */ void AircraftTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AircraftTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AircraftTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -165,11 +171,13 @@ void AircraftTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool AircraftTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AircraftTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("AircraftTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AircraftTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (!TechnoTypeClassExtension::Read_INI(ini)) { + return false; + } - const char *ini_name = ThisPtr->Name(); + const char *ini_name = Name(); if (!ini.Is_Present(ini_name)) { return false; diff --git a/src/extensions/aircrafttype/aircrafttypeext.h b/src/extensions/aircrafttype/aircrafttypeext.h index 3624244e..58ac4acb 100644 --- a/src/extensions/aircrafttype/aircrafttypeext.h +++ b/src/extensions/aircrafttype/aircrafttypeext.h @@ -27,33 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "technotypeext.h" +#include "aircrafttype.h" -class AircraftTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_AIRCRAFTTYPE_EXTENSION) +AircraftTypeClassExtension final : public TechnoTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class AircraftTypeClassExtension final : public Extension -{ public: - AircraftTypeClassExtension(AircraftTypeClass *this_ptr); + AircraftTypeClassExtension(const AircraftTypeClass *this_ptr = nullptr); AircraftTypeClassExtension(const NoInitClass &noinit); - ~AircraftTypeClassExtension(); + virtual ~AircraftTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + + virtual AircraftTypeClass *This() const override { return reinterpret_cast(TechnoTypeClassExtension::This()); } + virtual const AircraftTypeClass *This_Const() const override { return reinterpret_cast(TechnoTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_AIRCRAFTTYPE; } - bool Read_INI(CCINIClass &ini); + virtual bool Read_INI(CCINIClass &ini) override; public: - }; - - -extern ExtensionMap AircraftTypeClassExtensions; diff --git a/src/extensions/aircrafttype/aircrafttypeext_init.cpp b/src/extensions/aircrafttype/aircrafttypeext_init.cpp index fa9d30c4..54eda40a 100644 --- a/src/extensions/aircrafttype/aircrafttypeext_init.cpp +++ b/src/extensions/aircrafttype/aircrafttypeext_init.cpp @@ -30,10 +30,15 @@ #include "aircrafttype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,23 +51,20 @@ DECLARE_PATCH(_AircraftTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(AircraftTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0x0C); // ini name. - static AircraftTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating AircraftTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = AircraftTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create AircraftTypeClassExtension instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create AircraftTypeClassExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create AircraftTypeClassExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * Stolen bytes here. */ @@ -93,28 +95,6 @@ DECLARE_PATCH(_AircraftTypeClass_Find_Or_Make_Patch) } -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_AircraftTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(AircraftTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { ret 4 } -} - - /** * Patch for including the extended class members in the destruction process. * @@ -129,15 +109,14 @@ DECLARE_PATCH(_AircraftTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - AircraftTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007E2420 } // AircraftTypes.vtble + JMP_REG(eax, 0x0040FCDE); } @@ -155,90 +134,14 @@ DECLARE_PATCH(_AircraftTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - AircraftTypeClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_AircraftTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(AircraftTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static AircraftTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = AircraftTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_AircraftTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(AircraftTypeClass *, this_ptr, esi); - GET_REGISTER_STATIC(CCINIClass *, ini, ebx); - static AircraftTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = AircraftTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov al, 1 } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 4 } + _asm { mov edx, ds:0x007E2420 } // AircraftTypes.vtble + JMP_REG(eax, 0x0041022E); } @@ -249,9 +152,6 @@ void AircraftTypeClassExtension_Init() { Patch_Jump(0x0040FC8F, &_AircraftTypeClass_Constructor_Patch); Patch_Jump(0x0041009C, &_AircraftTypeClass_Find_Or_Make_Patch); // Constructor is also inlined in AircraftTypeClass::Find_Or_Make! - Patch_Jump(0x0040FCBA, &_AircraftTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x0040FD28, &_AircraftTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x00410288, &_AircraftTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x0040FF66, &_AircraftTypeClass_Compute_CRC_Patch); - Patch_Jump(0x0040FF0E, &_AircraftTypeClass_Read_INI_Patch); + //Patch_Jump(0x0040FCD8, &_AircraftTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x00410228, &_AircraftTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/anim/animext.cpp b/src/extensions/anim/animext.cpp index 283a1998..5465abcc 100644 --- a/src/extensions/anim/animext.cpp +++ b/src/extensions/anim/animext.cpp @@ -28,29 +28,22 @@ #include "animext.h" #include "anim.h" #include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all AnimClass extension instances. - */ -ExtensionMap AnimClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -AnimClassExtension::AnimClassExtension(AnimClass *this_ptr) : - Extension(this_ptr) +AnimClassExtension::AnimClassExtension(const AnimClass *this_ptr) : + ObjectClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AnimClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("AnimClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("AnimClassExtension::AnimClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + AnimExtensions.Add(this); } @@ -60,9 +53,9 @@ AnimClassExtension::AnimClassExtension(AnimClass *this_ptr) : * @author: CCHyper */ AnimClassExtension::AnimClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("AnimClassExtension::AnimClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ AnimClassExtension::AnimClassExtension(const NoInitClass &noinit) : */ AnimClassExtension::~AnimClassExtension() { - //EXT_DEBUG_TRACE("AnimClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("AnimClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AnimClassExtension::~AnimClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + AnimExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT AnimClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("AnimClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); - IsInitialized = false; + return S_OK; } @@ -87,10 +98,9 @@ AnimClassExtension::~AnimClassExtension() */ HRESULT AnimClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AnimClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AnimClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT AnimClassExtension::Load(IStream *pStm) */ HRESULT AnimClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AnimClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AnimClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT AnimClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int AnimClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AnimClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AnimClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int AnimClassExtension::Size_Of() const */ void AnimClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AnimClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AnimClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,6 +160,5 @@ void AnimClassExtension::Detach(TARGET target, bool all) */ void AnimClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AnimClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AnimClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } diff --git a/src/extensions/anim/animext.h b/src/extensions/anim/animext.h index a0f5d206..fc991d15 100644 --- a/src/extensions/anim/animext.h +++ b/src/extensions/anim/animext.h @@ -27,33 +27,41 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" - -#include "ttimer.h" -#include "ftimer.h" +#include "objectext.h" +#include "anim.h" class AnimClass; class HouseClass; -class AnimClassExtension final : public Extension +class DECLSPEC_UUID(UUID_ANIM_EXTENSION) +AnimClassExtension final : public ObjectClassExtension { public: - AnimClassExtension(AnimClass *this_ptr); + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + AnimClassExtension(const AnimClass *this_ptr = nullptr); AnimClassExtension(const NoInitClass &noinit); - ~AnimClassExtension(); + virtual ~AnimClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + virtual AnimClass *This() const override { return reinterpret_cast(ObjectClassExtension::This()); } + virtual const AnimClass *This_Const() const override { return reinterpret_cast(ObjectClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_ANIM; } + public: }; - - -extern ExtensionMap AnimClassExtensions; diff --git a/src/extensions/anim/animext_hooks.cpp b/src/extensions/anim/animext_hooks.cpp index 48a8011e..f8be329d 100644 --- a/src/extensions/anim/animext_hooks.cpp +++ b/src/extensions/anim/animext_hooks.cpp @@ -40,6 +40,7 @@ #include "cell.h" #include "rules.h" #include "scenario.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" @@ -55,7 +56,7 @@ * @note: This must not contain a constructor or destructor! * @note: All functions must be prefixed with "_" to prevent accidental virtualization. */ -class AnimClassFake final : public AnimClass +class AnimClassExt final : public AnimClass { public: LayerType _In_Which_Layer() const; @@ -67,7 +68,7 @@ class AnimClassFake final : public AnimClass * * @author: CCHyper */ -LayerType AnimClassFake::_In_Which_Layer() const +LayerType AnimClassExt::_In_Which_Layer() const { if (Target_Legal(xObject)) { return LAYER_GROUND; @@ -81,8 +82,8 @@ LayerType AnimClassFake::_In_Which_Layer() const * @author: CCHyper */ AnimTypeClassExtension *animtypeext = nullptr; - animtypeext = AnimTypeClassExtensions.find(Class); - if (animtypeext && animtypeext->AttachLayer != LAYER_NONE) { + animtypeext = Extension::Fetch(Class); + if (animtypeext->AttachLayer != LAYER_NONE) { return animtypeext->AttachLayer; } @@ -116,22 +117,20 @@ static void Anim_Spawn_Particles(AnimClass *this_ptr) { AnimTypeClassExtension *animtypeext; - animtypeext = AnimTypeClassExtensions.find(this_ptr->Class); - if (animtypeext) { - if (animtypeext->ParticleToSpawn != PARTICLE_NONE) { + animtypeext = Extension::Fetch(this_ptr->Class); + if (animtypeext->ParticleToSpawn != PARTICLE_NONE) { - for (int i = 0; i < animtypeext->NumberOfParticles; ++i) { + for (int i = 0; i < animtypeext->NumberOfParticles; ++i) { - Coordinate spawn_coord = this_ptr->Coord; + Coordinate spawn_coord = this_ptr->Coord; - /** - * Spawn a new particle at this anims coord. - */ - MasterParticle->Spawn_Particle( - (ParticleTypeClass *)ParticleTypeClass::As_Pointer(animtypeext->ParticleToSpawn), - spawn_coord); + /** + * Spawn a new particle at this anims coord. + */ + MasterParticle->Spawn_Particle( + (ParticleTypeClass *)ParticleTypeClass::As_Pointer(animtypeext->ParticleToSpawn), + spawn_coord); - } } } } @@ -177,12 +176,12 @@ DECLARE_PATCH(_AnimClass_Constructor_Layer_Set_Z_Height_Patch) GET_REGISTER_STATIC(AnimClass *, this_ptr, esi); static AnimTypeClassExtension *animtypeext; - animtypeext = AnimTypeClassExtensions.find(this_ptr->Class); + animtypeext = Extension::Fetch(this_ptr->Class); /** * Set the layer to the highest level if "air" or "top". */ - if (animtypeext && animtypeext->AttachLayer != LAYER_NONE + if (animtypeext->AttachLayer != LAYER_NONE && (animtypeext->AttachLayer == LAYER_AIR || animtypeext->AttachLayer == LAYER_TOP)) { this_ptr->Set_Z_Coord(Rule->FlightLevel); @@ -221,12 +220,12 @@ DECLARE_PATCH(_AnimClass_Middle_Create_Crater_ForceBigCraters_Patch) coord.Y = tmpcoord->Y; coord.Z = tmpcoord->Z; - animtypeext = AnimTypeClassExtensions.find(this_ptr->Class); + animtypeext = Extension::Fetch(this_ptr->Class); /** * Is this anim is to spawn big craters? */ - if (animtypeext && animtypeext->IsForceBigCraters) { + if (animtypeext->IsForceBigCraters) { SmudgeTypeClass::Create_Crater(coord, 300, 300, true); } else { SmudgeTypeClass::Create_Crater(coord, width, height, false); @@ -249,7 +248,7 @@ DECLARE_PATCH(_AnimClass_AI_Beginning_Patch) static CellClass *cell; animtype = this_ptr->Class; - animtypeext = AnimTypeClassExtensions.find(animtype); + animtypeext = Extension::Fetch(animtype); /** * Stolen bytes/code. @@ -259,28 +258,21 @@ DECLARE_PATCH(_AnimClass_AI_Beginning_Patch) this_ptr->ObjectClass::AI(); } + cell = this_ptr->Get_Cell_Ptr(); + /** - * Do we have a valid extension instance? + * #issue-560 + * + * Implements IsHideIfNotTiberium for Anims. + * + * @author: CCHyper */ - if (animtypeext) { - - cell = this_ptr->Get_Cell_Ptr(); - - /** - * #issue-560 - * - * Implements IsHideIfNotTiberium for Anims. - * - * @author: CCHyper - */ - if (animtypeext->IsHideIfNotTiberium) { - - if (!cell || !cell->Get_Tiberium_Value()) { - this_ptr->IsInvisible = true; - } - + if (animtypeext->IsHideIfNotTiberium) { + + if (!cell || !cell->Get_Tiberium_Value()) { + this_ptr->IsInvisible = true; } - + } JMP_REG(edx, 0x00414EAA); @@ -323,10 +315,8 @@ DECLARE_PATCH(_AnimClass_Constructor_Init_Class_Values_Patch) * @author: CCHyper */ if (!this_ptr->ZAdjust) { - animtypeext = AnimTypeClassExtensions.find(this_ptr->Class); - if (animtypeext) { - this_ptr->ZAdjust = animtypeext->ZAdjust; - } + animtypeext = Extension::Fetch(this_ptr->Class); + this_ptr->ZAdjust = animtypeext->ZAdjust; } /** @@ -399,6 +389,6 @@ void AnimClassExtension_Hooks() Patch_Jump(0x00414E8F, &_AnimClass_AI_Beginning_Patch); Patch_Jump(0x004160FB, &_AnimClass_Middle_Create_Crater_ForceBigCraters_Patch); Patch_Jump(0x0041606C, &_AnimClass_Middle_SpawnParticle_Patch); - Patch_Jump(0x00415D30, &AnimClassFake::_In_Which_Layer); + Patch_Jump(0x00415D30, &AnimClassExt::_In_Which_Layer); Patch_Jump(0x00413D3E, &_AnimClass_Constructor_Layer_Set_Z_Height_Patch); } diff --git a/src/extensions/anim/animext_init.cpp b/src/extensions/anim/animext_init.cpp index 3361ba9e..8576e0ce 100644 --- a/src/extensions/anim/animext_init.cpp +++ b/src/extensions/anim/animext_init.cpp @@ -31,9 +31,15 @@ #include "animtype.h" #include "fatal.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "tibsun_globals.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -45,20 +51,14 @@ DECLARE_PATCH(_AnimClass_Constructor_Patch) { GET_REGISTER_STATIC(AnimClass *, this_ptr, esi); // Current "this" pointer. - static AnimClassExtension *exttype_ptr; static AnimTypeClassExtension *animtypeext; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = AnimClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create AnimClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create AnimClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create AnimClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** @@ -78,6 +78,11 @@ DECLARE_PATCH(_AnimClass_Constructor_Patch) goto destroy_anim; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * #issue-561 * @@ -87,10 +92,8 @@ DECLARE_PATCH(_AnimClass_Constructor_Patch) * @author: CCHyper */ if (!this_ptr->ZAdjust) { - animtypeext = AnimTypeClassExtensions.find(this_ptr->Class); - if (animtypeext) { - this_ptr->ZAdjust = animtypeext->ZAdjust; - } + animtypeext = Extension::Fetch(this_ptr->Class); + this_ptr->ZAdjust = animtypeext->ZAdjust; } original_code: @@ -134,145 +137,62 @@ DECLARE_PATCH(_AnimClass_Constructor_Patch) DECLARE_PATCH(_AnimClass_Default_Constructor_Patch) { GET_REGISTER_STATIC(AnimClass *, this_ptr, esi); // Current "this" pointer. - static AnimClassExtension *exttype_ptr; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = AnimClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create AnimClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create AnimClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create AnimClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ebx } - _asm { ret } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_AnimClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(AnimClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit, esp, 0x10); - static AnimClassExtension *ext_ptr; - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov dword ptr [esi], 0x006CB92C } // this->vftable = const AnimClass::`vftable'{for `IRTTITypeInfo'}; - JMP(0x004164DD); -} - - -/** - * Patch for including the extended class members in the destruction process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_AnimClass_Destructor_Patch) -{ - GET_REGISTER_STATIC(AnimClass *, this_ptr, esi); - - /** - * Remove the extended class from the global index. + * Create an extended class instance. */ - AnimClassExtensions.remove(this_ptr); + Extension::Make(this_ptr); /** * Stolen bytes here. */ original_code: + _asm { mov eax, this_ptr } _asm { pop esi } _asm { pop ebx } - _asm { add esp, 0x10 } _asm { ret } } /** - * Patch for including the extended class members to the base class detach process. + * Patch for including the extended class members in the destruction process. * * @warning: Do not touch this unless you know what you are doing! * * @author: CCHyper */ -DECLARE_PATCH(_AnimClass_Detach_Patch) +DECLARE_PATCH(_AnimClass_Destructor_Patch) { GET_REGISTER_STATIC(AnimClass *, this_ptr, esi); - GET_STACK_STATIC(TARGET, target, esp, 0x10); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static AnimClassExtension *ext_ptr; /** - * Find the extension instance. + * If this anim instance was destoryed because it has a NULL class type, then + * it would not have created an extension instance, so we can skip the destroy + * call here. */ - ext_ptr = AnimClassExtensions.find(this_ptr); - if (!ext_ptr) { + if (!this_ptr->Class) { goto original_code; } - ext_ptr->Detach(target, all); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members to the base class crc calculation. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_AnimClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(AnimClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static AnimClassExtension *ext_ptr; - /** - * Find the extension instance. + * Remove the extended class from the global index. */ - ext_ptr = AnimClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Compute_CRC(*crc); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } + _asm { mov eax, ds:0x007E4580 } // GameActive + JMP_REG(ebx, 0x004142D0); } @@ -283,9 +203,6 @@ void AnimClassExtension_Init() { Patch_Jump(0x00413C79, &_AnimClass_Constructor_Patch); Patch_Jump(0x004142A6, &_AnimClass_Default_Constructor_Patch); - Patch_Jump(0x004164D7, &_AnimClass_NoInit_Constructor_Patch); Patch_Jump(0x0041441F, 0x00414475); // This jump goes from duplicate code in the destructor to our patch, removing the need for two hooks. - Patch_Jump(0x0041447C, &_AnimClass_Destructor_Patch); - Patch_Jump(0x004163D9, &_AnimClass_Detach_Patch); - Patch_Jump(0x00416626, &_AnimClass_Compute_CRC_Patch); + Patch_Jump(0x004142CB, &_AnimClass_Destructor_Patch); } diff --git a/src/extensions/animtype/animtypeext.cpp b/src/extensions/animtype/animtypeext.cpp index 03fa9d88..2f0934d7 100644 --- a/src/extensions/animtype/animtypeext.cpp +++ b/src/extensions/animtype/animtypeext.cpp @@ -29,23 +29,19 @@ #include "animtype.h" #include "ccini.h" #include "tibsun_defines.h" +#include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all AnimTypeClass extension instances. - */ -ExtensionMap AnimTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -AnimTypeClassExtension::AnimTypeClassExtension(AnimTypeClass *this_ptr) : - Extension(this_ptr), +AnimTypeClassExtension::AnimTypeClassExtension(const AnimTypeClass *this_ptr) : + ObjectTypeClassExtension(this_ptr), IsHideIfNotTiberium(false), IsForceBigCraters(false), ZAdjust(0), @@ -53,11 +49,9 @@ AnimTypeClassExtension::AnimTypeClassExtension(AnimTypeClass *this_ptr) : ParticleToSpawn(PARTICLE_NONE), NumberOfParticles(0) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AnimTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("AnimTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("AnimTypeClassExtension::AnimTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + AnimTypeExtensions.Add(this); } @@ -67,9 +61,9 @@ AnimTypeClassExtension::AnimTypeClassExtension(AnimTypeClass *this_ptr) : * @author: CCHyper */ AnimTypeClassExtension::AnimTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("AnimTypeClassExtension::AnimTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -80,10 +74,28 @@ AnimTypeClassExtension::AnimTypeClassExtension(const NoInitClass &noinit) : */ AnimTypeClassExtension::~AnimTypeClassExtension() { - //EXT_DEBUG_TRACE("AnimTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("AnimTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AnimTypeClassExtension::~AnimTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + AnimTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT AnimTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("AnimTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -94,10 +106,9 @@ AnimTypeClassExtension::~AnimTypeClassExtension() */ HRESULT AnimTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AnimTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AnimTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -115,10 +126,9 @@ HRESULT AnimTypeClassExtension::Load(IStream *pStm) */ HRESULT AnimTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AnimTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AnimTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -134,8 +144,7 @@ HRESULT AnimTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int AnimTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AnimTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AnimTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -148,8 +157,7 @@ int AnimTypeClassExtension::Size_Of() const */ void AnimTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AnimTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AnimTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -160,8 +168,7 @@ void AnimTypeClassExtension::Detach(TARGET target, bool all) */ void AnimTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AnimTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AnimTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); crc(AttachLayer); crc(NumberOfParticles); @@ -175,11 +182,13 @@ void AnimTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool AnimTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("AnimTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("AnimTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AnimTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (!ObjectTypeClassExtension::Read_INI(ini)) { + return false; + } - const char *ini_name = ThisPtr->Name(); + const char *ini_name = This()->Name(); if (!ini.Is_Present(ini_name)) { return false; @@ -193,21 +202,21 @@ bool AnimTypeClassExtension::Read_INI(CCINIClass &ini) TPoint2D random_rate = ini.Get_Point(ini_name, "RandomRate", TPoint2D(-1, -1)); if (random_rate.X != -1) { if (random_rate.Y <= 0) { - DEV_DEBUG_WARNING("Animation \"%s\" has a zero or negative random rate 'Low' value!\n", ThisPtr->Name()); + DEV_DEBUG_WARNING("Animation \"%s\" has a zero or negative random rate 'Low' value!\n", This()->Name()); } random_rate.X = TICKS_PER_MINUTE / std::abs(random_rate.X); } if (random_rate.Y != -1) { if (random_rate.Y <= 0) { - DEV_DEBUG_WARNING("Animation \"%s\" has a zero or negative random rate 'High' value!\n", ThisPtr->Name()); + DEV_DEBUG_WARNING("Animation \"%s\" has a zero or negative random rate 'High' value!\n", This()->Name()); } random_rate.Y = TICKS_PER_MINUTE / std::abs(random_rate.Y); } if ((random_rate.X != -1 && random_rate.Y != -1) && random_rate.X > random_rate.Y) { std::swap(random_rate.X, random_rate.Y); } - ThisPtr->RandomRateMin = std::clamp(random_rate.X, 0, random_rate.X); - ThisPtr->RandomRateMax = std::clamp(random_rate.Y, 0, random_rate.Y); + This()->RandomRateMin = std::clamp(random_rate.X, 0, random_rate.X); + This()->RandomRateMax = std::clamp(random_rate.Y, 0, random_rate.Y); /** * #issue-646 @@ -216,7 +225,7 @@ bool AnimTypeClassExtension::Read_INI(CCINIClass &ini) * of range and as a result do not play in-game. This makes sure the values * are never outside of the expected range. */ - ThisPtr->DetailLevel = std::clamp(ThisPtr->DetailLevel, 0, 2); + This()->DetailLevel = std::clamp(This()->DetailLevel, 0, 2); IsHideIfNotTiberium = ini.Get_Bool(ini_name, "HideIfNoTiberium", IsHideIfNotTiberium); IsForceBigCraters = ini.Get_Bool(ini_name, "ForceBigCraters", IsForceBigCraters); diff --git a/src/extensions/animtype/animtypeext.h b/src/extensions/animtype/animtypeext.h index ec72cde1..3f8ae31d 100644 --- a/src/extensions/animtype/animtypeext.h +++ b/src/extensions/animtype/animtypeext.h @@ -27,30 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "objecttypeext.h" +#include "animtype.h" -class AnimTypeClass; -class CCINIClass; -class ParticleTypeClass; +class DECLSPEC_UUID(UUID_ANIMTYPE_EXTENSION) +AnimTypeClassExtension final : public ObjectTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class AnimTypeClassExtension final : public Extension -{ public: - AnimTypeClassExtension(AnimTypeClass *this_ptr); + AnimTypeClassExtension(const AnimTypeClass *this_ptr = nullptr); AnimTypeClassExtension(const NoInitClass &noinit); - ~AnimTypeClassExtension(); + virtual ~AnimTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual AnimTypeClass *This() const override { return reinterpret_cast(ObjectTypeClassExtension::This()); } + virtual const AnimTypeClass *This_Const() const override { return reinterpret_cast(ObjectTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_ANIMTYPE; } + + virtual bool Read_INI(CCINIClass &ini) override; public: /** @@ -86,6 +95,3 @@ class AnimTypeClassExtension final : public Extension */ unsigned NumberOfParticles; }; - - -extern ExtensionMap AnimTypeClassExtensions; diff --git a/src/extensions/animtype/animtypeext_hooks.cpp b/src/extensions/animtype/animtypeext_hooks.cpp index 6828a6ee..339d5c85 100644 --- a/src/extensions/animtype/animtypeext_hooks.cpp +++ b/src/extensions/animtype/animtypeext_hooks.cpp @@ -34,6 +34,9 @@ #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patches in an assertion check for image data. diff --git a/src/extensions/animtype/animtypeext_init.cpp b/src/extensions/animtype/animtypeext_init.cpp index 801f6c2a..46b6f600 100644 --- a/src/extensions/animtype/animtypeext_init.cpp +++ b/src/extensions/animtype/animtypeext_init.cpp @@ -30,10 +30,15 @@ #include "animtype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,53 +51,28 @@ DECLARE_PATCH(_AnimTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(AnimTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0x10); // ini name. - static AnimTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating AnimTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = AnimTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create AnimTypeClassExtension instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create AnimTypeClassExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create AnimTypeClassExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_AnimTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(AnimTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. */ original_code: _asm { mov eax, this_ptr } + _asm { pop edi } _asm { pop esi } + _asm { pop ebx } _asm { ret 4 } } @@ -111,15 +91,14 @@ DECLARE_PATCH(_AnimTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - AnimTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x0080F588 } // NeuronClass vector .vtble + JMP_REG(eax, 0x004187F8); } @@ -137,125 +116,14 @@ DECLARE_PATCH(_AnimTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - AnimTypeClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_AnimTypeClass_Detach_Patch) -{ - GET_REGISTER_STATIC(AnimTypeClass *, this_ptr, ecx); - GET_STACK_STATIC(TARGET, target, esp, 0x4); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static AnimTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = AnimTypeClassExtensions.find(this_ptr, false); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class detach. - */ - exttype_ptr->Detach(target, all); - - /** - * Stolen bytes here. - */ -original_code: - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_AnimTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(AnimTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static AnimTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = AnimTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_AnimTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(AnimTypeClass *, this_ptr, esi); - GET_REGISTER_STATIC(CCINIClass *, ini, ebx); - static AnimTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = AnimTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { mov al, 1 } - _asm { pop esi } - _asm { pop ebx } - _asm { add esp, 0x90 } - _asm { ret 4 } + _asm { mov edx, ds:0x0080F588 } // NeuronClass vector .vtble + JMP_REG(eax, 0x00419C28); } @@ -265,10 +133,6 @@ DECLARE_PATCH(_AnimTypeClass_Read_INI_Patch) void AnimTypeClassExtension_Init() { Patch_Jump(0x00418798, &_AnimTypeClass_Constructor_Patch); - Patch_Jump(0x004187BA, &_AnimTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x0041888B, &_AnimTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x00419CCB, &_AnimTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x00419A18, &_AnimTypeClass_Detach_Patch); - Patch_Jump(0x00419963, &_AnimTypeClass_Compute_CRC_Patch); - Patch_Jump(0x00419624, &_AnimTypeClass_Read_INI_Patch); + //Patch_Jump(0x004187DB, &_AnimTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x00419C22, &_AnimTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/building/buildingext.cpp b/src/extensions/building/buildingext.cpp index 9812ed93..c2de93d1 100644 --- a/src/extensions/building/buildingext.cpp +++ b/src/extensions/building/buildingext.cpp @@ -32,33 +32,26 @@ #include "house.h" #include "housetype.h" #include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all BuildingClass extension instances. - */ -ExtensionMap BuildingClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -BuildingClassExtension::BuildingClassExtension(BuildingClass *this_ptr) : - Extension(this_ptr), +BuildingClassExtension::BuildingClassExtension(const BuildingClass *this_ptr) : + TechnoClassExtension(this_ptr), ProduceCashTimer(), CurrentProduceCashBudget(-1), IsCaptureOneTimeCashGiven(false), IsBudgetDepleted(false) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("BuildingClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("BuildingClassExtension::BuildingClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + BuildingExtensions.Add(this); } @@ -68,9 +61,9 @@ BuildingClassExtension::BuildingClassExtension(BuildingClass *this_ptr) : * @author: CCHyper */ BuildingClassExtension::BuildingClassExtension(const NoInitClass &noinit) : - Extension(noinit) + TechnoClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("BuildingClassExtension::BuildingClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -81,10 +74,28 @@ BuildingClassExtension::BuildingClassExtension(const NoInitClass &noinit) : */ BuildingClassExtension::~BuildingClassExtension() { - //EXT_DEBUG_TRACE("BuildingClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("BuildingClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingClassExtension::~BuildingClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + BuildingExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT BuildingClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("BuildingClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -95,10 +106,9 @@ BuildingClassExtension::~BuildingClassExtension() */ HRESULT BuildingClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = TechnoClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -116,10 +126,9 @@ HRESULT BuildingClassExtension::Load(IStream *pStm) */ HRESULT BuildingClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = TechnoClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -135,8 +144,7 @@ HRESULT BuildingClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int BuildingClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -149,8 +157,7 @@ int BuildingClassExtension::Size_Of() const */ void BuildingClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -161,8 +168,7 @@ void BuildingClassExtension::Detach(TARGET target, bool all) */ void BuildingClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); /** * #issue-26 @@ -181,16 +187,15 @@ void BuildingClassExtension::Compute_CRC(WWCRCEngine &crc) const */ void BuildingClassExtension::Produce_Cash_AI() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingClassExtension::Produce_Cash_AI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingClassExtension::Produce_Cash_AI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + const BuildingClass *this_building = reinterpret_cast(This()); + const BuildingTypeClass *this_buildingtype = reinterpret_cast(This()->Class_Of()); /** - * Find the type class extension instance. + * Fetch the extension instance. */ - BuildingTypeClassExtension *buildingtypeext = BuildingTypeClassExtensions.find(ThisPtr->Class); - if (!buildingtypeext) { - return; - } + BuildingTypeClassExtension *buildingtypeext = Extension::Fetch(this_buildingtype); #if 0 /** @@ -198,7 +203,7 @@ void BuildingClassExtension::Produce_Cash_AI() * * Only updates player owned buildings. */ - if (ThisPtr->House != PlayerPtr) { + if (This()->House != PlayerPtr) { return; } #endif @@ -211,19 +216,19 @@ void BuildingClassExtension::Produce_Cash_AI() /** * Check if this building requires power to produce cash. */ - if (reinterpret_cast(ThisPtr->Class_Of())->IsPowered) { + if (this_buildingtype->IsPowered) { /** * Stop the timer if the building is offline or has low power. */ - if (ProduceCashTimer.Is_Active() && !ThisPtr->Is_Powered_On()) { + if (ProduceCashTimer.Is_Active() && !This()->Is_Powered_On()) { ProduceCashTimer.Stop(); } /** * Restart the timer is if it previously stopped due to low power or is offline. */ - if (!ProduceCashTimer.Is_Active() && ThisPtr->Is_Powered_On()) { + if (!ProduceCashTimer.Is_Active() && This()->Is_Powered_On()) { ProduceCashTimer.Start(); } @@ -237,7 +242,7 @@ void BuildingClassExtension::Produce_Cash_AI() /** * Is the owner a passive house? If so, they should not be receiving cash. */ - if (!ThisPtr->House->Class->IsMultiplayPassive) { + if (!This()->House->Class->IsMultiplayPassive) { int amount = buildingtypeext->ProduceCashAmount; @@ -268,9 +273,9 @@ void BuildingClassExtension::Produce_Cash_AI() */ if (!IsBudgetDepleted && amount != 0) { if (amount < 0) { - ThisPtr->House->Spend_Money(std::abs(amount)); + This()->House->Spend_Money(std::abs(amount)); } else { - ThisPtr->House->Refund_Money(amount); + This()->House->Refund_Money(amount); } } diff --git a/src/extensions/building/buildingext.h b/src/extensions/building/buildingext.h index 2c90afaa..2b05613a 100644 --- a/src/extensions/building/buildingext.h +++ b/src/extensions/building/buildingext.h @@ -27,9 +27,8 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" - +#include "technoext.h" +#include "building.h" #include "ttimer.h" #include "ftimer.h" @@ -38,20 +37,34 @@ class BuildingClass; class HouseClass; -class BuildingClassExtension final : public Extension +class DECLSPEC_UUID(UUID_BUILDING_EXTENSION) +BuildingClassExtension final : public TechnoClassExtension { public: - BuildingClassExtension(BuildingClass *this_ptr); + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + BuildingClassExtension(const BuildingClass *this_ptr = nullptr); BuildingClassExtension(const NoInitClass &noinit); - ~BuildingClassExtension(); + virtual ~BuildingClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + virtual BuildingClass *This() const override { return reinterpret_cast(TechnoClassExtension::This()); } + virtual const BuildingClass *This_Const() const override { return reinterpret_cast(TechnoClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_BUILDING; } + void Produce_Cash_AI(); public: @@ -75,6 +88,3 @@ class BuildingClassExtension final : public Extension */ bool IsBudgetDepleted; }; - - -extern ExtensionMap BuildingClassExtensions; diff --git a/src/extensions/building/buildingext_hooks.cpp b/src/extensions/building/buildingext_hooks.cpp index de0b879b..20443ddf 100644 --- a/src/extensions/building/buildingext_hooks.cpp +++ b/src/extensions/building/buildingext_hooks.cpp @@ -47,6 +47,7 @@ #include "voc.h" #include "iomap.h" #include "spritecollection.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" @@ -68,12 +69,11 @@ DECLARE_PATCH(_BuildingClass_AI_ProduceCash_Patch) static BuildingClassExtension *ext_ptr; /** - * Find the extension instances. + * Fetch the extension instance. */ - ext_ptr = BuildingClassExtensions.find(this_ptr); - if (ext_ptr) { - ext_ptr->Produce_Cash_AI(); - } + ext_ptr = Extension::Fetch(this_ptr); + + ext_ptr->Produce_Cash_AI(); /** * Stolen bytes/code here. @@ -104,13 +104,10 @@ DECLARE_PATCH(_BuildingClass_Captured_ProduceCash_Patch) static BuildingTypeClassExtension *exttype_ptr; /** - * Find the extension instances. + * Fetch the extension instances. */ - ext_ptr = BuildingClassExtensions.find(this_ptr); - exttype_ptr = BuildingTypeClassExtensions.find(this_ptr->Class); - if (!ext_ptr || !exttype_ptr) { - goto original_code; - } + ext_ptr = Extension::Fetch(this_ptr); + exttype_ptr = Extension::Fetch(this_ptr->Class); /** * Is the owner a passive/neutral house? Only they can provide the capture bonus. @@ -192,13 +189,10 @@ DECLARE_PATCH(_BuildingClass_Grand_Opening_ProduceCash_Patch) } /** - * Find the extension instances. + * Fetch the extension instances. */ - ext_ptr = BuildingClassExtensions.find(this_ptr); - exttype_ptr = BuildingTypeClassExtensions.find(this_ptr->Class); - if (!ext_ptr || !exttype_ptr) { - goto continue_function; - } + ext_ptr = Extension::Fetch(this_ptr); + exttype_ptr = Extension::Fetch(this_ptr->Class); /** * Start the cash delay timer. @@ -256,17 +250,15 @@ DECLARE_PATCH(_BuildingClass_Mission_Open_Gate_Open_Sound_Patch) voc = Rule->GateDownSound; /** - * Fetch the class extension if it exists. + * Fetch the extension instance. */ - buildingtypeext = BuildingTypeClassExtensions.find(buildingtype); - if (buildingtypeext) { + buildingtypeext = Extension::Fetch(buildingtype); - /** - * Does this building have a custom gate lowering sound? If so, use it. - */ - if (buildingtypeext->GateDownSound != VOC_NONE) { - voc = buildingtypeext->GateDownSound; - } + /** + * Does this building have a custom gate lowering sound? If so, use it. + */ + if (buildingtypeext->GateDownSound != VOC_NONE) { + voc = buildingtypeext->GateDownSound; } /** @@ -293,17 +285,15 @@ DECLARE_PATCH(_BuildingClass_Mission_Open_Gate_Close_Sound_Patch) voc = Rule->GateUpSound; /** - * Fetch the class extension if it exists. + * Fetch the extension instance. */ - buildingtypeext = BuildingTypeClassExtensions.find(buildingtype); - if (buildingtypeext) { + buildingtypeext = Extension::Fetch(buildingtype); - /** - * Does this building have a custom gate rising sound? If so, use it. - */ - if (buildingtypeext->GateUpSound != VOC_NONE) { - voc = buildingtypeext->GateUpSound; - } + /** + * Does this building have a custom gate rising sound? If so, use it. + */ + if (buildingtypeext->GateUpSound != VOC_NONE) { + voc = buildingtypeext->GateUpSound; } /** @@ -328,14 +318,12 @@ DECLARE_PATCH(_BuildingClass_Mission_Open_Gate_Close_Sound_Patch) */ static void BuildingClass_Shake_Screen(BuildingClass *building) { - TechnoTypeClass *technotype; - TechnoTypeClassExtension *technotypeext; + BuildingTypeClassExtension *buildingtypeext; /** - * Fetch the extended techno type instance if it exists. + * Fetch the extension instance. */ - technotype = building->Techno_Type_Class(); - technotypeext = TechnoTypeClassExtensions.find(technotype); + buildingtypeext = Extension::Fetch(building->Techno_Type_Class()); /** * #issue-414 @@ -344,20 +332,20 @@ static void BuildingClass_Shake_Screen(BuildingClass *building) * * @author: CCHyper */ - if (technotypeext && technotypeext->IsShakeScreen) { + if (buildingtypeext->IsShakeScreen) { /** * If this building has screen shake values defined, then set the blitter * offset values. GScreenClass::Blit will handle the rest for us. */ - if ((technotypeext->ShakePixelXLo > 0 || technotypeext->ShakePixelXHi > 0) - || (technotypeext->ShakePixelYLo > 0 || technotypeext->ShakePixelYHi > 0)) { + if ((buildingtypeext->ShakePixelXLo > 0 || buildingtypeext->ShakePixelXHi > 0) + || (buildingtypeext->ShakePixelYLo > 0 || buildingtypeext->ShakePixelYHi > 0)) { - if (technotypeext->ShakePixelXLo > 0 || technotypeext->ShakePixelXHi > 0) { - Map.ScreenX = Sim_Random_Pick(technotypeext->ShakePixelXLo, technotypeext->ShakePixelXHi); + if (buildingtypeext->ShakePixelXLo > 0 || buildingtypeext->ShakePixelXHi > 0) { + Map.ScreenX = Sim_Random_Pick(buildingtypeext->ShakePixelXLo, buildingtypeext->ShakePixelXHi); } - if (technotypeext->ShakePixelYLo > 0 || technotypeext->ShakePixelYHi > 0) { - Map.ScreenY = Sim_Random_Pick(technotypeext->ShakePixelYLo, technotypeext->ShakePixelYHi); + if (buildingtypeext->ShakePixelYLo > 0 || buildingtypeext->ShakePixelYHi > 0) { + Map.ScreenY = Sim_Random_Pick(buildingtypeext->ShakePixelYLo, buildingtypeext->ShakePixelYHi); } } else { @@ -446,7 +434,7 @@ DECLARE_PATCH(_BuildingClass_Draw_Spied_Cameo_Palette_Patch) * * @author: CCHyper */ - technotypeext = TechnoTypeClassExtensions.find(technotype); + technotypeext = Extension::Fetch(technotype); if (technotypeext->CameoImageSurface) { /** diff --git a/src/extensions/building/buildingext_init.cpp b/src/extensions/building/buildingext_init.cpp index f5c54bf7..1a65e131 100644 --- a/src/extensions/building/buildingext_init.cpp +++ b/src/extensions/building/buildingext_init.cpp @@ -31,10 +31,15 @@ #include "buildingtype.h" #include "house.h" #include "housetype.h" +#include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" -#include "vinifera_util.h" + +#include "hooker.h" +#include "hooker_macros.h" /** @@ -47,150 +52,55 @@ DECLARE_PATCH(_BuildingClass_Constructor_Patch) { GET_REGISTER_STATIC(BuildingClass *, this_ptr, esi); // Current "this" pointer. - static BuildingClassExtension *exttype_ptr; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = BuildingClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create BuildingClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create BuildingClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create BuildingClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_BuildingClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(BuildingClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit, esp, 0x4); - static BuildingClassExtension *ext_ptr; + Extension::Make(this_ptr); /** * Stolen bytes here. */ original_code: _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the destruction process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_BuildingClass_Destructor_Patch) -{ - GET_REGISTER_STATIC(BuildingClass *, this_ptr, esi); - - /** - * Remove the extended class from the global index. - */ - BuildingClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: _asm { pop edi } _asm { pop esi } _asm { pop ebp } - _asm { pop ecx } - _asm { ret } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_BuildingClass_Detach_Patch) -{ - GET_REGISTER_STATIC(BuildingClass *, this_ptr, esi); - GET_STACK_STATIC(TARGET, target, esp, 0x10); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static BuildingClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = BuildingClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Detach(target, all); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } _asm { pop ebx } _asm { ret 8 } } /** - * Patch for including the extended class members to the base class crc calculation. + * Patch for including the extended class members in the destruction process. * * @warning: Do not touch this unless you know what you are doing! * * @author: CCHyper */ -DECLARE_PATCH(_BuildingClass_Compute_CRC_Patch) +DECLARE_PATCH(_BuildingClass_Destructor_Patch) { GET_REGISTER_STATIC(BuildingClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static BuildingClassExtension *ext_ptr; /** - * Find the extension instance. + * Remove the extended class from the global index. */ - ext_ptr = BuildingClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Compute_CRC(*crc); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } + _asm { mov edx, ds:0x007E4708 } // Buildings.vtble + JMP_REG(eax, 0x00426674); } @@ -200,8 +110,5 @@ DECLARE_PATCH(_BuildingClass_Compute_CRC_Patch) void BuildingClassExtension_Init() { Patch_Jump(0x00426615, &_BuildingClass_Constructor_Patch); - Patch_Jump(0x00426184, &_BuildingClass_NoInit_Constructor_Patch); - Patch_Jump(0x004268BB, &_BuildingClass_Destructor_Patch); - Patch_Jump(0x00433FA9, &_BuildingClass_Detach_Patch); - Patch_Jump(0x0043843D, &_BuildingClass_Compute_CRC_Patch); + Patch_Jump(0x0042666E, &_BuildingClass_Destructor_Patch); } diff --git a/src/extensions/buildingtype/buildingtypeext.cpp b/src/extensions/buildingtype/buildingtypeext.cpp index d34c6015..f24c01db 100644 --- a/src/extensions/buildingtype/buildingtypeext.cpp +++ b/src/extensions/buildingtype/buildingtypeext.cpp @@ -29,23 +29,19 @@ #include "buildingtype.h" #include "tibsun_defines.h" #include "ccini.h" +#include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all BuildingTypeClass extension instances. - */ -ExtensionMap BuildingTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -BuildingTypeClassExtension::BuildingTypeClassExtension(BuildingTypeClass *this_ptr) : - Extension(this_ptr), +BuildingTypeClassExtension::BuildingTypeClassExtension(const BuildingTypeClass *this_ptr) : + TechnoTypeClassExtension(this_ptr), GateUpSound(VOC_NONE), GateDownSound(VOC_NONE), ProduceCashStartup(0), @@ -56,11 +52,9 @@ BuildingTypeClassExtension::BuildingTypeClassExtension(BuildingTypeClass *this_p IsResetBudgetOnCapture(false), IsEligibleForAllyBuilding(false) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("BuildingTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("BuildingTypeClassExtension::BuildingTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + BuildingTypeExtensions.Add(this); } @@ -70,9 +64,9 @@ BuildingTypeClassExtension::BuildingTypeClassExtension(BuildingTypeClass *this_p * @author: CCHyper */ BuildingTypeClassExtension::BuildingTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + TechnoTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("BuildingTypeClassExtension::BuildingTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -83,10 +77,28 @@ BuildingTypeClassExtension::BuildingTypeClassExtension(const NoInitClass &noinit */ BuildingTypeClassExtension::~BuildingTypeClassExtension() { - //EXT_DEBUG_TRACE("BuildingTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("BuildingTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingTypeClassExtension::~BuildingTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + BuildingTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT BuildingTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("BuildingTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -97,10 +109,9 @@ BuildingTypeClassExtension::~BuildingTypeClassExtension() */ HRESULT BuildingTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = TechnoTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -118,10 +129,9 @@ HRESULT BuildingTypeClassExtension::Load(IStream *pStm) */ HRESULT BuildingTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = TechnoTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -137,8 +147,7 @@ HRESULT BuildingTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int BuildingTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -151,8 +160,7 @@ int BuildingTypeClassExtension::Size_Of() const */ void BuildingTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -163,8 +171,7 @@ void BuildingTypeClassExtension::Detach(TARGET target, bool all) */ void BuildingTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); crc(IsEligibleForAllyBuilding); } @@ -177,16 +184,14 @@ void BuildingTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool BuildingTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BuildingTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("BuildingTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BuildingTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - const char *ini_name = ThisPtr->Name(); - - if (!ini.Is_Present(ini_name)) { + if (!TechnoTypeClassExtension::Read_INI(ini)) { return false; } + const char *ini_name = Name(); + GateUpSound = ini.Get_VocType(ini_name, "GateUpSound", GateUpSound); GateDownSound = ini.Get_VocType(ini_name, "GateDownSound", GateDownSound); @@ -198,7 +203,7 @@ bool BuildingTypeClassExtension::Read_INI(CCINIClass &ini) IsResetBudgetOnCapture = ini.Get_Bool(ini_name, "ProduceCashResetOnCapture", IsResetBudgetOnCapture); IsEligibleForAllyBuilding = ini.Get_Bool(ini_name, "EligibleForAllyBuilding", - ThisPtr->IsConstructionYard ? true : IsEligibleForAllyBuilding); + This()->IsConstructionYard ? true : IsEligibleForAllyBuilding); return true; } diff --git a/src/extensions/buildingtype/buildingtypeext.h b/src/extensions/buildingtype/buildingtypeext.h index 63e2b38c..b3e79ae4 100644 --- a/src/extensions/buildingtype/buildingtypeext.h +++ b/src/extensions/buildingtype/buildingtypeext.h @@ -27,29 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "technotypeext.h" +#include "buildingtype.h" -class BuildingTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_BUILDINGTYPE_EXTENSION) +BuildingTypeClassExtension final : public TechnoTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class BuildingTypeClassExtension final : public Extension -{ public: - BuildingTypeClassExtension(BuildingTypeClass *this_ptr); + BuildingTypeClassExtension(const BuildingTypeClass *this_ptr = nullptr); BuildingTypeClassExtension(const NoInitClass &noinit); - ~BuildingTypeClassExtension(); + virtual ~BuildingTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual BuildingTypeClass *This() const override { return reinterpret_cast(TechnoTypeClassExtension::This()); } + virtual const BuildingTypeClass *This_Const() const override { return reinterpret_cast(TechnoTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_BUILDINGTYPE; } + + virtual bool Read_INI(CCINIClass &ini) override; public: /** @@ -97,6 +107,3 @@ class BuildingTypeClassExtension final : public Extension */ bool IsEligibleForAllyBuilding; }; - - -extern ExtensionMap BuildingTypeClassExtensions; diff --git a/src/extensions/buildingtype/buildingtypeext_hooks.cpp b/src/extensions/buildingtype/buildingtypeext_hooks.cpp index ce43d97a..65f85027 100644 --- a/src/extensions/buildingtype/buildingtypeext_hooks.cpp +++ b/src/extensions/buildingtype/buildingtypeext_hooks.cpp @@ -33,6 +33,9 @@ #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patches in an assertion check for image data. diff --git a/src/extensions/buildingtype/buildingtypeext_init.cpp b/src/extensions/buildingtype/buildingtypeext_init.cpp index cc6ba6b3..82624df6 100644 --- a/src/extensions/buildingtype/buildingtypeext_init.cpp +++ b/src/extensions/buildingtype/buildingtypeext_init.cpp @@ -30,10 +30,15 @@ #include "buildingtype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,54 +51,29 @@ DECLARE_PATCH(_BuildingTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(BuildingTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0x4); // ini name. - static BuildingTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating BuildingTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = BuildingTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create BuildingTypeClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create BuildingTypeClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create BuildingTypeClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_BuildingTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(BuildingTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. */ original_code: _asm { mov eax, this_ptr } + _asm { pop edi } _asm { pop esi } + _asm { pop ebp } + _asm { pop ebx } _asm { ret 4 } } @@ -112,15 +92,14 @@ DECLARE_PATCH(_BuildingTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - BuildingTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007E21A0 } // BuildingTypes.vtble + JMP_REG(eax, 0x0043F958); } @@ -138,91 +117,14 @@ DECLARE_PATCH(_BuildingTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - BuildingTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_BuildingTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(BuildingTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static BuildingTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = BuildingTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_BuildingTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(BuildingTypeClass *, this_ptr, ebp); - GET_STACK_STATIC(CCINIClass *, ini, esp, 0x32C); // Can't use ESI as its reused by this point. - static BuildingTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = BuildingTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov al, 1 } - _asm { pop edi } - _asm { pop ebx } - _asm { pop esi } - _asm { pop ebp } - _asm { add esp, 0x318 } - _asm { ret 4 } + _asm { mov edx, ds:0x007E21A0 } // BuildingTypes.vtble + JMP_REG(eax, 0x00444088); } @@ -232,9 +134,6 @@ DECLARE_PATCH(_BuildingTypeClass_Read_INI_Patch) void BuildingTypeClassExtension_Init() { Patch_Jump(0x0043F8B1, &_BuildingTypeClass_Constructor_Patch); - Patch_Jump(0x0043F8E4, &_BuildingTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x0043F9A2, &_BuildingTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x004440E2, &_BuildingTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x00443349, &_BuildingTypeClass_Compute_CRC_Patch); - Patch_Jump(0x00442E29, &_BuildingTypeClass_Read_INI_Patch); + //Patch_Jump(0x0043F952, &_BuildingTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x00444082, &_BuildingTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/bullet/bulletext_hooks.cpp b/src/extensions/bullet/bulletext_hooks.cpp index e1585520..a230a9c0 100644 --- a/src/extensions/bullet/bulletext_hooks.cpp +++ b/src/extensions/bullet/bulletext_hooks.cpp @@ -32,6 +32,7 @@ #include "warheadtype.h" #include "warheadtypeext.h" #include "iomap.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" @@ -53,22 +54,14 @@ DECLARE_PATCH(_BulletClass_AI_SpawnDelay_Patch) static BulletTypeClassExtension *bullettypeext; /** - * Find the extended bullet type data. + * Fetch the extension instance. */ - bullettypeext = BulletTypeClassExtensions.find(this_ptr->Class); + bullettypeext = Extension::Fetch(this_ptr->Class); /** - * If this bullet has a custom spawn delay, perform that check first. + * If this bullet has a custom spawn delay (defaults to the original delay of 3), perform that check first. */ - if (bullettypeext) { - if ((Frame % bullettypeext->SpawnDelay) == 0) { - goto create_trailer_anim; - } - - /** - * Original case, hardcoded delay of 3. - */ - } else if ((Frame % 3) == 0) { + if ((Frame % bullettypeext->SpawnDelay) == 0) { goto create_trailer_anim; } @@ -95,21 +88,19 @@ DECLARE_PATCH(_BulletClass_Logic_ShakeScreen_Patch) static WarheadTypeClassExtension *warheadext; /** - * Fetch the extended warhead type instance if it exists. + * Fetch the extension instance. */ - warheadext = WarheadTypeClassExtensions.find(warhead); - if (warheadext) { + warheadext = Extension::Fetch(warhead); - /** - * If this warhead has screen shake values defined, then set the blitter - * offset values. GScreenClass::Blit will handle the rest for us. - */ - if (warheadext->ShakePixelXLo > 0 || warheadext->ShakePixelXHi > 0) { - Map.ScreenX = Sim_Random_Pick(warheadext->ShakePixelXLo, warheadext->ShakePixelXHi); - } - if (warheadext->ShakePixelYLo > 0 || warheadext->ShakePixelYHi > 0) { - Map.ScreenY = Sim_Random_Pick(warheadext->ShakePixelYLo, warheadext->ShakePixelYHi); - } + /** + * If this warhead has screen shake values defined, then set the blitter + * offset values. GScreenClass::Blit will handle the rest for us. + */ + if (warheadext->ShakePixelXLo > 0 || warheadext->ShakePixelXHi > 0) { + Map.ScreenX = Sim_Random_Pick(warheadext->ShakePixelXLo, warheadext->ShakePixelXHi); + } + if (warheadext->ShakePixelYLo > 0 || warheadext->ShakePixelYHi > 0) { + Map.ScreenY = Sim_Random_Pick(warheadext->ShakePixelYLo, warheadext->ShakePixelYHi); } /** diff --git a/src/extensions/bullettype/bullettypeext.cpp b/src/extensions/bullettype/bullettypeext.cpp index 059e8f92..394e5d77 100644 --- a/src/extensions/bullettype/bullettypeext.cpp +++ b/src/extensions/bullettype/bullettypeext.cpp @@ -27,31 +27,25 @@ ******************************************************************************/ #include "bullettypeext.h" #include "bullettype.h" +#include "tibsun_globals.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all BulletTypeClass extension instances. - */ -ExtensionMap BulletTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -BulletTypeClassExtension::BulletTypeClassExtension(BulletTypeClass *this_ptr) : - Extension(this_ptr), +BulletTypeClassExtension::BulletTypeClassExtension(const BulletTypeClass *this_ptr) : + ObjectTypeClassExtension(this_ptr), SpawnDelay(3) // Default hardcoded value. { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BulletTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("BulletTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("BulletTypeClassExtension::BulletTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + BulletTypeExtensions.Add(this); } @@ -61,9 +55,9 @@ BulletTypeClassExtension::BulletTypeClassExtension(BulletTypeClass *this_ptr) : * @author: CCHyper */ BulletTypeClassExtension::BulletTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("BulletTypeClassExtension::BulletTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -74,10 +68,28 @@ BulletTypeClassExtension::BulletTypeClassExtension(const NoInitClass &noinit) : */ BulletTypeClassExtension::~BulletTypeClassExtension() { - //EXT_DEBUG_TRACE("BulletTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("BulletTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BulletTypeClassExtension::~BulletTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + BulletTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT BulletTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("BulletTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } - IsInitialized = false; + *lpClassID = __uuidof(this); + + return S_OK; } @@ -88,10 +100,9 @@ BulletTypeClassExtension::~BulletTypeClassExtension() */ HRESULT BulletTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BulletTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BulletTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -109,10 +120,9 @@ HRESULT BulletTypeClassExtension::Load(IStream *pStm) */ HRESULT BulletTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BulletTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BulletTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -128,8 +138,7 @@ HRESULT BulletTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int BulletTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BulletTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BulletTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -142,8 +151,7 @@ int BulletTypeClassExtension::Size_Of() const */ void BulletTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BulletTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BulletTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -154,8 +162,7 @@ void BulletTypeClassExtension::Detach(TARGET target, bool all) */ void BulletTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BulletTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BulletTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -166,17 +173,18 @@ void BulletTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool BulletTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("BulletTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("BulletTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("BulletTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - const char *ini_name = ThisPtr->Name(); + if (!AbstractTypeClassExtension::Read_INI(ini)) { + return false; + } + + const char *ini_name = Name(); + const char *graphic_name = Graphic_Name(); if (!ini.Is_Present(ini_name)) { return false; } - - const char *graphic_name = ThisPtr->Graphic_Name(); //if (!ArtINI.Is_Present(graphic_name)) { // return false; diff --git a/src/extensions/bullettype/bullettypeext.h b/src/extensions/bullettype/bullettypeext.h index 057c7641..80c70943 100644 --- a/src/extensions/bullettype/bullettypeext.h +++ b/src/extensions/bullettype/bullettypeext.h @@ -27,29 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "objecttypeext.h" +#include "bullettype.h" -class BulletTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_BULLETTYPE_EXTENSION) +BulletTypeClassExtension final : public ObjectTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class BulletTypeClassExtension final : public Extension -{ public: - BulletTypeClassExtension(BulletTypeClass *this_ptr); + BulletTypeClassExtension(const BulletTypeClass *this_ptr = nullptr); BulletTypeClassExtension(const NoInitClass &noinit); - ~BulletTypeClassExtension(); + virtual ~BulletTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + + virtual BulletTypeClass *This() const override { return reinterpret_cast(ObjectTypeClassExtension::This()); } + virtual const BulletTypeClass *This_Const() const override { return reinterpret_cast(ObjectTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_BULLETTYPE; } - bool Read_INI(CCINIClass &ini); + virtual bool Read_INI(CCINIClass &ini) override; public: /** @@ -57,6 +67,3 @@ class BulletTypeClassExtension final : public Extension */ unsigned SpawnDelay; }; - - -extern ExtensionMap BulletTypeClassExtensions; diff --git a/src/extensions/bullettype/bullettypeext_init.cpp b/src/extensions/bullettype/bullettypeext_init.cpp index 9dcb7263..a9f401e3 100644 --- a/src/extensions/bullettype/bullettypeext_init.cpp +++ b/src/extensions/bullettype/bullettypeext_init.cpp @@ -30,10 +30,15 @@ #include "bullettype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,45 +51,19 @@ DECLARE_PATCH(_BulletTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(BulletTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0xC); // ini name. - static BulletTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating BulletTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = BulletTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create BulletTypeClassExtension instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create BulletTypeClassExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create BulletTypeClassExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_BulletTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(BulletTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. @@ -92,6 +71,7 @@ DECLARE_PATCH(_BulletTypeClass_NoInit_Constructor_Patch) original_code: _asm { mov eax, this_ptr } _asm { pop esi } + _asm { pop ebx } _asm { ret 4 } } @@ -110,15 +90,14 @@ DECLARE_PATCH(_BulletTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - BulletTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007E21B8 } // BulletTypes.vtble + JMP_REG(eax, 0x00447E17); } @@ -136,125 +115,14 @@ DECLARE_PATCH(_BulletTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - BulletTypeClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_BulletTypeClass_Detach_Patch) -{ - GET_REGISTER_STATIC(BulletTypeClass *, this_ptr, esi); - GET_STACK_STATIC(TARGET, target, esp, 0x4); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static BulletTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = BulletTypeClassExtensions.find(this_ptr, false); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class detach. - */ - exttype_ptr->Detach(target, all); - - /** - * Stolen bytes here. - */ -original_code: - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_BulletTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(BulletTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static BulletTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = BulletTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_BulletTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(BulletTypeClass *, this_ptr, esi); - GET_REGISTER_STATIC(CCINIClass *, ini, ebx); - static BulletTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = BulletTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov al, 1 } - _asm { pop esi } - _asm { pop ebx } - _asm { add esp, 0x84 } - _asm { ret 4 } + _asm { mov edx, ds:0x007E21B8 } // BulletTypes.vtble + JMP_REG(eax, 0x00448777); } @@ -264,10 +132,6 @@ DECLARE_PATCH(_BulletTypeClass_Read_INI_Patch) void BulletTypeClassExtension_Init() { Patch_Jump(0x00447D86, &_BulletTypeClass_Constructor_Patch); - Patch_Jump(0x00447DAA, &_BulletTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x00447E61, &_BulletTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x004487D1, &_BulletTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x004486B8, &_BulletTypeClass_Detach_Patch); - Patch_Jump(0x004484DD, &_BulletTypeClass_Compute_CRC_Patch); - Patch_Jump(0x00448275, &_BulletTypeClass_Read_INI_Patch); + //Patch_Jump(0x00447E11, &_BulletTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x00448771, &_BulletTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/campaign/campaignext.cpp b/src/extensions/campaign/campaignext.cpp index ae0aa446..8071f358 100644 --- a/src/extensions/campaign/campaignext.cpp +++ b/src/extensions/campaign/campaignext.cpp @@ -28,31 +28,24 @@ #include "campaignext.h" #include "campaign.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all CampaignClass extension instances. - */ -ExtensionMap CampaignClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -CampaignClassExtension::CampaignClassExtension(CampaignClass *this_ptr) : - Extension(this_ptr), +CampaignClassExtension::CampaignClassExtension(const CampaignClass *this_ptr) : + AbstractTypeClassExtension(this_ptr), IsDebugOnly(false), IntroMovie() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("CampaignClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("CampaignClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("CampaignClassExtension::CampaignClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + CampaignExtensions.Add(this); } @@ -62,9 +55,9 @@ CampaignClassExtension::CampaignClassExtension(CampaignClass *this_ptr) : * @author: CCHyper */ CampaignClassExtension::CampaignClassExtension(const NoInitClass &noinit) : - Extension(noinit) + AbstractTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("CampaignClassExtension::CampaignClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -75,10 +68,28 @@ CampaignClassExtension::CampaignClassExtension(const NoInitClass &noinit) : */ CampaignClassExtension::~CampaignClassExtension() { - //EXT_DEBUG_TRACE("CampaignClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("CampaignClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("CampaignClassExtension::~CampaignClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + CampaignExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT CampaignClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("CampaignClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -89,10 +100,9 @@ CampaignClassExtension::~CampaignClassExtension() */ HRESULT CampaignClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("CampaignClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("CampaignClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = AbstractTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -110,10 +120,9 @@ HRESULT CampaignClassExtension::Load(IStream *pStm) */ HRESULT CampaignClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("CampaignClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("CampaignClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = AbstractTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -129,8 +138,7 @@ HRESULT CampaignClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int CampaignClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("CampaignClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("CampaignClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -143,8 +151,7 @@ int CampaignClassExtension::Size_Of() const */ void CampaignClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("CampaignClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("CampaignClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -155,8 +162,7 @@ void CampaignClassExtension::Detach(TARGET target, bool all) */ void CampaignClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("CampaignClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("CampaignClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -167,16 +173,14 @@ void CampaignClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool CampaignClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("CampaignClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("CampaignClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("CampaignClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - const char *ini_name = ThisPtr->Name(); - - if (!ini.Is_Present(ini_name)) { + if (!AbstractTypeClassExtension::Read_INI(ini)) { return false; } + const char *ini_name = Name(); + IsDebugOnly = ini.Get_Bool(ini_name, "DebugOnly", IsDebugOnly); /** @@ -184,8 +188,8 @@ bool CampaignClassExtension::Read_INI(CCINIClass &ini) */ if (IsDebugOnly) { char buffer[128]; - std::strncpy(buffer, ThisPtr->Description, sizeof(buffer)); - std::snprintf(ThisPtr->Description, sizeof(ThisPtr->Description), "[Debug] - %s", buffer); + std::strncpy(buffer, This()->Description, sizeof(buffer)); + std::snprintf(This()->Description, sizeof(This()->Description), "[Debug] - %s", buffer); } ini.Get_String(ini_name, "IntroMovie", IntroMovie, sizeof(IntroMovie)); diff --git a/src/extensions/campaign/campaignext.h b/src/extensions/campaign/campaignext.h index 7a10a2f4..bbc0195b 100644 --- a/src/extensions/campaign/campaignext.h +++ b/src/extensions/campaign/campaignext.h @@ -27,29 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "abstracttypeext.h" +#include "campaign.h" -class CampaignClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_CAMPAIGN_EXTENSION) +CampaignClassExtension final : public AbstractTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class CampaignClassExtension final : public Extension -{ public: - CampaignClassExtension(CampaignClass *this_ptr); + CampaignClassExtension(const CampaignClass *this_ptr = nullptr); CampaignClassExtension(const NoInitClass &noinit); - ~CampaignClassExtension(); + virtual ~CampaignClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual CampaignClass *This() const override { return reinterpret_cast(AbstractTypeClassExtension::This()); } + virtual const CampaignClass *This_Const() const override { return reinterpret_cast(AbstractTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_CAMPAIGN; } + + virtual bool Read_INI(CCINIClass &ini) override; public: /** @@ -62,6 +72,3 @@ class CampaignClassExtension final : public Extension */ char IntroMovie[64]; }; - - -extern ExtensionMap CampaignClassExtensions; diff --git a/src/extensions/campaign/campaignext_hooks.cpp b/src/extensions/campaign/campaignext_hooks.cpp index fcb90551..921f1a32 100644 --- a/src/extensions/campaign/campaignext_hooks.cpp +++ b/src/extensions/campaign/campaignext_hooks.cpp @@ -30,10 +30,14 @@ #include "campaign.h" #include "campaignext.h" #include "addon.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * #issue-723 @@ -48,17 +52,15 @@ DECLARE_PATCH(_Choose_Campaign_Debug_Only_Patch) GET_REGISTER_STATIC(int, index, edi); static CampaignClassExtension *campaignext; - campaignext = CampaignClassExtensions.find(campaign); + campaignext = Extension::Fetch(campaign); /** * Is this a debug campaign? Make sure the developer mode is enabled * first before allowing it to continue availability checks. */ - if (campaignext) { - if (campaignext->IsDebugOnly && !Vinifera_DeveloperMode) { - DEBUG_INFO(" Skipping Debug-Only Campaign [%d] - %s\n", index, campaign->Description); - goto skip_no_print; - } + if (campaignext->IsDebugOnly && !Vinifera_DeveloperMode) { + DEBUG_INFO(" Skipping Debug-Only Campaign [%d] - %s\n", index, campaign->Description); + goto skip_no_print; } /** diff --git a/src/extensions/campaign/campaignext_init.cpp b/src/extensions/campaign/campaignext_init.cpp index 485a331b..69828ccd 100644 --- a/src/extensions/campaign/campaignext_init.cpp +++ b/src/extensions/campaign/campaignext_init.cpp @@ -30,10 +30,15 @@ #include "campaign.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,22 +51,22 @@ DECLARE_PATCH(_CampaignClass_Constructor_Patch) { GET_REGISTER_STATIC(CampaignClass *, this_ptr, ebp); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0x10); // ini name. - static CampaignClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating CampaignClassExtension instance for \"%s\".\n", ini_name); + // Campaign's are not saved to file, so this case is not required. +#if 0 /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = CampaignClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create CampaignClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create CampaignClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create CampaignClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } +#endif + + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); /** * Stolen bytes here. @@ -89,15 +94,14 @@ DECLARE_PATCH(_CampaignClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - CampaignClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007E2230 } // Campaigns.vtble + JMP_REG(eax, 0x00448AEE); } @@ -137,52 +141,14 @@ DECLARE_PATCH(_CampaignClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - CampaignClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_CampaignClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(CampaignClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static CampaignClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = CampaignClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } + _asm { mov edx, ds:0x007E2230 } // Campaigns.vtble + JMP_REG(eax, 0x00448EFE); } @@ -206,12 +172,9 @@ DECLARE_PATCH(_CampaignClass_Read_INI_Patch) this_ptr->RequiredAddon = (AddonType)required_addon; /** - * Find the extension instance. + * Fetch the extension instance. */ - exttype_ptr = CampaignClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } + exttype_ptr = Extension::Fetch(this_ptr); /** * Read type class ini. @@ -234,9 +197,8 @@ DECLARE_PATCH(_CampaignClass_Read_INI_Patch) void CampaignClassExtension_Init() { Patch_Jump(0x00448AC4, &_CampaignClass_Constructor_Patch); - //Patch_Jump(0x00448B38, &_CampaignClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + //Patch_Jump(0x00448AE8, &_CampaignClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! Patch_Jump(0x00448CD0, &_CampaignClass_Process_Patch); // Constructor is also inlined in CampaignClass::Process! - Patch_Jump(0x00448F58, &_CampaignClass_Scalar_Destructor_Patch); - Patch_Jump(0x00448E4E, &_CampaignClass_Compute_CRC_Patch); + Patch_Jump(0x00448EF8, &_CampaignClass_Scalar_Destructor_Patch); Patch_Jump(0x00448C17, &_CampaignClass_Read_INI_Patch); } diff --git a/src/extensions/ccfile/ccfileext_hooks.cpp b/src/extensions/ccfile/ccfileext_hooks.cpp index 8be3c646..3711d3df 100644 --- a/src/extensions/ccfile/ccfileext_hooks.cpp +++ b/src/extensions/ccfile/ccfileext_hooks.cpp @@ -43,7 +43,7 @@ * @note: This must not contain a constructor or destructor! * @note: All functions must be prefixed with "_" to prevent accidental virtualization. */ -class CCFileClassFake final : public CCFileClass +class CCFileClassExt final : public CCFileClass { public: void _Error(FileErrorType error, bool can_retry = false, const char *filename = nullptr); @@ -56,7 +56,7 @@ class CCFileClassFake final : public CCFileClass * @author: 10/17/1994 JLB - Red Alert source code. * CCHyper - Adjustments for Tiberian Sun, minor bug fix. */ -void CCFileClassFake::_Error(FileErrorType error, bool can_retry, const char *filename) +void CCFileClassExt::_Error(FileErrorType error, bool can_retry, const char *filename) { /** * File system is failled as local, no need to check if required cd is available. @@ -90,5 +90,5 @@ void CCFileClassFake::_Error(FileErrorType error, bool can_retry, const char *fi */ void CCFileClassExtension_Hooks() { - Patch_Jump(0x00449820, &CCFileClassFake::_Error); + Patch_Jump(0x00449820, &CCFileClassExt::_Error); } diff --git a/src/extensions/ccini/cciniext_hooks.cpp b/src/extensions/ccini/cciniext_hooks.cpp index ddbef85f..d1c4ab5b 100644 --- a/src/extensions/ccini/cciniext_hooks.cpp +++ b/src/extensions/ccini/cciniext_hooks.cpp @@ -48,7 +48,7 @@ * @note: This must not contain a constructor or destructor! * @note: All functions must be prefixed with "_" to prevent accidental virtualization. */ -static class CCINIClassFake final : public CCINIClass +static class CCINIClassExt final : public CCINIClass { public: TypeList Get_AnimType_List(const char *section, const char *entry, const TypeList defvalue); @@ -64,7 +64,7 @@ static class CCINIClassFake final : public CCINIClass /** * Fetch the owners (list of house bits). */ -long CCINIClassFake::_Get_Owners(const char *section, const char *entry, const long defvalue) +long CCINIClassExt::_Get_Owners(const char *section, const char *entry, const long defvalue) { /** * #issue-372 @@ -97,7 +97,7 @@ long CCINIClassFake::_Get_Owners(const char *section, const char *entry, const l /** * Store the house bitfield to the INI database. */ -bool CCINIClassFake::_Put_Owners(const char *section, const char *entry, long value) +bool CCINIClassExt::_Put_Owners(const char *section, const char *entry, long value) { /** * #issue-372 @@ -141,7 +141,7 @@ bool CCINIClassFake::_Put_Owners(const char *section, const char *entry, long va * * @author: CCHyper */ -TheaterType CCINIClassFake::_Get_TheaterType(const char *section, const char *entry, const TheaterType defvalue) +TheaterType CCINIClassExt::_Get_TheaterType(const char *section, const char *entry, const TheaterType defvalue) { char buffer[2048]; @@ -158,7 +158,7 @@ TheaterType CCINIClassFake::_Get_TheaterType(const char *section, const char *en * * @author: CCHyper */ -bool CCINIClassFake::_Put_TheaterType(const char *section, const char *entry, TheaterType value) +bool CCINIClassExt::_Put_TheaterType(const char *section, const char *entry, TheaterType value) { return CCINIClass::Put_String(section, entry, TheaterTypeClass::Name_From(value)); } @@ -169,7 +169,7 @@ bool CCINIClassFake::_Put_TheaterType(const char *section, const char *entry, Th * * @author: CCHyper */ -TypeList CCINIClassFake::Get_AnimType_List(const char *section, const char *entry, const TypeList defvalue) +TypeList CCINIClassExt::Get_AnimType_List(const char *section, const char *entry, const TypeList defvalue) { /** * #issue-391 @@ -212,7 +212,7 @@ TypeList CCINIClassFake::Get_AnimType_List(const char *section, * * @author: CCHyper */ -static void WeaponTypeClass_Read_INI_Get_AnimType_List_Encapsultator(WeaponTypeClass *this_ptr, CCINIClassFake &ini, const char *ini_name) +static void WeaponTypeClass_Read_INI_Get_AnimType_List_Encapsultator(WeaponTypeClass *this_ptr, CCINIClassExt &ini, const char *ini_name) { this_ptr->Anim = ini.Get_AnimType_List(ini_name, "Anim", this_ptr->Anim); } @@ -220,7 +220,7 @@ static void WeaponTypeClass_Read_INI_Get_AnimType_List_Encapsultator(WeaponTypeC DECLARE_PATCH(_WeaponTypeClass_Read_INI_Get_AnimType_List_Patch) { GET_REGISTER_STATIC(WeaponTypeClass *, this_ptr, esi); - GET_REGISTER_STATIC(CCINIClassFake *, ini, ebx); + GET_REGISTER_STATIC(CCINIClassExt *, ini, ebx); GET_REGISTER_STATIC(const char *, ini_name, edi); /** @@ -253,9 +253,9 @@ void CCINIClassExtension_Hooks() */ Patch_Jump(0x00680F07, &_WeaponTypeClass_Read_INI_Get_AnimType_List_Patch); - Patch_Jump(0x0044ADC0, &CCINIClassFake::_Get_Owners); - Patch_Jump(0x0044AE40, &CCINIClassFake::_Put_Owners); + Patch_Jump(0x0044ADC0, &CCINIClassExt::_Get_Owners); + Patch_Jump(0x0044AE40, &CCINIClassExt::_Put_Owners); - Patch_Jump(0x0044B310, &CCINIClassFake::_Get_TheaterType); - Patch_Jump(0x0044B360, &CCINIClassFake::_Put_TheaterType); + Patch_Jump(0x0044B310, &CCINIClassExt::_Get_TheaterType); + Patch_Jump(0x0044B360, &CCINIClassExt::_Put_TheaterType); } diff --git a/src/extensions/combat/combatext_hooks.cpp b/src/extensions/combat/combatext_hooks.cpp index 69e7b9c9..a6cc46f0 100644 --- a/src/extensions/combat/combatext_hooks.cpp +++ b/src/extensions/combat/combatext_hooks.cpp @@ -31,6 +31,7 @@ #include "overlaytype.h" #include "warheadtype.h" #include "warheadtypeext.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" @@ -76,8 +77,8 @@ DECLARE_PATCH(_Explosion_Damage_IsWallAbsoluteDestroyer_Patch) * of damage? If so, then pass -1 into Reduce_Wall to remove the wall * section from the cell. */ - warheadtypeext = WarheadTypeClassExtensions.find(warhead); - if (warheadtypeext && warheadtypeext->IsWallAbsoluteDestroyer) { + warheadtypeext = Extension::Fetch(warhead); + if (warheadtypeext->IsWallAbsoluteDestroyer) { cellptr->Reduce_Wall(-1); /** @@ -109,16 +110,15 @@ DECLARE_PATCH(_Do_Flash_CombatLightSize_Patch) static int flash_size; /** - * Fetch the warhead type extension instance if it exists. + * Fetch the extension instance. */ - warheadtypeext = WarheadTypeClassExtensions.find(warhead); + warheadtypeext = Extension::Fetch(warhead); /** - * If extension instance is not found, or no custom light size - * has been set, then just use the default code. This sets the - * size of the light based on the damage dealt by the Warhead. + * If no custom light size has been set, then just use the default code. + * This sets the size of the light based on the damage dealt by the Warhead. */ - if (!warheadtypeext || warheadtypeext->CombatLightSize <= 0.0f) { + if (warheadtypeext->CombatLightSize <= 0.0f) { /** * Original code. @@ -137,7 +137,7 @@ DECLARE_PATCH(_Do_Flash_CombatLightSize_Patch) /** * Has a custom light size been set on the warhead? */ - if (warheadtypeext && warheadtypeext->CombatLightSize > 0.0f) { + if (warheadtypeext->CombatLightSize > 0.0f) { /** * Clamp the light size and scale to expected size range. diff --git a/src/extensions/command/commandext.cpp b/src/extensions/command/commandext.cpp index 9957cf7e..4412fe7d 100644 --- a/src/extensions/command/commandext.cpp +++ b/src/extensions/command/commandext.cpp @@ -65,6 +65,7 @@ #include "wwcrc.h" #include "filepcx.h" #include "filepng.h" +#include "extension.h" #include "fatal.h" #include "minidump.h" #include "winutil.h" @@ -876,9 +877,9 @@ const char *InstantBuildCommandClass::Get_Description() const bool InstantBuildCommandClass::Process() { - if (!Session.Singleplayer_Game()) { - return false; - } + //if (!Session.Singleplayer_Game()) { + // return false; + //} Vinifera_Developer_InstantBuild = !Vinifera_Developer_InstantBuild; @@ -3239,3 +3240,86 @@ bool AIInstantSuperRechargeCommandClass::Process() return true; } + + +/** + * Toggles the instant recharge cheat for the AI player super weapons. + * + * @author: CCHyper + */ +const char *DumpNetworkCRCCommandClass::Get_Name() const +{ + return "DumpNetworkCRC"; +} + +const char *DumpNetworkCRCCommandClass::Get_UI_Name() const +{ + return "Dump Network CRC's"; +} + +const char *DumpNetworkCRCCommandClass::Get_Category() const +{ + return CATEGORY_DEVELOPER; +} + +const char *DumpNetworkCRCCommandClass::Get_Description() const +{ + return "Dumps all the current game network state to an output log."; +} + +bool DumpNetworkCRCCommandClass::Process() +{ + static unsigned _last_frame = -1; + + if (Session.Singleplayer_Game()) { + return false; + } + + /** + * Check to make sure we are not within a window that might cause rapid network desync. + */ + if (_last_frame != -1 && Frame < (_last_frame+30)) { + return false; + } + + /** + * Store the last execution frame. + */ + _last_frame = Frame; + + int day = 0; + int month = 0; + int year = 0; + int hour = 0; + int min = 0; + int sec = 0; + + Get_Full_Time(day, month, year, hour, min, sec); + + /** + * Create a unique filename for the sync log based on the current time and the player name. + */ + char filename_buffer[512]; + std::snprintf(filename_buffer, sizeof(filename_buffer), "%s\\SYNC_%s-%02d_%02u-%02u-%04u_%02u-%02u-%02u.LOG", + Vinifera_DebugDirectory, + PlayerPtr->IniName, + PlayerPtr->ID, + day, month, year, hour, min, sec); + + /** + * Open the sync log. + */ + FILE *fp = std::fopen(filename_buffer, "w+"); + if (fp == nullptr) { + DEBUG_ERROR("Failed to open sync log file for writing!\n"); + return false; + } + + DEBUG_INFO("Writing sync log to file %s.\n", filename_buffer); + + Extension::Print_CRCs(fp, nullptr); + + std::fclose(fp); + + return true; +} diff --git a/src/extensions/command/commandext.h b/src/extensions/command/commandext.h index 4b002bc4..aab6dc4f 100644 --- a/src/extensions/command/commandext.h +++ b/src/extensions/command/commandext.h @@ -27,8 +27,8 @@ ******************************************************************************/ #pragma once -#include "extension.h" #include "command.h" +#include "tibsun_defines.h" class BuildingClass; @@ -1206,6 +1206,25 @@ class AIInstantSuperRechargeCommandClass : public ViniferaCommandClass }; +/** + * Print CRC's + */ +class DumpNetworkCRCCommandClass : public ViniferaCommandClass +{ + public: + DumpNetworkCRCCommandClass() : ViniferaCommandClass() { IsDeveloper = true; } + virtual ~DumpNetworkCRCCommandClass() {} + + virtual const char *Get_Name() const override; + virtual const char *Get_UI_Name() const override; + virtual const char *Get_Category() const override; + virtual const char *Get_Description() const override; + virtual bool Process() override; + + virtual KeyNumType Default_Key() const override { return KeyNumType(KN_NONE); } +}; + + #ifndef DEBUG /** * Based class for all new developer/debug command classes. diff --git a/src/extensions/command/commandext_functions.cpp b/src/extensions/command/commandext_functions.cpp index 2608b831..7c0b0596 100644 --- a/src/extensions/command/commandext_functions.cpp +++ b/src/extensions/command/commandext_functions.cpp @@ -32,6 +32,7 @@ #include "rules.h" #include "tacticalext.h" #include "tactical.h" +#include "extension_globals.h" #include "asserthandler.h" #include "debughandler.h" @@ -73,24 +74,21 @@ bool Prev_Theme_Command() /** * Print the chosen music track name on the screen. */ - if (TacticalExtension) { + TacticalMapExtension->InfoTextTimer.Stop(); - TacticalExtension->InfoTextTimer.Stop(); + char buffer[256]; + std::snprintf(buffer, sizeof(buffer), "Now Playing: %s", Theme.ThemeClass::Full_Name(theme)); - char buffer[256]; - std::snprintf(buffer, sizeof(buffer), "Now Playing: %s", Theme.ThemeClass::Full_Name(theme)); + TacticalMapExtension->Set_Info_Text(buffer); + TacticalMapExtension->IsInfoTextSet = true; - TacticalExtension->InfoTextBuffer = buffer; - TacticalExtension->IsInfoTextSet = true; + TacticalMapExtension->InfoTextPosition = InfoTextPosType::BOTTOM_LEFT; - TacticalExtension->InfoTextPosition = InfoTextPosType::BOTTOM_LEFT; + //TacticalMapExtension->InfoTextNotifySound = Rule->OptionsChanged; + //TacticalMapExtension->InfoTextNotifySoundVolume = 0.5f; - //TacticalExtension->InfoTextNotifySound = Rule->OptionsChanged; - //TacticalExtension->InfoTextNotifySoundVolume = 0.5f; - - TacticalExtension->InfoTextTimer = SECONDS_TO_MILLISECONDS(4); - TacticalExtension->InfoTextTimer.Start(); - } + TacticalMapExtension->InfoTextTimer = SECONDS_TO_MILLISECONDS(4); + TacticalMapExtension->InfoTextTimer.Start(); return true; } @@ -133,24 +131,21 @@ bool Next_Theme_Command() /** * Print the chosen music track name on the screen. */ - if (TacticalExtension) { + TacticalMapExtension->InfoTextTimer.Stop(); - TacticalExtension->InfoTextTimer.Stop(); + char buffer[256]; + std::snprintf(buffer, sizeof(buffer), "Now Playing: %s", Theme.ThemeClass::Full_Name(theme)); - char buffer[256]; - std::snprintf(buffer, sizeof(buffer), "Now Playing: %s", Theme.ThemeClass::Full_Name(theme)); + TacticalMapExtension->Set_Info_Text(buffer); + TacticalMapExtension->IsInfoTextSet = true; + + TacticalMapExtension->InfoTextPosition = InfoTextPosType::BOTTOM_LEFT; - TacticalExtension->InfoTextBuffer = buffer; - TacticalExtension->IsInfoTextSet = true; - - TacticalExtension->InfoTextPosition = InfoTextPosType::BOTTOM_LEFT; + //TacticalMapExtension->InfoTextNotifySound = Rule->OptionsChanged; + //TacticalMapExtension->InfoTextNotifySoundVolume = 0.5f; - //TacticalExtension->InfoTextNotifySound = Rule->OptionsChanged; - //TacticalExtension->InfoTextNotifySoundVolume = 0.5f; - - TacticalExtension->InfoTextTimer = SECONDS_TO_MILLISECONDS(4); - TacticalExtension->InfoTextTimer.Start(); - } + TacticalMapExtension->InfoTextTimer = SECONDS_TO_MILLISECONDS(4); + TacticalMapExtension->InfoTextTimer.Start(); return true; } diff --git a/src/extensions/command/commandext_hooks.cpp b/src/extensions/command/commandext_hooks.cpp index 4007aa24..2703d806 100644 --- a/src/extensions/command/commandext_hooks.cpp +++ b/src/extensions/command/commandext_hooks.cpp @@ -38,6 +38,9 @@ #include "asserthandler.h" #include "debughandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * This function reimplements the chunk of code that populates the keyboard @@ -389,6 +392,9 @@ void Init_Vinifera_Commands() cmdptr = new AIInstantSuperRechargeCommandClass; Commands.Add(cmdptr); + + cmdptr = new DumpNetworkCRCCommandClass; + Commands.Add(cmdptr); } #ifndef NDEBUG diff --git a/src/extensions/container.h b/src/extensions/container.h deleted file mode 100644 index 04839f9a..00000000 --- a/src/extensions/container.h +++ /dev/null @@ -1,282 +0,0 @@ -/******************************************************************************* -/* O P E N S O U R C E -- V I N I F E R A ** -/******************************************************************************* - * - * @project Vinifera - * - * @file CONTAINER.H - * - * @author CCHyper - * - * @brief Wrapper to unordered map for use with extended classes. - * - * @license Vinifera is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version - * 3 of the License, or (at your option) any later version. - * - * Vinifera is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. - * If not, see . - * - ******************************************************************************/ -#pragma once - -#include "always.h" -#include - -#ifdef USE_ROBIN_HOOD -#include -#else -#include -#endif - -#include "debughandler.h" -#include "asserthandler.h" - - -/** - * Templated wrapper class around std::unordered_map. - */ -template -class ContainerMap -{ - public: -#ifdef USE_ROBIN_HOOD - using map_type = robin_hood::unordered_flat_map; -#else - using map_type = std::unordered_map; -#endif - using iterator = typename map_type::iterator; - using const_iterator = typename map_type::const_iterator; - - public: - ContainerMap() : Items() {} - ~ContainerMap() {} - - /** - * Finds element with specific key. - */ - Value * find(const Key * key) const - { - const auto it = Items.find(key); - if(it != Items.end()) { - return it->second; - } - return nullptr; - } - - /** - * Insert a new element instance into the map. - */ - Value * insert(const Key * key, Value * value) - { - Items.emplace(key, value); - return value; - } - - /** - * Remove an element from the map. - */ - Value * remove(const Key * key) - { - const auto it = Items.find(key); - if(it != Items.cend()) { - Value * value = it->second; - Items.erase(it); - return value; - } - return nullptr; - } - - /** - * Checks whether the container is empty. - */ - bool empty() const - { - return size() == 0; - } - - /** - * Clears the contents of the map. - */ - void clear() - { - Items.clear(); - } - - /** - * Returns the number of elements in the map. - */ - size_t size() const - { - return Items.size(); - } - - /** - * Returns an iterator to the beginning. - */ - iterator begin() const - { - auto item = Items.begin(); - return reinterpret_cast(item); - } - - /** - * Returns an iterator to the end. - */ - iterator end() const - { - auto item = Items.end(); - return reinterpret_cast(item); - } - - private: - /** - * The unordered map of items. - */ - map_type Items; - - private: - //ContainerMap() = default; - ContainerMap(const ContainerMap &) = delete; - ContainerMap & operator = (const ContainerMap &) = delete; - ContainerMap & operator = (ContainerMap &&) = delete; -}; - - -/** - * Templated wrapper class around ContainerMap that implements - * interfaces required by the extended classes for game use. - * - * This hides the direct access to the map without accessing - * it directly, which is not recommended. - */ -template -class ExtensionMap final -{ - public: - ExtensionMap() : Map() {} - ~ExtensionMap() {} - - /** - * Find the extension instance for this type. - */ - Extension * find(const Base * key, bool log_failure = true) const - { - if (key == nullptr) { - DEBUG_ERROR("Attempted to find \"%s\" instance a NULL base pointer!\n", typeid(Extension).name()); - return nullptr; - } - const auto ptr = Map.find(key); - if (!ptr) { - if (log_failure) { - DEBUG_WARNING("Failed to find extension instance \"%s\"!\n", typeid(Extension).name()); - } - return nullptr; - } - //DEBUG_WARNING("Found extension instance \"%s\"!\n", typeid(Extension).name()); - return ptr; - } - - /** - * Find the extension instance for this type or create a default instance. - */ - Extension * find_or_create(Base * key) - { - if (key == nullptr) { - DEBUG_ERROR("Find or create of \"%s\" instance attempted with a NULL base pointer!\n", typeid(Extension).name()); - return nullptr; - } - - /** - * Find and return the instance in the map, if it exists. - */ - if (const auto ptr = Map.find(key)) { - //DEBUG_WARNING("Found extension instance \"%s\"!\n", typeid(Extension).name()); - return ptr; - } - - /** - * Create an instance of the extended class. This expects the extended class - * constructor takes a pointer to the base class type! - */ - //DEBUG_WARNING("Creating new \"%s\" extension instance!\n", typeid(Extension).name()); - auto val = new Extension(key); - return Map.insert(key, val); - } - - /** - * Create a default instance. - * - * @warning: Only use this if you really need to! - */ - Extension * create(Base * key) - { - if (key == nullptr) { - DEBUG_ERROR("Creation of \"%s\" instance attempted with a NULL base pointer!\n", typeid(Extension).name()); - return nullptr; - } - - /** - * Create an instance of the extended class. This expects the extended class - * constructor takes a pointer to the base class type! - */ - //DEBUG_WARNING("Creating new \"%s\" extension instance!\n", typeid(Extension).name()); - auto val = new Extension(key); - return Map.insert(key, val); - } - - /** - * Remove an element from the map. - */ - void remove(const Base * key) - { - delete Map.remove(key); - } - - - /** - * Returns the number of elements in the map. - */ - size_t size() const - { - return Map.size(); - } - - /** - * Checks whether the container is empty. - */ - bool empty() const - { - return Map.size() == 0; - } - - /** - * Clears the contents of the map. - */ - void clear() - { - if (!empty()) { - int sz = Map.size(); - Map.clear(); - DEBUG_WARNING("Cleared %u items from \"%s\".\n", sz, typeid(Extension).name()); - } - } - - public: - /** - * The container map of items. - */ - ContainerMap Map; - - private: - ExtensionMap(const ExtensionMap &) = delete; - ExtensionMap & operator = (const ExtensionMap &) = delete; - ExtensionMap & operator = (ExtensionMap &&) = delete; -}; diff --git a/src/extensions/display/displayext_hooks.cpp b/src/extensions/display/displayext_hooks.cpp index 8a0886c1..2d3ed68e 100644 --- a/src/extensions/display/displayext_hooks.cpp +++ b/src/extensions/display/displayext_hooks.cpp @@ -40,6 +40,7 @@ #include "session.h" #include "sessionext.h" #include "wwmouse.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" @@ -92,8 +93,8 @@ DECLARE_PATCH(_DisplayClass_Passes_Proximity_Passes_Check_Patch) if (base->House != hptr && base->House->Is_Ally(hptr)) { - buildingtypeext = BuildingTypeClassExtensions.find(base->Class); - if (buildingtypeext && buildingtypeext->IsEligibleForAllyBuilding) { + buildingtypeext = Extension::Fetch(base->Class); + if (buildingtypeext->IsEligibleForAllyBuilding) { #ifndef NDEBUG //DEV_DEBUG_INFO("Ally \"%s's\" building \"%s\" is eligible for building off.\n", base->House->IniName, base->Name()); #endif diff --git a/src/extensions/empulse/empulseext_hooks.cpp b/src/extensions/empulse/empulseext_hooks.cpp index 053a5ef7..ae77a964 100644 --- a/src/extensions/empulse/empulseext_hooks.cpp +++ b/src/extensions/empulse/empulseext_hooks.cpp @@ -30,6 +30,7 @@ #include "techno.h" #include "building.h" #include "foot.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" @@ -51,15 +52,13 @@ DECLARE_PATCH(_EMPulseClass_Create_Building_EMPImmune_Patch) GET_REGISTER_STATIC(BuildingTypeClass *, buildingtype, eax); static TechnoTypeClassExtension *exttype_ptr; - exttype_ptr = TechnoTypeClassExtensions.find(buildingtype); - if (exttype_ptr) { + exttype_ptr = Extension::Fetch(buildingtype); - /** - * Is this building immune to EMP weapons? - */ - if (exttype_ptr->IsImmuneToEMP) { - goto loop_continue; - } + /** + * Is this building immune to EMP weapons? + */ + if (exttype_ptr->IsImmuneToEMP) { + goto loop_continue; } /** @@ -96,15 +95,13 @@ DECLARE_PATCH(_EMPulseClass_Create_Foot_EMPImmune_Patch) static ILocomotion *loco; static TechnoTypeClassExtension *exttype_ptr; - exttype_ptr = TechnoTypeClassExtensions.find(foot->Techno_Type_Class()); - if (exttype_ptr) { + exttype_ptr = Extension::Fetch(foot->Techno_Type_Class()); - /** - * Is this object immune to EMP weapons? - */ - if (exttype_ptr->IsImmuneToEMP) { - goto loop_continue; - } + /** + * Is this object immune to EMP weapons? + */ + if (exttype_ptr->IsImmuneToEMP) { + goto loop_continue; } /** diff --git a/src/extensions/extension.cpp b/src/extensions/extension.cpp index ca590f2f..cbb269dd 100644 --- a/src/extensions/extension.cpp +++ b/src/extensions/extension.cpp @@ -8,7 +8,7 @@ * * @author CCHyper * - * @brief Base class for declaring extended class instances. + * @brief The file contains the functions required for the extension system. * * @license Vinifera is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -26,39 +26,2038 @@ * ******************************************************************************/ #include "extension.h" -#include "tibsun_globals.h" +#include "tibsun_functions.h" +#include "vinifera_saveload.h" +#include "wstring.h" +#include "vector.h" +#include "tclassfactory.h" #include "swizzle.h" +#include "tracker.h" +#include "debughandler.h" +#include "asserthandler.h" + +#include "aircraft.h" +#include "aircrafttype.h" +#include "anim.h" +#include "animtype.h" +#include "building.h" +#include "buildingtype.h" +#include "buildinglight.h" +#include "bullet.h" +#include "bullettype.h" +#include "campaign.h" +#include "empulse.h" +#include "factory.h" +#include "foggedobject.h" +#include "side.h" +#include "house.h" +#include "housetype.h" +#include "infantry.h" +#include "infantrytype.h" +#include "isotile.h" +#include "isotiletype.h" +#include "lightsource.h" +#include "objecttype.h" +#include "overlay.h" +#include "overlaytype.h" +#include "particle.h" +#include "particletype.h" +#include "particlesys.h" +#include "particlesystype.h" +#include "radarevent.h" +#include "script.h" +#include "scripttype.h" +#include "smudge.h" +#include "smudgetype.h" +#include "super.h" +#include "supertype.h" +#include "taskforce.h" +#include "tag.h" +#include "tagtype.h" +#include "team.h" +#include "teamtype.h" +#include "trigger.h" +#include "triggertype.h" +#include "aitrigtype.h" +#include "terrain.h" +#include "terraintype.h" +#include "tiberium.h" +#include "unit.h" +#include "unittype.h" +#include "voxelanim.h" +#include "voxelanimtype.h" +#include "warheadtype.h" +#include "wave.h" +#include "weapontype.h" +#include "veinholemonster.h" +#include "taction.h" +#include "tevent.h" +#include "tube.h" +#include "waypointpath.h" +#include "alphashape.h" +#include "event.h" +#include "options.h" +#include "session.h" +#include "scenario.h" +#include "wsproto.h" +#include "iomap.h" +#include "layer.h" +#include "logic.h" + +#include "aircraftext.h" +#include "aircrafttypeext.h" +#include "animext.h" +#include "animtypeext.h" +#include "buildingext.h" +#include "buildingtypeext.h" +#include "bullettypeext.h" +#include "campaignext.h" +#include "sideext.h" +#include "houseext.h" +#include "housetypeext.h" +#include "infantryext.h" +#include "infantrytypeext.h" +#include "isotiletypeext.h" +#include "objecttypeext.h" +#include "overlaytypeext.h" +#include "particlesystypeext.h" +#include "particletypeext.h" +#include "smudgetypeext.h" +#include "superext.h" +#include "supertypeext.h" +#include "terrainext.h" +#include "terraintypeext.h" +#include "tiberiumext.h" +#include "unitext.h" +#include "unittypeext.h" +#include "voxelanimtypeext.h" +#include "warheadtypeext.h" +#include "waveext.h" +#include "weapontypeext.h" + +#include "rulesext.h" +#include "scenarioext.h" +#include "sessionext.h" +#include "tacticalext.h" + +#include "themeext.h" + +#include "tspp_gitinfo.h" +#include "vinifera_gitinfo.h" + +#include + + +extern int Execute_Day; +extern int Execute_Month; +extern int Execute_Year; +extern int Execute_Hour; +extern int Execute_Min; +extern int Execute_Sec; + + +/** + * Use this macro when you want to get or set the extension pointer from the abstract object. + */ +#define ABSTRACT_EXTENSION_POINTER_CAST_MACRO(_abstract) (*(uintptr_t *)(((unsigned char *)_abstract) + 0x10)) + +/** + * Use this macro when fetching the extension pointer from the abstract object + * for pointer remapping purposes. + */ +#define ABSTRACT_EXTENSION_POINTER_REMAP_MACRO(_abstract) (uintptr_t **)(((unsigned char *)_abstract) + 0x10); + + +/** + * Set the extension pointer to the input abstract object. + * + * @author: CCHyper + */ +static void Extension_Set_Abstract_Pointer(const AbstractClass *abstract, const AbstractClassExtension *abstract_extension) +{ + ASSERT(abstract != nullptr); + ASSERT(abstract_extension != nullptr); + + ABSTRACT_EXTENSION_POINTER_CAST_MACRO(abstract) = (uintptr_t)abstract_extension; +} + + +/** + * Get the extension pointer from the input abstract object. + * + * @author: CCHyper + */ +static AbstractClassExtension *Extension_Get_Abstract_Pointer(const AbstractClass *abstract) +{ + uintptr_t abstract_extension_address = ABSTRACT_EXTENSION_POINTER_CAST_MACRO(abstract); + AbstractClassExtension *abstract_extension = (AbstractClassExtension *)abstract_extension_address; + return abstract_extension; +} + + +/** + * Invalidate the extension pointer from the input abstract object. + * + * @author: CCHyper + */ +static void Extension_Clear_Abstract_Pointer(const AbstractClass *abstract) +{ + ABSTRACT_EXTENSION_POINTER_CAST_MACRO(abstract) = (uintptr_t)0x00000000; +} + + +/** + * Check if the extension pointer is a valid memory address. + * + * #WARNING: This is not guanteed to work, but it should capture the majority of possible bad pointers. + * + * 0x00870000 -> End of GAME.EXE .data segment virtual address. + * 0x20000000 -> Arbitrary address VINIFERA.DLL 'should' never get to. + * + * @author: CCHyper + */ +static bool Extension_Is_Valid_Pointer(const AbstractClassExtension *abstract_extension) +{ + return ((uintptr_t)abstract_extension) >= 0x00870000 || ((uintptr_t)abstract_extension) < 0x20000000; +} + + +/** + * Creates and attach an instance of the extension class associated with the abstract class. + * + * @author: CCHyper + */ +template +static EXT_CLASS * Extension_Make(const BASE_CLASS *abstract_ptr) +{ + const BASE_CLASS *abs_ptr = reinterpret_cast(abstract_ptr); + EXT_CLASS *ext_ptr = reinterpret_cast(Extension_Get_Abstract_Pointer(abs_ptr)); + + /** + * Create an instance of the extension linked to the abstract object. + */ + ext_ptr = new EXT_CLASS(reinterpret_cast(abs_ptr)); + ASSERT(ext_ptr != nullptr); + if (!ext_ptr) { + + char buffer[256]; + std::snprintf(buffer, sizeof(buffer), "Extension_Make: Failed to make \"%s\" extension!\n", Extension::Utility::Get_TypeID_Name().c_str()); + + EXT_DEBUG_WARNING(buffer); + + ShowCursor(TRUE); + MessageBoxA(MainWindow, buffer, "Vinifera", MB_OK|MB_ICONEXCLAMATION); + + //Vinifera_Generate_Mini_Dump(); + Fatal("Failed to create WeaponTypeClassExtension instance!\n"); + + return nullptr; + } + + EXT_DEBUG_INFO("Created \"%s\" extension.\n", Extension::Utility::Get_TypeID_Name().c_str()); + + /** + * Assign the extension class instance to the abstract class. + */ + Extension_Set_Abstract_Pointer(abstract_ptr, ext_ptr); + + return ext_ptr; +} + + +/** + * Destroys the attached extension instance for the abstract class. + * + * @author: CCHyper + */ +template +static bool Extension_Destroy(const BASE_CLASS *abstract_ptr) +{ + /** + * Fetch the extension instance from the abstract object. + */ + EXT_CLASS *ext_ptr = reinterpret_cast(Extension_Get_Abstract_Pointer(abstract_ptr)); + if (!ext_ptr) { + EXT_DEBUG_WARNING("Extension_Destroy: \"%s\" extension pointer is null!\n", Extension::Utility::Get_TypeID_Name().c_str()); + return false; + } + + /** + * Destroy the attached extension class instance. + */ + delete ext_ptr; + + EXT_DEBUG_INFO("Destroyed \"%s\" extension.\n", Extension::Utility::Get_TypeID_Name().c_str()); + + /** + * Clear the extension pointer for the abstract class. + */ + Extension_Clear_Abstract_Pointer(abstract_ptr); + + return true; +} + + +/** + * Saves all active objects to the data stream. + * + * @author: CCHyper + */ +template +static bool Extension_Save(IStream *pStm, const DynamicVectorClass &list) +{ + /** + * Save the number of instances of this class. + */ + int count = list.Count(); + HRESULT hr = pStm->Write(&count, sizeof(count), nullptr); + if (FAILED(hr)) { + return false; + } + + if (list.Count() <= 0) { + DEBUG_INFO("List for \"%s\" has a count of zero, skipping save.\n", Extension::Utility::Get_TypeID_Name().c_str()); + return true; + } + + DEBUG_INFO("Saving \"%s\" extensions (Count: %d)\n", Extension::Utility::Get_TypeID_Name().c_str(), list.Count()); + + /** + * Save each instance of this class. + */ + for (int index = 0; index < count; ++index) { + + EXT_CLASS *ptr = list[index]; + + /** + * Tell the extension class to persist itself into the data stream. + */ + IPersistStream *lpPS = nullptr; + hr = ptr->QueryInterface(__uuidof(IPersistStream), (LPVOID *)&lpPS); + if (FAILED(hr)) { + DEBUG_ERROR("Extension \"%s\" does not support IPersistStream!\n", Extension::Utility::Get_TypeID_Name().c_str()); + return false; + } + + /** + * Save the object itself. + */ + hr = OleSaveToStream(lpPS, pStm); + if (FAILED(hr)) { + DEBUG_ERROR("OleSaveToStream failed for extension \"%s\" (Index: %d)!\n", Extension::Utility::Get_TypeID_Name().c_str(), index); + return false; + } + + /** + * Release the interface. + */ + hr = lpPS->Release(); + if (FAILED(hr)) { + DEBUG_ERROR("Failed to release extension \"%s\" stream!\n", Extension::Utility::Get_TypeID_Name().c_str()); + return false; + } + + EXT_CLASS * ext_ptr = reinterpret_cast(lpPS); + + if (ext_ptr->What_Am_I() != RTTI_WAVE || ext_ptr->What_Am_I() != RTTI_LIGHT) { + EXT_DEBUG_INFO(" -> %s\n", ext_ptr->Name()); + } + } + + return true; +} + + +/** + * Loads all active objects form the data stream. + * + * @author: CCHyper + */ +template +static bool Extension_Load(IStream *pStm, DynamicVectorClass &list) +{ + /** + * Read the number of instances of this class. + */ + int count = 0; + HRESULT hr = pStm->Read(&count, sizeof(count), nullptr); + if (FAILED(hr)) { + return false; + } + + if (count <= 0) { + DEBUG_INFO("List for \"%s\" has a count of zero, skipping load.\n", Extension::Utility::Get_TypeID_Name().c_str()); + return true; + } + + DEBUG_INFO("Loading \"%s\" extensions (Count: %d)\n", Extension::Utility::Get_TypeID_Name().c_str(), count); + + /** + * Read each class instance. + */ + for (int index = 0; index < count; ++index) { + + /** + * Load the object. + */ + IUnknown *spUnk = nullptr; + hr = OleLoadFromStream(pStm, __uuidof(IUnknown), (LPVOID *)&spUnk); + if (FAILED(hr)) { + DEBUG_ERROR("OleLoadFromStream failed for extension \"%s\" (Index: %d)!\n", Extension::Utility::Get_TypeID_Name().c_str(), index); + return false; + } + + } + + return true; +} + + +/** + * Request remap of all the extension pointers from all the active abstract objects. + * + * @author: CCHyper + */ +template +static bool Extension_Request_Pointer_Remap(const DynamicVectorClass &list) +{ + if (!list.Count()) { + DEBUG_INFO("Requested remap of \"%s\" extension pointers, but the list is empty!\n", Extension::Utility::Get_TypeID_Name().c_str()); + return true; + } + + DEBUG_INFO("Requesting remap of \"%s\" extension pointers (Count %d)...\n", Extension::Utility::Get_TypeID_Name().c_str(), list.Count()); + + for (int index = 0; index < list.Count(); ++index) { + + const BASE_CLASS *object = list[index]; + if (object) { + + if (!Extension_Get_Abstract_Pointer(object)) { + DEV_DEBUG_ERROR("Extension_Request_Pointer_Remap: \"%s\" extension pointer (index %d) for is null!\n", Extension::Utility::Get_TypeID_Name().c_str(), index); + continue; //return false; + } + + Wstring extptr_name; + extptr_name += Extension::Utility::Get_TypeID_Name(object).c_str(); + extptr_name += "::ExtPtr"; + + /** + * Inform the swizzle manager that we need to remap the pointer. + */ + uintptr_t **ext_ptr_addr = ABSTRACT_EXTENSION_POINTER_REMAP_MACRO(object); + VINIFERA_SWIZZLE_REQUEST_POINTER_REMAP(*ext_ptr_addr, extptr_name.Peek_Buffer()); + + EXT_DEBUG_INFO(" Requested remap of index %d extension pointer complete.\n", index); + } + } + + return true; +} + + +/** + * Detaches the object from the list of active object. + * + * @author: CCHyper + */ +template +static void Extension_Detach_This_From_All(DynamicVectorClass &list, TARGET target, bool all) +{ + for (int index = 0; index < list.Count(); ++index) { + list[index]->Detach(target, all); + } +} + + +/** + * Internal function that performs the creation of the extension object and + * associates it with the abstract object. + * + * @author: CCHyper + */ +AbstractClassExtension *Extension::Private::Make_Internal(const AbstractClass *abstract) +{ + ASSERT(abstract != nullptr); + + AbstractClassExtension *extptr = nullptr; + + switch (const_cast(abstract)->What_Am_I()) { + case RTTI_UNIT: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_AIRCRAFT: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_AIRCRAFTTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_ANIM: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_ANIMTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_BUILDING: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_BUILDINGTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_BULLET: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_BULLETTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_CAMPAIGN: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_CELL: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_FACTORY: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_HOUSE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_HOUSETYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_INFANTRY: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_INFANTRYTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_ISOTILE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_ISOTILETYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_LIGHT: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_OVERLAY: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_OVERLAYTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_PARTICLE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_PARTICLETYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_PARTICLESYSTEM: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_PARTICLESYSTEMTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_SCRIPT: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_SCRIPTTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_SIDE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_SMUDGE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_SMUDGETYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_SUPERWEAPONTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_TASKFORCE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_TEAM: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_TEAMTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_TERRAIN: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_TERRAINTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_TRIGGER: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_TRIGGERTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_UNITTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_VOXELANIM: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_VOXELANIMTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_WAVE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_TAG: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_TAGTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_TIBERIUM: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_ACTION: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_EVENT: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_WEAPONTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + case RTTI_WARHEADTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_WAYPOINT: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_TUBE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_LIGHTSOURCE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_EMPULSE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_SUPERWEAPON: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } + //case RTTI_AITRIGGER: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_AITRIGGERTYPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_NEURON: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_FOGGEDOBJECT: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_ALPHASHAPE: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_VEINHOLEMONSTER: { extptr = Extension_Make(reinterpret_cast(abstract)); break; } // Not yet implemented + default: { DEBUG_ERROR("Extension::Make: No extension support for \"%s\" implemented!\n", Name_From_RTTI((RTTIType)abstract->What_Am_I())); break; } + }; + + return extptr; +} + + +/** + * Internal function that performs the destruction of the extension object + * associated with the abstract object. + * + * @author: CCHyper + */ +bool Extension::Private::Destroy_Internal(const AbstractClass *abstract) +{ + ASSERT(abstract != nullptr); + + bool removed = false; + + switch (abstract->What_Am_I()) { + case RTTI_UNIT: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_AIRCRAFT: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_AIRCRAFTTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_ANIM: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_ANIMTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_BUILDING: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_BUILDINGTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_BULLET: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_BULLETTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_CAMPAIGN: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_CELL: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_FACTORY: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_HOUSE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_HOUSETYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_INFANTRY: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_INFANTRYTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_ISOTILE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_ISOTILETYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_LIGHT: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_OVERLAY: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_OVERLAYTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_PARTICLE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_PARTICLETYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_PARTICLESYSTEM: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_PARTICLESYSTEMTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_SCRIPT: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_SCRIPTTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_SIDE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_SMUDGE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_SMUDGETYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_SUPERWEAPONTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_TASKFORCE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_TEAM: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_TEAMTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_TERRAIN: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_TERRAINTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_TRIGGER: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_TRIGGERTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_UNITTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_VOXELANIM: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_VOXELANIMTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_WAVE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_TAG: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_TAGTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_TIBERIUM: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_ACTION: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_EVENT: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_WEAPONTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + case RTTI_WARHEADTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_WAYPOINT: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_TUBE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_LIGHTSOURCE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_EMPULSE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + case RTTI_SUPERWEAPON: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } + //case RTTI_AITRIGGER: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_AITRIGGERTYPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_NEURON: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_FOGGEDOBJECT: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_ALPHASHAPE: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + //case RTTI_VEINHOLEMONSTER: { removed = Extension_Destroy(reinterpret_cast(abstract)); break; } // Not yet implemented + default: { DEBUG_ERROR("Extension::Destroy: No extension support for \"%s\" implemented!\n", Name_From_RTTI((RTTIType)abstract->What_Am_I())); break; } + }; + + ASSERT(removed); + + return true; +} + + +/** + * Internal function for fetching the extension object associated with the abstract object. + * + * @author: CCHyper + */ +AbstractClassExtension *Extension::Private::Fetch_Internal(const AbstractClass *abstract) +{ + ASSERT(abstract != nullptr); + + AbstractClassExtension *ext_ptr = Extension_Get_Abstract_Pointer(abstract); + + if (!ext_ptr) { + DEBUG_ERROR("Extension::Fetch: Extension for \"%s\" is null!\n", Extension::Utility::Get_TypeID_Name(abstract).c_str()); + return nullptr; + } + + /** + * Check for a malformed extension pointer. + */ + if (!Extension_Is_Valid_Pointer(ext_ptr)) { + DEBUG_ERROR("Extension::Fetch: Corrupt extension pointer for \"%s\"!\n", Extension::Utility::Get_TypeID_Name(abstract).c_str()); + return nullptr; + } + + /** + * Its still possible the pointer could be invalid, so perform a final check. + */ + if (ext_ptr->What_Am_I() <= RTTI_NONE || ext_ptr->What_Am_I() >= RTTI_COUNT) { + DEBUG_ERROR("Extension::Fetch: Invalid extension rtti type for \"%s\"!\n", Extension::Utility::Get_TypeID_Name(abstract).c_str()); + return nullptr; + } + + //EXT_DEBUG_INFO("Extension::Fetch: Abstract \"%s\", got extension \"%s\".\n", Extension::Utility::Get_TypeID_Name(abstract).c_str(), ext_ptr->Name()); + + return ext_ptr; +} /** - * Base class implementation of Load. + * Save all the extension class data to the stream. * * @author: CCHyper */ -HRESULT ExtensionBase::Load(IStream *pStm) +bool Extension::Save(IStream *pStm) { + ASSERT(pStm != nullptr); + if (!pStm) { - return E_POINTER; + return false; } - return S_OK; + DEV_DEBUG_INFO("Extension::Save(enter)\n"); + + /** + * #NOTE: The order of these calls must match the relevant RTTIType order! + */ + if (!Extension_Save(pStm, UnitExtensions)) { return false; } + if (!Extension_Save(pStm, AircraftExtensions)) { return false; } + if (!Extension_Save(pStm, AircraftTypeExtensions)) { return false; } + if (!Extension_Save(pStm, AnimExtensions)) { return false; } + if (!Extension_Save(pStm, AnimTypeExtensions)) { return false; } + if (!Extension_Save(pStm, BuildingExtensions)) { return false; } + if (!Extension_Save(pStm, BuildingTypeExtensions)) { return false; } + //if (!Extension_Save(pStm, BulletExtensions)) { return false; } // Not yet implemented + if (!Extension_Save(pStm, BulletTypeExtensions)) { return false; } + //if (!Extension_Save(pStm, CampaignExtensions)) { return false; } // Supported, but Campaign's are not saved to file. + //if (!Extension_Save(pStm, CellExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, FactoryExtensions)) { return false; } // Not yet implemented + if (!Extension_Save(pStm, HouseExtensions)) { return false; } + if (!Extension_Save(pStm, HouseTypeExtensions)) { return false; } + if (!Extension_Save(pStm, InfantryExtensions)) { return false; } + if (!Extension_Save(pStm, InfantryTypeExtensions)) { return false; } + //if (!Extension_Save(pStm, IsometricTileExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, IsometricTileTypeExtensions)) { return false; } // Supported, but IsoTileTypes's are not saved to file. + //if (!Extension_Save(pStm, BuildingLightExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, OverlayExtensions)) { return false; } // Not yet implemented + if (!Extension_Save(pStm, OverlayTypeExtensions)) { return false; } + //if (!Extension_Save(pStm, ParticleClassExtensions)) { return false; } // Not yet implemented + if (!Extension_Save(pStm, ParticleTypeExtensions)) { return false; } + //if (!Extension_Save(pStm, ParticleSystemExtensions)) { return false; } // Not yet implemented + if (!Extension_Save(pStm, ParticleSystemTypeExtensions)) { return false; } + //if (!Extension_Save(pStm, ScriptExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, ScriptTypeExtensions)) { return false; } // Not yet implemented + if (!Extension_Save(pStm, SideExtensions)) { return false; } + //if (!Extension_Save(pStm, SmudgeExtensions)) { return false; } // Not yet implemented + if (!Extension_Save(pStm, SmudgeTypeExtensions)) { return false; } + if (!Extension_Save(pStm, SuperWeaponTypeExtensions)) { return false; } + //if (!Extension_Save(pStm, TaskForceExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, TeamExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, TeamTypeExtensions)) { return false; } // Not yet implemented + if (!Extension_Save(pStm, TerrainExtensions)) { return false; } + if (!Extension_Save(pStm, TerrainTypeExtensions)) { return false; } + //if (!Extension_Save(pStm, TriggerExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, TriggerTypeExtensions)) { return false; } // Not yet implemented + if (!Extension_Save(pStm, UnitTypeExtensions)) { return false; } + //if (!Extension_Save(pStm, VoxelAnimExtensions)) { return false; } // Not yet implemented + if (!Extension_Save(pStm, VoxelAnimTypeExtensions)) { return false; } + if (!Extension_Save(pStm, WaveExtensions)) { return false; } + //if (!Extension_Save(pStm, TagExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, TagTypeExtensions)) { return false; } // Not yet implemented + if (!Extension_Save(pStm, TiberiumExtensions)) { return false; } + //if (!Extension_Save(pStm, TActionExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, TEventExtensions)) { return false; } // Not yet implemented + if (!Extension_Save(pStm, WeaponTypeExtensions)) { return false; } + if (!Extension_Save(pStm, WarheadTypeExtensions)) { return false; } + //if (!Extension_Save(pStm, WaypointExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, TubeExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, LightSourceExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, EMPulseExtensions)) { return false; } // Not yet implemented + if (!Extension_Save(pStm, SuperExtensions)) { return false; } + //if (!Extension_Save(pStm, AITriggerExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, AITriggerExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, NeuronExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, FoggedObjectExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, AlphaShapeExtensions)) { return false; } // Not yet implemented + //if (!Extension_Save(pStm, VeinholeMonsterExtensions)) { return false; } // Not yet implemented + + if (FAILED(TacticalMapExtension->Save(pStm, true))) { return false; } + DEBUG_INFO("Saved \"%s\" extension.\n", TacticalMapExtension->Name()); + + if (FAILED(RuleExtension->Save(pStm, true))) { return false; } + DEBUG_INFO("Saved \"%s\" extension\n", RuleExtension->Name()); + + if (FAILED(ScenExtension->Save(pStm, true))) { return false; } + DEBUG_INFO("Saved \"%s\" extension\n", ScenExtension->Name()); + + if (FAILED(SessionExtension->Save(pStm, true))) { return false; } + DEBUG_INFO("Saved \"%s\" extension\n", SessionExtension->Name()); + + DEV_DEBUG_INFO("Extension::Save(exit)\n"); + + return true; } /** - * Base class implementation of Save. + * Load all the extension class data from the stream. * * @author: CCHyper */ -HRESULT ExtensionBase::Save(IStream *pStm, BOOL fClearDirty) +bool Extension::Load(IStream *pStm) { + ASSERT(pStm != nullptr); + if (!pStm) { - return E_POINTER; + return false; + } + + DEV_DEBUG_INFO("Extension::Load(enter)\n"); + + /** + * #NOTE: The order of these calls must match the relevant RTTIType order! + */ + if (!Extension_Load(pStm, UnitExtensions)) { return false; } + if (!Extension_Load(pStm, AircraftExtensions)) { return false; } + if (!Extension_Load(pStm, AircraftTypeExtensions)) { return false; } + if (!Extension_Load(pStm, AnimExtensions)) { return false; } + if (!Extension_Load(pStm, AnimTypeExtensions)) { return false; } + if (!Extension_Load(pStm, BuildingExtensions)) { return false; } + if (!Extension_Load(pStm, BuildingTypeExtensions)) { return false; } + //if (!Extension_Load(pStm, BulletExtensions)) { return false; } // Not yet implemented + if (!Extension_Load(pStm, BulletTypeExtensions)) { return false; } + //if (!Extension_Load(pStm, CampaignExtensions)) { return false; } // Supported, but Campaign's are not saved to file. + //if (!Extension_Load(pStm, CellExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, FactoryExtensions)) { return false; } // Not yet implemented + if (!Extension_Load(pStm, HouseExtensions)) { return false; } + if (!Extension_Load(pStm, HouseTypeExtensions)) { return false; } + if (!Extension_Load(pStm, InfantryExtensions)) { return false; } + if (!Extension_Load(pStm, InfantryTypeExtensions)) { return false; } + //if (!Extension_Load(pStm, IsometricTileExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, IsometricTileTypeExtensions)) { return false; } // Supported, but IsoTileTypes's are not saved to file. + //if (!Extension_Load(pStm, BuildingLightExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, OverlayExtensions)) { return false; } // Not yet implemented + if (!Extension_Load(pStm, OverlayTypeExtensions)) { return false; } + //if (!Extension_Load(pStm, ParticleClassExtensions)) { return false; } // Not yet implemented + if (!Extension_Load(pStm, ParticleTypeExtensions)) { return false; } + //if (!Extension_Load(pStm, ParticleSystemExtensions)) { return false; } // Not yet implemented + if (!Extension_Load(pStm, ParticleSystemTypeExtensions)) { return false; } + //if (!Extension_Load(pStm, ScriptExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, ScriptTypeExtensions)) { return false; } // Not yet implemented + if (!Extension_Load(pStm, SideExtensions)) { return false; } + //if (!Extension_Load(pStm, SmudgeExtensions)) { return false; } // Not yet implemented + if (!Extension_Load(pStm, SmudgeTypeExtensions)) { return false; } + if (!Extension_Load(pStm, SuperWeaponTypeExtensions)) { return false; } + //if (!Extension_Load(pStm, TaskForceExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, TeamExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, TeamTypeExtensions)) { return false; } // Not yet implemented + if (!Extension_Load(pStm, TerrainExtensions)) { return false; } + if (!Extension_Load(pStm, TerrainTypeExtensions)) { return false; } + //if (!Extension_Load(pStm, TriggerExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, TriggerTypeExtensions)) { return false; } // Not yet implemented + if (!Extension_Load(pStm, UnitTypeExtensions)) { return false; } + //if (!Extension_Load(pStm, VoxelAnimExtensions)) { return false; } // Not yet implemented + if (!Extension_Load(pStm, VoxelAnimTypeExtensions)) { return false; } + if (!Extension_Load(pStm, WaveExtensions)) { return false; } + //if (!Extension_Load(pStm, TagExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, TagTypeExtensions)) { return false; } // Not yet implemented + if (!Extension_Load(pStm, TiberiumExtensions)) { return false; } + //if (!Extension_Load(pStm, TActionExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, TEventExtensions)) { return false; } // Not yet implemented + if (!Extension_Load(pStm, WeaponTypeExtensions)) { return false; } + if (!Extension_Load(pStm, WarheadTypeExtensions)) { return false; } + //if (!Extension_Load(pStm, WaypointExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, TubeExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, LightSourceExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, EMPulseExtensions)) { return false; } // Not yet implemented + if (!Extension_Load(pStm, SuperExtensions)) { return false; } + //if (!Extension_Load(pStm, AITriggerExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, AITriggerExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, NeuronExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, FoggedObjectExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, AlphaShapeExtensions)) { return false; } // Not yet implemented + //if (!Extension_Load(pStm, VeinholeMonsterExtensions)) { return false; } // Not yet implemented + + if (FAILED(TacticalMapExtension->Load(pStm))) { return false; } + DEBUG_INFO("Loaded \"%s\" extension.\n", TacticalMapExtension->Name()); + TacticalMapExtension->Assign_This(TacticalMap); + + if (FAILED(RuleExtension->Load(pStm))) { return false; } + DEBUG_INFO("Loaded \"%s\" extension.\n", RuleExtension->Name()); + RuleExtension->Assign_This(Rule); + + if (FAILED(ScenExtension->Load(pStm))) { return false; } + DEBUG_INFO("Loaded \"%s\" extension.\n", ScenExtension->Name()); + ScenExtension->Assign_This(Scen); + + if (FAILED(SessionExtension->Load(pStm))) { return false; } + DEBUG_INFO("Loaded \"%s\" extension.\n", SessionExtension->Name()); + SessionExtension->Assign_This(&Session); + + /** + * Now we have sucessfully loaded the class data, request the remapping + * of all the abstract extension pointers. + */ + if (!Extension::Request_Pointer_Remap()) { return false; } + + DEV_DEBUG_INFO("Extension::Load(exit)\n"); + + return true; +} + + +/** + * Request pointer remap on all extension pointers. + * + * @author: CCHyper + */ +bool Extension::Request_Pointer_Remap() +{ + DEBUG_INFO("Extension::Request_Pointer_Remap(enter)\n"); + + /** + * #NOTE: The order of these calls must match the relevant RTTIType order! + */ + if (!Extension_Request_Pointer_Remap(Units)) { return false; } + if (!Extension_Request_Pointer_Remap(Aircrafts)) { return false; } + if (!Extension_Request_Pointer_Remap(AircraftTypes)) { return false; } + if (!Extension_Request_Pointer_Remap(Anims)) { return false; } + if (!Extension_Request_Pointer_Remap(AnimTypes)) { return false; } + if (!Extension_Request_Pointer_Remap(Buildings)) { return false; } + if (!Extension_Request_Pointer_Remap(BuildingTypes)) { return false; } + //if (!Extension_Request_Pointer_Remap(Bullets)) { return false; } // Not yet implemented + if (!Extension_Request_Pointer_Remap(BulletTypes)) { return false; } + //if (!Extension_Request_Pointer_Remap(Campaigns)) { return false; } // Does not need to be processed for pointer remapping. + //if (!Extension_Request_Pointer_Remap()) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(Factories)) { return false; } // Not yet implemented + if (!Extension_Request_Pointer_Remap(Houses)) { return false; } + if (!Extension_Request_Pointer_Remap(HouseTypes)) { return false; } + if (!Extension_Request_Pointer_Remap(Infantry)) { return false; } + if (!Extension_Request_Pointer_Remap(InfantryTypes)) { return false; } + //if (!Extension_Request_Pointer_Remap(IsoTiles)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(IsoTileTypes)) { return false; } // Does not need to be processed. + //if (!Extension_Request_Pointer_Remap(BuildingLights)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(Overlays)) { return false; } // Not yet implemented + if (!Extension_Request_Pointer_Remap(OverlayTypes)) { return false; } + //if (!Extension_Request_Pointer_Remap(Particles)) { return false; } // Not yet implemented + if (!Extension_Request_Pointer_Remap(ParticleTypes)) { return false; } + //if (!Extension_Request_Pointer_Remap(ParticleSystems)) { return false; } // Not yet implemented + if (!Extension_Request_Pointer_Remap(ParticleSystemTypes)) { return false; } + //if (!Extension_Request_Pointer_Remap(Scripts)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(ScriptTypes)) { return false; } // Not yet implemented + if (!Extension_Request_Pointer_Remap(Sides)) { return false; } + //if (!Extension_Request_Pointer_Remap(Smudges)) { return false; } // Not yet implemented + if (!Extension_Request_Pointer_Remap(SmudgeTypes)) { return false; } + if (!Extension_Request_Pointer_Remap(SuperWeaponTypes)) { return false; } + //if (!Extension_Request_Pointer_Remap(TaskForces)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(Teams)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(TeamTypes)) { return false; } // Not yet implemented + if (!Extension_Request_Pointer_Remap(Terrains)) { return false; } + if (!Extension_Request_Pointer_Remap(TerrainTypes)) { return false; } + //if (!Extension_Request_Pointer_Remap(Triggers)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(TriggerTypes)) { return false; } // Not yet implemented + if (!Extension_Request_Pointer_Remap(UnitTypes)) { return false; } + //if (!Extension_Request_Pointer_Remap(VoxelAnims)) { return false; } // Not yet implemented + if (!Extension_Request_Pointer_Remap(VoxelAnimTypes)) { return false; } + if (!Extension_Request_Pointer_Remap(Waves)) { return false; } + //if (!Extension_Request_Pointer_Remap(Tags)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(TagTypes)) { return false; } // Not yet implemented + if (!Extension_Request_Pointer_Remap(Tiberiums)) { return false; } + //if (!Extension_Request_Pointer_Remap(TActions)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(TEvents)) { return false; } // Not yet implemented + if (!Extension_Request_Pointer_Remap(WeaponTypes)) { return false; } + if (!Extension_Request_Pointer_Remap(WarheadTypes)) { return false; } + //if (!Extension_Request_Pointer_Remap(Waypoints)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(Tubes)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(LightSources)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(EMPulses)) { return false; } // Not yet implemented + if (!Extension_Request_Pointer_Remap(Supers)) { return false; } + //if (!Extension_Request_Pointer_Remap(AITriggers)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(AITriggerTypes)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(Neurons)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(FoggedObjects)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(AlphaShapes)) { return false; } // Not yet implemented + //if (!Extension_Request_Pointer_Remap(VeinholeMonsters)) { return false; } // Not yet implemented + + DEBUG_INFO("Extension::Request_Pointer_Remap(exit)\n"); + + return true; +} + + +/** + * Register the extension class COM factories. + * + * @author: CCHyper + */ +bool Extension::Register_Class_Factories() +{ + DEV_DEBUG_INFO("Extension::Register_Class_Factories(enter)\n"); + + /** + * #NOTE: The order of these calls must match the relevant RTTIType order! + */ + REGISTER_CLASS(UnitClassExtension); + REGISTER_CLASS(AircraftClassExtension); + REGISTER_CLASS(AircraftTypeClassExtension); + REGISTER_CLASS(AnimClassExtension); + REGISTER_CLASS(AnimTypeClassExtension); + REGISTER_CLASS(BuildingClassExtension); + REGISTER_CLASS(BuildingTypeClassExtension); + //REGISTER_CLASS(BulletClassExtension); // Not yet implemented + REGISTER_CLASS(BulletTypeClassExtension); + REGISTER_CLASS(CampaignClassExtension); + //REGISTER_CLASS(CellClassExtension); // Not yet implemented + //REGISTER_CLASS(FactoryClassExtension); // Not yet implemented + REGISTER_CLASS(HouseClassExtension); + REGISTER_CLASS(HouseTypeClassExtension); + REGISTER_CLASS(InfantryClassExtension); + REGISTER_CLASS(InfantryTypeClassExtension); + //REGISTER_CLASS(IsometricTileClassExtension); // Not yet implemented + REGISTER_CLASS(IsometricTileTypeClassExtension); + //REGISTER_CLASS(BuildingLightClassExtension); // Not yet implemented + //REGISTER_CLASS(OverlayClassExtension); // Not yet implemented + REGISTER_CLASS(OverlayTypeClassExtension); + //REGISTER_CLASS(ParticleClassExtension); // Not yet implemented + REGISTER_CLASS(ParticleTypeClassExtension); + //REGISTER_CLASS(ParticleSystemClassExtension); // Not yet implemented + REGISTER_CLASS(ParticleSystemTypeClassExtension); + //REGISTER_CLASS(ScriptClassExtension); // Not yet implemented + //REGISTER_CLASS(ScriptTypeClassExtension); // Not yet implemented + REGISTER_CLASS(SideClassExtension); + //REGISTER_CLASS(SmudgeClassExtension); // Not yet implemented + REGISTER_CLASS(SmudgeTypeClassExtension); + REGISTER_CLASS(SuperWeaponTypeClassExtension); + //REGISTER_CLASS(TaskForceClassExtension); // Not yet implemented + //REGISTER_CLASS(TeamClassExtension); // Not yet implemented + //REGISTER_CLASS(TeamTypeClassExtension); // Not yet implemented + REGISTER_CLASS(TerrainClassExtension); + REGISTER_CLASS(TerrainTypeClassExtension); + //REGISTER_CLASS(TriggerClassExtension); // Not yet implemented + //REGISTER_CLASS(TriggerTypeClassExtension); // Not yet implemented + REGISTER_CLASS(UnitTypeClassExtension); + //REGISTER_CLASS(VoxelAnimClassExtension); // Not yet implemented + REGISTER_CLASS(VoxelAnimTypeClassExtension); + REGISTER_CLASS(WaveClassExtension); + //REGISTER_CLASS(TagClassExtension); // Not yet implemented + //REGISTER_CLASS(TagTypeClassExtension); // Not yet implemented + REGISTER_CLASS(TiberiumClassExtension); + //REGISTER_CLASS(TActionClassExtension); // Not yet implemented + //REGISTER_CLASS(TEventClassExtension); // Not yet implemented + REGISTER_CLASS(WeaponTypeClassExtension); + REGISTER_CLASS(WarheadTypeClassExtension); + //REGISTER_CLASS(WaypointClassExtension); // Not yet implemented + //REGISTER_CLASS(TubeClassExtension); // Not yet implemented + //REGISTER_CLASS(LightSourceClassExtension); // Not yet implemented + //REGISTER_CLASS(EMPulseClassExtension); // Not yet implemented + //REGISTER_CLASS(TacticalExtension); // Tactical extension is now a global class and no longer uses COM, so we don't need to register it. + REGISTER_CLASS(SuperClassExtension); + //REGISTER_CLASS(AITriggerClassExtension); // Not yet implemented + //REGISTER_CLASS(AITriggerTypeClassExtension); // Not yet implemented + //REGISTER_CLASS(NeuronClassExtension); // Not yet implemented + //REGISTER_CLASS(FoggedObjectClassExtension); // Not yet implemented + //REGISTER_CLASS(AlphaShapeClassExtension); // Not yet implemented + //REGISTER_CLASS(VeinholeMonsterClassExtension);); // Not yet implemented + + DEV_DEBUG_INFO("Extension::Register_Class_Factories(exit)\n"); + + return true; +} + + +/** + * Clear out the extension class heaps. + * + * @author: CCHyper + */ +void Extension::Free_Heaps() +{ + DEV_DEBUG_INFO("Extension::Free_Heaps(enter)\n"); + + ++ScenarioInit; + + /** + * #NOTE: The order of these calls must match the relevant RTTIType order! + */ + UnitExtensions.Clear(); + AircraftExtensions.Clear(); + AircraftTypeExtensions.Clear(); + AnimExtensions.Clear(); + AnimTypeExtensions.Clear(); + BuildingExtensions.Clear(); + BuildingTypeExtensions.Clear(); + //BulletExtensions.Clear(); // Not yet implemented + BulletTypeExtensions.Clear(); + //CampaignExtensions.Clear(); // Campaign's do not need to be processed. + //CellExtensions.Clear(); // Not yet implemented + //FactoryExtensions.Clear(); // Not yet implemented + HouseExtensions.Clear(); + HouseTypeExtensions.Clear(); + InfantryExtensions.Clear(); + InfantryTypeExtensions.Clear(); + //IsometricTileExtensions.Clear(); // Not yet implemented + //IsometricTileTypeExtensions.Clear(); // IsoTileType's not need to be processed. + //BuildingLightExtensions.Clear(); // Not yet implemented + //OverlayExtensions.Clear(); // Not yet implemented + OverlayTypeExtensions.Clear(); + //ParticleExtensions.Clear(); // Not yet implemented + ParticleTypeExtensions.Clear(); + //ParticleSystemExtensions.Clear(); // Not yet implemented + ParticleSystemTypeExtensions.Clear(); + //ScriptExtensions.Clear(); // Not yet implemented + //ScriptTypeExtensions.Clear(); // Not yet implemented + SideExtensions.Clear(); + //SmudgeExtensions.Clear(); // Not yet implemented + SmudgeTypeExtensions.Clear(); + SuperWeaponTypeExtensions.Clear(); + //TaskForceExtensions.Clear(); // Not yet implemented + //TeamExtensions.Clear(); // Not yet implemented + //TeamTypeExtensions.Clear(); // Not yet implemented + TerrainExtensions.Clear(); + TerrainTypeExtensions.Clear(); + //TriggerExtensions.Clear(); // Not yet implemented + //TriggerTypeExtensions.Clear(); // Not yet implemented + UnitTypeExtensions.Clear(); + //VoxelAnimExtensions.Clear(); // Not yet implemented + VoxelAnimTypeExtensions.Clear(); + WaveExtensions.Clear(); + //TagExtensions.Clear(); // Not yet implemented + //TagTypeExtensions.Clear(); // Not yet implemented + TiberiumExtensions.Clear(); + //TActionExtensions.Clear(); // Not yet implemented + //TEventExtensions.Clear(); // Not yet implemented + WeaponTypeExtensions.Clear(); + WarheadTypeExtensions.Clear(); + //WaypointExtensions.Clear(); // Not yet implemented + //TubeExtensions.Clear(); // Not yet implemented + //LightSourceExtensions.Clear(); // Not yet implemented + //EMPulseExtensions.Clear(); // Not yet implemented + //delete TacticalMapExtension; // Does not need to be processed here, class has been promoted to a global. + SuperExtensions.Clear(); + //AITriggerExtensions.Clear(); // Not yet implemented + //AITriggerTypeExtensions.Clear(); // Not yet implemented + //NeuronExtensions.Clear(); // Not yet implemented + //FoggedObjectExtensions.Clear(); // Not yet implemented + //AlphaShapeExtensions.Clear(); // Not yet implemented + //VeinholeMonsterExtensions.Clear(); // Not yet implemented + + --ScenarioInit; + + DEV_DEBUG_INFO("Extension::Free_Heaps(exit)\n"); +} + + +/** + * Prints all the events from the queue list. + * + * @author: CCHyper + */ +template +static bool Print_Event_List(FILE *fp, QueueClass &list) +{ + for (int index = 0; index < DoList.Count; ++index) { + EventClass *ev = &DoList[index]; + if (ev) { + char ev_byte_format[8]; + char ev_data_buffer[128]; + int ev_size = EventClass::Event_Length(ev->Type); + for (int i = 0; i < ev_size; ++i) { + unsigned char ev_byte = ((unsigned char *)ev->Data.Variable.Pointer)[i]; // We use this union member so we can do array access. + std::snprintf(ev_byte_format, sizeof(ev_byte_format), "%02X", ev_byte); + std::strcat(ev_data_buffer, ev_byte_format); + if (i < ev_size-1) std::strcat(ev_data_buffer, " "); + } + std::fprintf(fp, "%04d %s Frame: %d ID: %d Data: %s\n", index, EventClass::Event_Name(ev->Type), ev->Frame, ev->ID, ev->Data); + } + } + return true; +} + + +/** + * Prints the unique crc for each object in the list. + * + * @author: CCHyper + */ +template +static void Print_Heap_CRC_Lists(FILE *fp, DynamicVectorClass &list) +{ + WWCRCEngine *crc = new WWCRCEngine; + + std::fprintf(fp, "\n\n********* %s CRCs ********\n\n", Extension::Utility::Get_TypeID_Name().c_str()); + std::fprintf(fp, "Index CRC\n"); + std::fprintf(fp, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); + + for (int index = 0; index < list.Count(); ++index) { + T *ptr = list[index]; + ptr->Compute_CRC(*crc); + std::fprintf(fp, "%05d %08x\n", index, crc->CRC_Value()); + EXT_DEBUG_INFO("%05d %08x\n", index, crc->CRC_Value()); } - if (fClearDirty) { - IsDirty = false; + delete crc; +} + + +/** + * Prints a data file for finding Sync Bugs. + * + * @author: CCHyper + */ +void Extension::Print_CRCs(EventClass *ev) +{ + /** + * Create a unique filename for the sync log based on the time of execution and the player name. + */ + char filename_buffer[512]; + std::snprintf(filename_buffer, sizeof(filename_buffer), "%s\\SYNC_%s-%02d_%02u-%02u-%04u_%02u-%02u-%02u.LOG", + Vinifera_DebugDirectory, + PlayerPtr->IniName, + PlayerPtr->ID, + Execute_Day, Execute_Month, Execute_Year, Execute_Hour, Execute_Min, Execute_Sec); + + /** + * Open the sync log. + */ + FILE *fp = std::fopen(filename_buffer, "w+"); + if (fp == nullptr) { + DEBUG_ERROR("Failed to open sync log file for writing!\n"); + return; } - return S_OK; + DEBUG_INFO("Writing sync log to file %s.\n", filename_buffer); + + Extension::Print_CRCs(fp, ev); + + std::fclose(fp); +} + + +/** + * Prints a data file for finding Sync Bugs. + * + * @author: CCHyper + */ +void Extension::Print_CRCs(FILE *fp, EventClass *ev) +{ + DEV_DEBUG_INFO("Extension::Print_CRCs(enter)\n"); + + char buffer[128]; + +#ifndef NDEBUG + const char *build_type = Vinifera_DeveloperMode ? "DEBUG (Dev mode enabled)" : "DEBUG"; +#else +#if defined(NIGHTLY) + const char *build_type = Vinifera_DeveloperMode ? "NIGHTLY (Dev mode enabled)" : "NIGHTLY"; +#elif defined(PREVIEW) + const char *build_type = Vinifera_DeveloperMode ? "PREVIEW (Dev mode enabled)" : "PREVIEW"; +#else + const char *build_type = Vinifera_DeveloperMode ? "RELEASE (Dev mode enabled)" : "RELEASE"; +#endif +#endif +#if defined(TS_CLIENT) + std::snprintf(buffer, sizeof(buffer), "%s [TS-Client]", build_type); + build_type = buffer; +#endif + + std::fprintf(fp, "--------------------------------------------------------------------------------\n"); + std::fprintf(fp, "--------------------- V I N I F E R A S Y N C L O G ----------------------\n"); + std::fprintf(fp, "--------------------------------------------------------------------------------\n"); + std::fprintf(fp, "\n"); + std::fprintf(fp, "Build Type : %s\n", build_type); + std::fprintf(fp, "TS++ author: %s\n", TSPP_Git_Author()); + std::fprintf(fp, "TS++ date: %s\n", TSPP_Git_DateTime()); + std::fprintf(fp, "TS++ branch: %s\n", "master"); // TSPP_Git_Branch()); + std::fprintf(fp, "TS++ commit: %s\n", TSPP_Git_Hash_Short()); + std::fprintf(fp, "TS++ local changes: %s\n", TSPP_Git_Uncommitted_Changes() ? "YES" : "NO"); + std::fprintf(fp, "Vinifera author: %s\n", Vinifera_Git_Author()); + std::fprintf(fp, "Vinifera date: %s\n", Vinifera_Git_DateTime()); + std::fprintf(fp, "Vinifera branch: %s\n", Vinifera_Git_Branch()); + std::fprintf(fp, "Vinifera commit: %s\n", Vinifera_Git_Hash_Short()); + std::fprintf(fp, "Vinifera local changes: %s\n", Vinifera_Git_Uncommitted_Changes() ? "YES" : "NO"); + std::fprintf(fp, "\n"); + std::fprintf(fp, "--------------------------------------------------------------------------------\n"); + std::fprintf(fp, "\n"); + + std::fprintf(fp, "Frames: %d\n", Frame); + std::fprintf(fp, "Player ID: %02d\n", PlayerPtr->ID); + std::fprintf(fp, "Player Name: %s\n", PlayerPtr->IniName); + //std::fprintf(fp, "Average FPS: %d\n", total_cycles_or_iterations_ > 0 ? total_fps_ / total_cycles_or_iterations_ : 0); + std::fprintf(fp, "Max MaxAhead: %d\n", Session.MaxMaxAhead); + std::fprintf(fp, "FrameSendRate: %d\n", Session.FrameSendRate); + std::fprintf(fp, "Latency setting: %d\n", Session.LatencyFudge); + std::fprintf(fp, "Game speed setting: %d\n", Options.GameSpeed); + std::fprintf(fp, "Scenario random: %d\n", Scen->RandomNumber()); + std::fprintf(fp, "Random seed: %d\n", Seed); + std::fprintf(fp, "\n"); + + /** + * Print the local addresses. + */ + if (PacketTransport) { + for (int index = 0; index < PacketTransport->Local_Addresses_Count(); ++index) { + unsigned char *addr = PacketTransport->Get_Local_Address(index); + if (addr) { + std::fprintf(fp, "Local address: %d.%d.%d.%d\n", addr[0], addr[1], addr[2], addr[3]); + } + } + } + std::fprintf(fp, "\n"); + + /** + * Print information on each of the players in the game. + */ + for (int index = 0; index < MAX_MULTI_NAMES; ++index) { + MPStatsType &player_stats = Session.Stats[index]; + if (std::strlen(player_stats.Name) > 0) { + std::fprintf(fp, "Name: %s\n", player_stats.Name); + std::fprintf(fp, "Address: %s\n", player_stats.Address.As_String()); + std::fprintf(fp, "Max avg round trip: %d\n", player_stats.MaxAvgRoundTrip); + std::fprintf(fp, "Max round trip: %d\n", player_stats.MaxRoundTrip); + std::fprintf(fp, "Resends: %d\n", player_stats.Resends); + std::fprintf(fp, "Frame sync stalls: %d\n", player_stats.FrameSyncStalls); + std::fprintf(fp, "Command count stalls: %d\n", player_stats.CommandCountStalls); + std::fprintf(fp, "Lost: %d\n", player_stats.Lost); + std::fprintf(fp, "Percent lost: %d\n", player_stats.PercentLost); + std::fprintf(fp, "\n"); + } + } + //std::fprintf(fp, "\n"); + + /** + * Print the most recent CRC values. + */ + for (int i = 0; i < 32; ++i) { + std::fprintf(fp, "CRC[%d]=%x\n", i, CRC[i]); + } + std::fprintf(fp, "\n"); + + /** + * Log the extension heap sizes. + */ + std::fprintf(fp, "-------------------------- Heap Sizes -------------------------\n"); + std::fprintf(fp, "Units.Count = %d\n", Units.Count()); + std::fprintf(fp, "Aircrafts.Count = %d\n", Aircrafts.Count()); + std::fprintf(fp, "AircraftTypes.Count = %d\n", AircraftTypes.Count()); + std::fprintf(fp, "Anims.Count = %d\n", Anims.Count()); + std::fprintf(fp, "AnimTypes.Count = %d\n", AnimTypes.Count()); + std::fprintf(fp, "Buildings.Count = %d\n", Buildings.Count()); + std::fprintf(fp, "BuildingTypes.Count = %d\n", BuildingTypes.Count()); + std::fprintf(fp, "Bullets.Count = %d\n", Bullets.Count()); + std::fprintf(fp, "BulletTypes.Count = %d\n", BulletTypes.Count()); + //std::fprintf(fp, "Campaigns.Count = %d\n", Campaigns.Count()); // Does not need to be processed as these have no impact on networking. + std::fprintf(fp, "Factories.Count = %d\n", Factories.Count()); + std::fprintf(fp, "Houses.Count = %d\n", Houses.Count()); + std::fprintf(fp, "HouseTypes.Count = %d\n", HouseTypes.Count()); + std::fprintf(fp, "Infantry.Count = %d\n", Infantry.Count()); + std::fprintf(fp, "InfantryTypes.Count = %d\n", InfantryTypes.Count()); + std::fprintf(fp, "IsometricTiles.Count = %d\n", IsoTiles.Count()); + std::fprintf(fp, "IsometricTileTypes.Count = %d\n", IsoTileTypes.Count()); + std::fprintf(fp, "BuildingLights.Count = %d\n", BuildingLights.Count()); + std::fprintf(fp, "Overlays.Count = %d\n", Overlays.Count()); + std::fprintf(fp, "OverlayTypes.Count = %d\n", OverlayTypes.Count()); + std::fprintf(fp, "Particles.Count = %d\n", Particles.Count()); + std::fprintf(fp, "ParticleTypes.Count = %d\n", ParticleTypes.Count()); + std::fprintf(fp, "ParticleSystems.Count = %d\n", ParticleSystems.Count()); + std::fprintf(fp, "ParticleSystemTypes.Count = %d\n", ParticleSystemTypes.Count()); + std::fprintf(fp, "Scripts.Count = %d\n", Scripts.Count()); + std::fprintf(fp, "ScriptTypes.Count = %d\n", ScriptTypes.Count()); + std::fprintf(fp, "Sides.Count = %d\n", Sides.Count()); + std::fprintf(fp, "Smudges.Count = %d\n", Smudges.Count()); + std::fprintf(fp, "SmudgeTypes.Count = %d\n", SmudgeTypes.Count()); + std::fprintf(fp, "SuperWeaponTypes.Count = %d\n", SuperWeaponTypes.Count()); + std::fprintf(fp, "TaskForces.Count = %d\n", TaskForces.Count()); + std::fprintf(fp, "Teams.Count = %d\n", Teams.Count()); + std::fprintf(fp, "TeamTypes.Count = %d\n", TeamTypes.Count()); + std::fprintf(fp, "Terrains.Count = %d\n", Terrains.Count()); + std::fprintf(fp, "TerrainTypes.Count = %d\n", TerrainTypes.Count()); + std::fprintf(fp, "Triggers.Count = %d\n", Triggers.Count()); + std::fprintf(fp, "TriggerTypes.Count = %d\n", TriggerTypes.Count()); + std::fprintf(fp, "UnitTypes.Count = %d\n", UnitTypes.Count()); + std::fprintf(fp, "VoxelAnims.Count = %d\n", VoxelAnims.Count()); + std::fprintf(fp, "VoxelAnimTypes.Count = %d\n", VoxelAnimTypes.Count()); + std::fprintf(fp, "Waves.Count = %d\n", Waves.Count()); + std::fprintf(fp, "Tags.Count = %d\n", Tags.Count()); + std::fprintf(fp, "TagTypes.Count = %d\n", TagTypes.Count()); + std::fprintf(fp, "Tiberiums.Count = %d\n", Tiberiums.Count()); + std::fprintf(fp, "TActions.Count = %d\n", TActions.Count()); + std::fprintf(fp, "TEvents.Count = %d\n", TEvents.Count()); + std::fprintf(fp, "WeaponTypes.Count = %d\n", WeaponTypes.Count()); + std::fprintf(fp, "WarheadTypes.Count = %d\n", WarheadTypes.Count()); + std::fprintf(fp, "WaypointPaths.Count = %d\n", WaypointPaths.Count()); + std::fprintf(fp, "Tubes.Count = %d\n", Tubes.Count()); + std::fprintf(fp, "LightSources.Count = %d\n", LightSources.Count()); + std::fprintf(fp, "Empulses.Count = %d\n", Empulses.Count()); + std::fprintf(fp, "Supers.Count = %d\n", Supers.Count()); + std::fprintf(fp, "AITriggerTypes.Count = %d\n", AITriggerTypes.Count()); + std::fprintf(fp, "FoggedObjects.Count = %d\n", FoggedObjects.Count()); + std::fprintf(fp, "AlphaShapes.Count = %d\n", AlphaShapes.Count()); + std::fprintf(fp, "VeinholeMonsters.Count = %d\n", VeinholeMonsters.Count()); + std::fprintf(fp, "\n"); + + std::fprintf(fp, "UnitExtensions.Count = %d\n", UnitExtensions.Count()); + std::fprintf(fp, "AircraftExtensions.Count = %d\n", AircraftExtensions.Count()); + std::fprintf(fp, "AircraftTypeExtensions.Count = %d\n", AircraftTypeExtensions.Count()); + std::fprintf(fp, "AnimExtensions.Count = %d\n", AnimExtensions.Count()); + std::fprintf(fp, "AnimTypeExtensions.Count = %d\n", AnimTypeExtensions.Count()); + std::fprintf(fp, "BuildingExtensions.Count = %d\n", BuildingExtensions.Count()); + std::fprintf(fp, "BuildingTypeExtensions.Count = %d\n", BuildingTypeExtensions.Count()); + //std::fprintf(fp, "BulletExtensions.Count = %d\n", BulletExtensions.Count()); // Not yet implemented + std::fprintf(fp, "BulletTypeExtensions.Count = %d\n", BulletTypeExtensions.Count()); + //std::fprintf(fp, "CampaignExtensions.Count = %d\n", CampaignExtensions.Count()); // Does not need to be logged as these have no impact on networking. + //std::fprintf(fp, "FactoryExtensions.Count = %d\n", FactoryExtensions.Count()); // Not yet implemented + std::fprintf(fp, "HouseExtensions.Count = %d\n", HouseExtensions.Count()); + std::fprintf(fp, "HouseTypeExtensions.Count = %d\n", HouseTypeExtensions.Count()); + std::fprintf(fp, "InfantryExtensions.Count = %d\n", InfantryExtensions.Count()); + std::fprintf(fp, "InfantryTypeExtensions.Count = %d\n", InfantryTypeExtensions.Count()); + //std::fprintf(fp, "IsometricTileExtensions.Count = %d\n", IsometricTileExtensions.Count()); // Not yet implemented + std::fprintf(fp, "IsometricTileTypeExtensions.Count = %d\n", IsometricTileTypeExtensions.Count()); + //std::fprintf(fp, "BuildingLightExtensions.Count = %d\n", BuildingLightExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "OverlayExtensions.Count = %d\n", OverlayExtensions.Count()); // Not yet implemented + std::fprintf(fp, "OverlayTypeExtensions.Count = %d\n", OverlayTypeExtensions.Count()); + //std::fprintf(fp, "ParticleExtensions.Count = %d\n", ParticleExtensions.Count()); // Not yet implemented + std::fprintf(fp, "ParticleTypeExtensions.Count = %d\n", ParticleTypeExtensions.Count()); + //std::fprintf(fp, "ParticleSystemExtensions.Count = %d\n", ParticleSystemExtensions.Count()); // Not yet implemented + std::fprintf(fp, "ParticleSystemTypeExtensions.Count = %d\n", ParticleSystemTypeExtensions.Count()); + //std::fprintf(fp, "ScriptExtensions.Count = %d\n", ScriptExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "ScriptTypeExtensions.Count = %d\n", ScriptTypeExtensions.Count()); // Not yet implemented + std::fprintf(fp, "SideExtensions.Count = %d\n", SideExtensions.Count()); + //std::fprintf(fp, "SmudgeExtensions.Count = %d\n", SmudgeExtensions.Count()); // Not yet implemented + std::fprintf(fp, "SmudgeTypeExtensions.Count = %d\n", SmudgeTypeExtensions.Count()); + std::fprintf(fp, "SuperWeaponTypeExtensions.Count = %d\n", SuperWeaponTypeExtensions.Count()); + //std::fprintf(fp, "TaskForceExtensions.Count = %d\n", TaskForceExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "TeamExtensions.Count = %d\n", TeamExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "TeamTypeExtensions.Count = %d\n", TeamTypeExtensions.Count()); // Not yet implemented + std::fprintf(fp, "TerrainExtensions.Count = %d\n", TerrainExtensions.Count()); + std::fprintf(fp, "TerrainTypeExtensions.Count = %d\n", TerrainTypeExtensions.Count()); + //std::fprintf(fp, "TriggerExtensions.Count = %d\n", TriggerExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "TriggerTypeExtensions.Count = %d\n", TriggerTypeExtensions.Count()); // Not yet implemented + std::fprintf(fp, "UnitTypeExtensions.Count = %d\n", UnitTypeExtensions.Count()); + //std::fprintf(fp, "VoxelAnimExtensions.Count = %d\n", VoxelAnimExtensions.Count()); // Not yet implemented + std::fprintf(fp, "VoxelAnimTypeExtensions.Count = %d\n", VoxelAnimTypeExtensions.Count()); + std::fprintf(fp, "WaveExtensions.Count = %d\n", WaveExtensions.Count()); + //std::fprintf(fp, "TagExtensions.Count = %d\n", TagExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "TagTypeExtensions.Count = %d\n", TagTypeExtensions.Count()); // Not yet implemented + std::fprintf(fp, "TiberiumExtensions.Count = %d\n", TiberiumExtensions.Count()); + //std::fprintf(fp, "TActionExtensions.Count = %d\n", TActionExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "TEventExtensions.Count = %d\n", TEventExtensions.Count()); // Not yet implemented + std::fprintf(fp, "WeaponTypeExtensions.Count = %d\n", WeaponTypeExtensions.Count()); + std::fprintf(fp, "WarheadTypeExtensions.Count = %d\n", WarheadTypeExtensions.Count()); + //std::fprintf(fp, "WaypointExtensions.Count = %d\n", WaypointExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "TubeExtensions.Count = %d\n", TubeExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "LightSourceExtensions.Count = %d\n", LightSourceExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "EMPulseExtensions.Count = %d\n", EMPulseExtensions.Count()); // Not yet implemented + std::fprintf(fp, "SuperExtensions.Count = %d\n", SuperExtensions.Count()); + //std::fprintf(fp, "AITriggerExtensions.Count = %d\n", AITriggerExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "AITriggerTypeExtensions.Count = %d\n", AITriggerTypeExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "NeuronExtensions.Count = %d\n", NeuronExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "FoggedObjectExtensions.Count = %d\n", FoggedObjectExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "AlphaShapeExtensions.Count = %d\n", AlphaShapeExtensions.Count()); // Not yet implemented + //std::fprintf(fp, "VeinholeMonsterExtensions.Count = %d\n", VeinholeMonsterExtensions.Count()); // Not yet implemented + std::fprintf(fp, "\n"); + + std::fprintf(fp, "Map.Array.Length = %d\n", Map.Array.Length()); + //std::fprintf(fp, "CellExtensions.Count = %d\n", CellExtensions.Count()); // Not yet implemented + std::fprintf(fp, "\n"); + + /** + * Houses + */ + for (int house = 0; house < Houses.Count(); ++house) { + GameCRC = 0; + HouseClass *housep = Houses[house]; + if (housep) { + //const char *a = HouseTypes[housep->ID]->Name(); + //const char *b = housep->ActLike != SIDE_NONE ? Sides[housep->ActLike]->Name() : ""; + std::fprintf(fp, "%s: IsHuman:%d Color:%s ID:%d HouseType:%s ActLike:%s\n", + housep->IniName, + housep->IsHuman, + ColorSchemes[housep->RemapColor]->Name, + housep->ID, + housep->Class->Name(), + housep->ActLike != SIDE_NONE ? Sides[housep->ActLike]->Name() : ""); + Add_CRC(&GameCRC, (int)housep->Credits + (int)housep->Power + (int)housep->Drain); + EXT_DEBUG_INFO("House %s:%x\n", housep->Class->Name(), GameCRC); + } + } + std::fprintf(fp, "\n"); + + /** + * Infantry + */ + for (int house = 0; house <= Houses.Count(); ++house) { + HouseClass *housep = Houses[house]; + if (housep) { + GameCRC = 0; + std::fprintf(fp, "------------- %s (%s %d) %s ------------\n", housep->Class->Name(), housep->IniName, housep->ID, Extension::Utility::Get_TypeID_Name().c_str()); + for (int index = 0; index < Infantry.Count(); ++index) { + InfantryClass *ptr = Infantry[index]; + if (ptr->Owner() == house) { + Add_CRC(&GameCRC, (int)((ptr->Get_Coord().X / 10) << 16) + (int)(ptr->Get_Coord().Y / 10) + (int)ptr->PrimaryFacing.Current().Get_Dir()); + + const char *tarcom_name = "None"; + Coordinate tarcom_coord; + + const char *navcom_name = "None"; + Coordinate navcom_coord; + + if (ptr->TarCom) { + tarcom_name = Name_From_RTTI((RTTIType)ptr->TarCom->What_Am_I()); + tarcom_coord = ptr->TarCom->Center_Coord(); + } + + if (ptr->NavCom) { + navcom_name = Name_From_RTTI((RTTIType)ptr->NavCom->What_Am_I()); + navcom_coord = ptr->NavCom->Center_Coord(); + } + + std::fprintf(fp, "COORD:%d,%d,%d Facing:%d Mission:%s Type:%s(%d) Speed:%d TarCom:%s(%d,%d,%d) NavCom:%s(%d,%d,%d)\n", + ptr->Center_Coord().X, ptr->Center_Coord().Y, ptr->Center_Coord().Z, + (int)ptr->PrimaryFacing.Current().Get_Dir(), MissionClass::Mission_Name(ptr->Get_Mission()), + ptr->Class->Name(), ptr->Class->Type, + (int)(ptr->Speed * 256.0), + tarcom_name, tarcom_coord.X, tarcom_coord.Y, tarcom_coord.Z, + navcom_name, navcom_coord.X, navcom_coord.Y, navcom_coord.Z); + } + } + EXT_DEBUG_INFO("%s %s:%x\n", housep->Class->Name(), Extension::Utility::Get_TypeID_Name().c_str(), GameCRC); + } + std::fprintf(fp, "\n"); + } + + /** + * Units + */ + for (int house = 0; house <= Houses.Count(); ++house) { + HouseClass *housep = Houses[house]; + if (housep) { + GameCRC = 0; + std::fprintf(fp, "------------- %s (%s %d) %s ------------\n", housep->Class->Name(), housep->IniName, housep->ID, Extension::Utility::Get_TypeID_Name().c_str()); + for (int index = 0; index < Units.Count(); ++index) { + UnitClass *ptr = Units[index]; + if (ptr->Owner() == house) { + Add_CRC(&GameCRC, (int)((ptr->Get_Coord().X / 10) << 16) + (int)(ptr->Get_Coord().Y / 10) + (int)ptr->PrimaryFacing.Current().Get_Dir()); + + const char *tarcom_name = "None"; + Coordinate tarcom_coord; + + const char *navcom_name = "None"; + Coordinate navcom_coord; + + if (ptr->TarCom) { + tarcom_name = Name_From_RTTI((RTTIType)ptr->TarCom->What_Am_I()); + tarcom_coord = ptr->TarCom->Center_Coord(); + } + + if (ptr->NavCom) { + navcom_name = Name_From_RTTI((RTTIType)ptr->NavCom->What_Am_I()); + navcom_coord = ptr->NavCom->Center_Coord(); + } + + std::fprintf(fp, "COORD:%d,%d,%d Facing:%d Facing2:%d Mission:%s Type:%s(%d) TarCom:%s(%d,%d,%d) NavCom:%s(%d,%d,%d) TrkNum:%d TrkInd:%d SpdAcc:%d\n", + ptr->Center_Coord().X, ptr->Center_Coord().Y, ptr->Center_Coord().Z, + (int)ptr->PrimaryFacing.Current().Get_Dir(), (int)ptr->SecondaryFacing.Current().Get_Dir(), MissionClass::Mission_Name(ptr->Get_Mission()), + ptr->Class->Name(), ptr->Class->Type, + tarcom_name, tarcom_coord.X, tarcom_coord.Y, tarcom_coord.Z, + navcom_name, navcom_coord.X, navcom_coord.Y, navcom_coord.Z, + ptr->Locomotor_Ptr()->Get_Track_Number(), ptr->Locomotor_Ptr()->Get_Track_Number(), ptr->Locomotor_Ptr()->Get_Speed_Accum()); + } + } + EXT_DEBUG_INFO("%s %s:%x\n", housep->Class->Name(), Extension::Utility::Get_TypeID_Name().c_str(), GameCRC); + } + std::fprintf(fp, "\n"); + } + + /** + * Buildings + */ + for (int house = 0; house <= Houses.Count(); ++house) { + HouseClass *housep = Houses[house]; + if (housep) { + GameCRC = 0; + std::fprintf(fp, "------------- %s (%s %d) %s ------------\n", housep->Class->Name(), housep->IniName, housep->ID, Extension::Utility::Get_TypeID_Name().c_str()); + for (int index = 0; index < Buildings.Count(); ++index) { + BuildingClass *ptr = Buildings[index]; + if (ptr->Owner() == house) { + Add_CRC(&GameCRC, (int)((ptr->Get_Coord().X / 10) << 16) + (int)(ptr->Get_Coord().Y / 10) + (int)ptr->PrimaryFacing.Current().Get_Dir()); + + const char *tarcom_name = "None"; + Coordinate tarcom_coord; + + if (ptr->TarCom) { + tarcom_name = Name_From_RTTI((RTTIType)ptr->TarCom->What_Am_I()); + tarcom_coord = ptr->TarCom->Center_Coord(); + } + + std::fprintf(fp, "COORD:%d,%d,%d Facing:%d Mission:%s Type:%s(%d) TarCom:%s(%d,%d,%d)\n", + ptr->Center_Coord().X, ptr->Center_Coord().Y, ptr->Center_Coord().Z, + (int)ptr->PrimaryFacing.Current().Get_Dir(), MissionClass::Mission_Name(ptr->Get_Mission()), + ptr->Class->Name(), ptr->Class->Type, + tarcom_name, tarcom_coord.X, tarcom_coord.Y, tarcom_coord.Z); + } + } + EXT_DEBUG_INFO("%s %s:%x\n", housep->Class->Name(), Extension::Utility::Get_TypeID_Name().c_str(), GameCRC); + } + std::fprintf(fp, "\n"); + } + + /** + * Units + */ + for (int house = 0; house <= Houses.Count(); ++house) { + HouseClass *housep = Houses[house]; + if (housep) { + GameCRC = 0; + std::fprintf(fp, "------------- %s (%s %d) %s ------------\n", housep->Class->Name(), housep->IniName, housep->ID, Extension::Utility::Get_TypeID_Name().c_str()); + for (int index = 0; index < Aircrafts.Count(); ++index) { + AircraftClass *ptr = Aircrafts[index]; + if (ptr->Owner() == house) { + Add_CRC(&GameCRC, (int)((ptr->Get_Coord().X / 10) << 16) + (int)(ptr->Get_Coord().Y / 10) + (int)ptr->PrimaryFacing.Current().Get_Dir()); + + const char *tarcom_name = "None"; + Coordinate tarcom_coord; + + const char *navcom_name = "None"; + Coordinate navcom_coord; + + if (ptr->TarCom) { + tarcom_name = Name_From_RTTI((RTTIType)ptr->TarCom->What_Am_I()); + tarcom_coord = ptr->TarCom->Center_Coord(); + } + + if (ptr->NavCom) { + navcom_name = Name_From_RTTI((RTTIType)ptr->NavCom->What_Am_I()); + navcom_coord = ptr->NavCom->Center_Coord(); + } + + std::fprintf(fp, "COORD:%d,%d,%d Facing:%d Mission:%s Type:%s(%d) TarCom:%s(%d,%d,%d) NavCom:%s(%d,%d,%d)\n", + ptr->Center_Coord().X, ptr->Center_Coord().Y, ptr->Center_Coord().Z, + (int)ptr->PrimaryFacing.Current().Get_Dir(), MissionClass::Mission_Name(ptr->Get_Mission()), + ptr->Class->Name(), ptr->Class->Type, + tarcom_name, tarcom_coord.X, tarcom_coord.Y, tarcom_coord.Z, + navcom_name, navcom_coord.X, navcom_coord.Y, navcom_coord.Z); + } + } + EXT_DEBUG_INFO("%s %s:%x\n", housep->Class->Name(), Extension::Utility::Get_TypeID_Name().c_str(), GameCRC); + } + std::fprintf(fp, "\n"); + } + + /** + * Animations + */ + std::fprintf(fp, "-------------------- Animations -------------------\n"); + for (int index = 0; index < Anims.Count(); ++index) { + AnimClass *animp = Anims[index]; + std::fprintf(fp, "Target:%x OwnerHouse:%d Loops:%d\n", + (uintptr_t)animp->xObject, + animp->OwnerHouse, + animp->Loops); + } + std::fprintf(fp, "\n"); + + /** + * Map Layers + */ + GameCRC = 0; + for (LayerType layer = LAYER_FIRST; layer < LAYER_COUNT; ++layer) { + std::fprintf(fp, ">>>> MAP LAYER %s (%d) <<<<\n", Name_From_Layer(layer), layer); + for (int index = 0; index < Map.Layer[layer].Count(); ++index) { + ObjectClass *objp = Map.Layer[layer][index]; + Add_CRC(&GameCRC, (int)((objp->Get_Coord().X / 10) << 16) + (int)(objp->Get_Coord().Y / 10)); + std::fprintf(fp, "Object %d: %s ", index, objp->Coord.As_String()); + switch (objp->What_Am_I()) { + case RTTI_AIRCRAFT: + std::fprintf(fp, "Aircraft (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_ANIM: + std::fprintf(fp, "Anim (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_BUILDING: + std::fprintf(fp, "Building (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_BULLET: + std::fprintf(fp, "Bullet (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_INFANTRY: + std::fprintf(fp, "Infantry (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_OVERLAY: + std::fprintf(fp, "Overlay (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_SMUDGE: + std::fprintf(fp, "Smudge (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_TERRAIN: + std::fprintf(fp, "Terrain (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_UNIT: + std::fprintf(fp, "Unit (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + }; + HouseClass *housep = objp->Owning_House(); + if (housep) { + std::fprintf(fp, "Owner: %s\n", housep->Class->IniName); + } else { + std::fprintf(fp, "Owner: NONE\n"); + } + } + std::fprintf(fp, "\n"); + } + std::fprintf(fp, "\n"); + EXT_DEBUG_INFO("Map Layers: %x\n", GameCRC); + + /** + * Logic Layers + */ + GameCRC = 0; + std::fprintf(fp, ">>>> LOGIC LAYER <<<<\n"); + for (int index = 0; index < Logic.Count(); ++index) { + ObjectClass *objp = Logic[index]; + Add_CRC(&GameCRC, (int)((objp->Get_Coord().X / 10) << 16) + (int)(objp->Get_Coord().Y / 10)); + std::fprintf(fp, "Object %d: %s ", index, objp->Coord.As_String()); + switch (objp->What_Am_I()) { + case RTTI_AIRCRAFT: + std::fprintf(fp, "Aircraft (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_ANIM: + std::fprintf(fp, "Anim (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_BUILDING: + std::fprintf(fp, "Building (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_BULLET: + std::fprintf(fp, "Bullet (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_INFANTRY: + std::fprintf(fp, "Infantry (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_OVERLAY: + std::fprintf(fp, "Overlay (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_SMUDGE: + std::fprintf(fp, "Smudge (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_TERRAIN: + std::fprintf(fp, "Terrain (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + case RTTI_UNIT: + std::fprintf(fp, "Unit (Type:%s (%d)) ", objp->Name(), objp->Get_Heap_ID()); + break; + }; + HouseClass *housep = objp->Owning_House(); + if (housep) { + std::fprintf(fp, "Owner: %s\n", housep->Class->IniName); + } else { + std::fprintf(fp, "Owner: NONE\n"); + } + } + std::fprintf(fp, "\n"); + EXT_DEBUG_INFO("Logic: %x\n", GameCRC); + + /** + * Random # generator, frame #. + */ + std::fprintf(fp, "\nRandom Number:%x\n", Scen->RandomNumber()); + EXT_DEBUG_INFO("Random Number: %x\n", Scen->RandomNumber()); + + std::fprintf(fp, "My Frame:%d\n", Frame); + EXT_DEBUG_INFO("My Frame: %d\n", Frame); + + if (ev) { + std::fprintf(fp, "\n"); + std::fprintf(fp, "Offending event:\n"); + std::fprintf(fp, " Type: %s\n", EventClass::Event_Name(ev->Type)); + std::fprintf(fp, " Frame: %d\n", ev->Frame); + std::fprintf(fp, " ID: %x\n", ev->ID); + std::fprintf(fp, " CRC: %x\n", ev->Data.FrameInfo.CRC); + std::fprintf(fp, " CommandCount: %d\n", ev->Data.FrameInfo.CommandCount); + std::fprintf(fp, " Delay: %d\n", ev->Data.FrameInfo.Delay); + } + std::fprintf(fp, "\n"); + + /** + * Event queues. + */ + std::fprintf(fp, "-------------------- DoList Events -------------------\n"); + Print_Event_List(fp, DoList); + std::fprintf(fp, "\n"); + + std::fprintf(fp, "-------------------- OutList Events -------------------\n"); + Print_Event_List(fp, OutList); + std::fprintf(fp, "\n"); + + /** + * Print heap CRC's. + */ + Print_Heap_CRC_Lists(fp, Units); + Print_Heap_CRC_Lists(fp, Aircrafts); + Print_Heap_CRC_Lists(fp, AircraftTypes); + Print_Heap_CRC_Lists(fp, Anims); + Print_Heap_CRC_Lists(fp, AnimTypes); + Print_Heap_CRC_Lists(fp, Buildings); + Print_Heap_CRC_Lists(fp, BuildingTypes); + Print_Heap_CRC_Lists(fp, Bullets); + Print_Heap_CRC_Lists(fp, BulletTypes); + //Print_Heap_CRC_Lists(fp, Campaigns); // Does not need to be processed as these have no impact on networking. + Print_Heap_CRC_Lists(fp, Factories); + Print_Heap_CRC_Lists(fp, Houses); + Print_Heap_CRC_Lists(fp, HouseTypes); + Print_Heap_CRC_Lists(fp, Infantry); + Print_Heap_CRC_Lists(fp, InfantryTypes); + Print_Heap_CRC_Lists(fp, IsoTiles); + Print_Heap_CRC_Lists(fp, IsoTileTypes); + Print_Heap_CRC_Lists(fp, BuildingLights); + Print_Heap_CRC_Lists(fp, Overlays); + Print_Heap_CRC_Lists(fp, OverlayTypes); + Print_Heap_CRC_Lists(fp, Particles); + Print_Heap_CRC_Lists(fp, ParticleTypes); + Print_Heap_CRC_Lists(fp, ParticleSystems); + Print_Heap_CRC_Lists(fp, ParticleSystemTypes); + Print_Heap_CRC_Lists(fp, Scripts); + Print_Heap_CRC_Lists(fp, ScriptTypes); + Print_Heap_CRC_Lists(fp, Sides); + Print_Heap_CRC_Lists(fp, Smudges); + Print_Heap_CRC_Lists(fp, SmudgeTypes); + Print_Heap_CRC_Lists(fp, SuperWeaponTypes); + Print_Heap_CRC_Lists(fp, TaskForces); + Print_Heap_CRC_Lists(fp, Teams); + Print_Heap_CRC_Lists(fp, TeamTypes); + Print_Heap_CRC_Lists(fp, Terrains); + Print_Heap_CRC_Lists(fp, TerrainTypes); + Print_Heap_CRC_Lists(fp, Triggers); + Print_Heap_CRC_Lists(fp, TriggerTypes); + Print_Heap_CRC_Lists(fp, UnitTypes); + Print_Heap_CRC_Lists(fp, VoxelAnims); + Print_Heap_CRC_Lists(fp, VoxelAnimTypes); + Print_Heap_CRC_Lists(fp, Waves); + Print_Heap_CRC_Lists(fp, Tags); + Print_Heap_CRC_Lists(fp, TagTypes); + Print_Heap_CRC_Lists(fp, Tiberiums); + Print_Heap_CRC_Lists(fp, TActions); + Print_Heap_CRC_Lists(fp, TEvents); + Print_Heap_CRC_Lists(fp, WeaponTypes); + Print_Heap_CRC_Lists(fp, WarheadTypes); + Print_Heap_CRC_Lists(fp, WaypointPaths); + Print_Heap_CRC_Lists(fp, Tubes); + Print_Heap_CRC_Lists(fp, LightSources); + Print_Heap_CRC_Lists(fp, Empulses); + Print_Heap_CRC_Lists(fp, Supers); + Print_Heap_CRC_Lists(fp, AITriggerTypes); + Print_Heap_CRC_Lists(fp, FoggedObjects); + Print_Heap_CRC_Lists(fp, AlphaShapes); + Print_Heap_CRC_Lists(fp, VeinholeMonsters); + + /** + * Print extension heap CRC's. + */ + Print_Heap_CRC_Lists(fp, UnitExtensions); + Print_Heap_CRC_Lists(fp, AircraftExtensions); + Print_Heap_CRC_Lists(fp, AircraftTypeExtensions); + Print_Heap_CRC_Lists(fp, AnimExtensions); + Print_Heap_CRC_Lists(fp, AnimTypeExtensions); + Print_Heap_CRC_Lists(fp, BuildingExtensions); + Print_Heap_CRC_Lists(fp, BuildingTypeExtensions); + //Print_Heap_CRC_Lists(fp, BulletExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, BulletTypeExtensions); + //Print_Heap_CRC_Lists(fp, CampaignExtensions); // Does not need to be processed as these have no impact on networking. + //Print_Heap_CRC_Lists(fp, CellExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, FactoryExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, HouseExtensions); + Print_Heap_CRC_Lists(fp, HouseTypeExtensions); + Print_Heap_CRC_Lists(fp, InfantryExtensions); + Print_Heap_CRC_Lists(fp, InfantryTypeExtensions); + //Print_Heap_CRC_Lists(fp, IsometricTileExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, IsometricTileTypeExtensions); + //Print_Heap_CRC_Lists(fp, BuildingLightExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, OverlayExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, OverlayTypeExtensions); + //Print_Heap_CRC_Lists(fp, ParticleExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, ParticleTypeExtensions); + //Print_Heap_CRC_Lists(fp, ParticleSystemExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, ParticleSystemTypeExtensions); + //Print_Heap_CRC_Lists(fp, ScriptExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, ScriptTypeExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, SideExtensions); + //Print_Heap_CRC_Lists(fp, SmudgeExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, SmudgeTypeExtensions); + Print_Heap_CRC_Lists(fp, SuperWeaponTypeExtensions); + //Print_Heap_CRC_Lists(fp, TaskForceExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, TeamExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, TeamTypeExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, TerrainExtensions); + Print_Heap_CRC_Lists(fp, TerrainTypeExtensions); + //Print_Heap_CRC_Lists(fp, TriggerExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, TriggerTypeExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, UnitTypeExtensions); + //Print_Heap_CRC_Lists(fp, VoxelAnimExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, VoxelAnimTypeExtensions); + Print_Heap_CRC_Lists(fp, WaveExtensions); + //Print_Heap_CRC_Lists(fp, TagExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, TagTypeExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, TiberiumExtensions); + //Print_Heap_CRC_Lists(fp, TActionExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, TEventExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, WeaponTypeExtensions); + Print_Heap_CRC_Lists(fp, WarheadTypeExtensions); + //Print_Heap_CRC_Lists(fp, WaypointExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, TubeExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, LightSourceExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, EMPulseExtensions); // Not yet implemented + Print_Heap_CRC_Lists(fp, SuperExtensions); + //Print_Heap_CRC_Lists(fp, AITriggerExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, AITriggerTypeExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, NeuronExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, FoggedObjectExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, AlphaShapeExtensions); // Not yet implemented + //Print_Heap_CRC_Lists(fp, VeinholeMonsterExtensions); // Not yet implemented + + DEV_DEBUG_INFO("Extension::Print_CRCs(exit)\n"); +} + + +/** + * Detaches this object from all active extension classes. + * + * @author: CCHyper + */ +void Extension::Detach_This_From_All(TARGET target, bool all) +{ + //DEV_DEBUG_INFO("Extension::Detach_This_From_All(enter)\n"); + + /** + * #NOTE: The order of these calls must match the relevant RTTIType order! + */ + Extension_Detach_This_From_All(UnitExtensions, target, all); + Extension_Detach_This_From_All(AircraftExtensions, target, all); + Extension_Detach_This_From_All(AircraftTypeExtensions, target, all); + Extension_Detach_This_From_All(AnimExtensions, target, all); + Extension_Detach_This_From_All(AnimTypeExtensions, target, all); + Extension_Detach_This_From_All(BuildingExtensions, target, all); + Extension_Detach_This_From_All(BuildingTypeExtensions, target, all); + //Extension_Detach_This_From_All(BulletExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(BulletTypeExtensions, target, all); + //Extension_Detach_This_From_All(CampaignExtensions, target, all); // Does not need to be processed. + //Extension_Detach_This_From_All(CellExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(FactoryExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(HouseExtensions, target, all); + Extension_Detach_This_From_All(HouseTypeExtensions, target, all); + Extension_Detach_This_From_All(InfantryExtensions, target, all); + Extension_Detach_This_From_All(InfantryTypeExtensions, target, all); + //Extension_Detach_This_From_All(IsometricTileExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(IsometricTileTypeExtensions, target, all); + //Extension_Detach_This_From_All(BuildingLightExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(OverlayExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(OverlayTypeExtensions, target, all); + //Extension_Detach_This_From_All(ParticleExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(ParticleTypeExtensions, target, all); + //Extension_Detach_This_From_All(ParticleSystemExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(ParticleSystemTypeExtensions, target, all); + //Extension_Detach_This_From_All(ScriptExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(ScriptTypeExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(SideExtensions, target, all); + //Extension_Detach_This_From_All(SmudgeExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(SmudgeTypeExtensions, target, all); + Extension_Detach_This_From_All(SuperWeaponTypeExtensions, target, all); + //Extension_Detach_This_From_All(TaskForceExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(TeamExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(TeamTypeExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(TerrainExtensions, target, all); + Extension_Detach_This_From_All(TerrainTypeExtensions, target, all); + //Extension_Detach_This_From_All(TriggerExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(TriggerTypeExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(UnitTypeExtensions, target, all); + //Extension_Detach_This_From_All(VoxelAnimExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(VoxelAnimTypeExtensions, target, all); + Extension_Detach_This_From_All(WaveExtensions, target, all); + //Extension_Detach_This_From_All(TagExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(TagTypeExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(TiberiumExtensions, target, all); + //Extension_Detach_This_From_All(TActionExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(TEventExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(WeaponTypeExtensions, target, all); + Extension_Detach_This_From_All(WarheadTypeExtensions, target, all); + //Extension_Detach_This_From_All(WaypointExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(TubeExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(LightSourceExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(EMPulseExtensions, target, all); // Not yet implemented + Extension_Detach_This_From_All(SuperExtensions, target, all); + //Extension_Detach_This_From_All(AITriggerExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(AITriggerTypeExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(NeuronExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(FoggedObjectExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(AlphaShapeExtensions, target, all); // Not yet implemented + //Extension_Detach_This_From_All(VeinholeMonsterExtensions, target, all); // Not yet implemented + + TacticalMapExtension->Detach(target, all); + RuleExtension->Detach(target, all); + ScenExtension->Detach(target, all); + SessionExtension->Detach(target, all); + + //DEV_DEBUG_INFO("Extension::Detach_This_From_All(exit)\n"); +} + + +/** + * Calculate the save game version. + * + * @author: CCHyper + */ +unsigned Extension::Get_Save_Version_Number() +{ + unsigned version = 0x100000; + + /** + * For debug builds, offset the save file version. + */ +#ifndef NDEBUG + version += 0x10000000; +#endif + + /** + * Game classes. + */ + version += sizeof(UnitClassExtension); + version += sizeof(AircraftClassExtension); + version += sizeof(AircraftTypeClassExtension); + version += sizeof(AnimClassExtension); + version += sizeof(AnimTypeClassExtension); + version += sizeof(BuildingClassExtension); + version += sizeof(BuildingTypeClassExtension); + //version += sizeof(BulletClassExtension); // Not yet implemented + version += sizeof(BulletTypeClassExtension); + version += sizeof(CampaignClassExtension); + //version += sizeof(CellClassExtension); // Not yet implemented + //version += sizeof(FactoryClassExtension); // Not yet implemented + version += sizeof(HouseClassExtension); + version += sizeof(HouseTypeClassExtension); + version += sizeof(InfantryClassExtension); + version += sizeof(InfantryTypeClassExtension); + //version += sizeof(IsometricTileClassExtension); // Not yet implemented + version += sizeof(IsometricTileTypeClassExtension); + //version += sizeof(BuildingLightClassExtension); // Not yet implemented + //version += sizeof(OverlayClassExtension); // Not yet implemented + version += sizeof(OverlayTypeClassExtension); + //version += sizeof(ParticleClassExtension); // Not yet implemented + version += sizeof(ParticleTypeClassExtension); + //version += sizeof(ParticleSystemClassExtension); // Not yet implemented + version += sizeof(ParticleSystemTypeClassExtension); + //version += sizeof(ScriptClassExtension); // Not yet implemented + //version += sizeof(ScriptTypeClassExtension); // Not yet implemented + version += sizeof(SideClassExtension); + //version += sizeof(SmudgeClassExtension); // Not yet implemented + version += sizeof(SmudgeTypeClassExtension); + version += sizeof(SuperWeaponTypeClassExtension); + //version += sizeof(TaskForceClassExtension); // Not yet implemented + //version += sizeof(TeamClassExtension); // Not yet implemented + //version += sizeof(TeamTypeClassExtension); // Not yet implemented + version += sizeof(TerrainClassExtension); + version += sizeof(TerrainTypeClassExtension); + //version += sizeof(TriggerClassExtension); // Not yet implemented + //version += sizeof(TriggerTypeClassExtension); // Not yet implemented + version += sizeof(UnitTypeClassExtension); + //version += sizeof(VoxelAnimClassExtension); // Not yet implemented + version += sizeof(VoxelAnimTypeClassExtension); + version += sizeof(WaveClassExtension); + //version += sizeof(TagClassExtension); // Not yet implemented + //version += sizeof(TagTypeClassExtension); // Not yet implemented + version += sizeof(TiberiumClassExtension); + //version += sizeof(TActionClassExtension); // Not yet implemented + //version += sizeof(TEventClassExtension); // Not yet implemented + version += sizeof(WeaponTypeClassExtension); + version += sizeof(WarheadTypeClassExtension); + //version += sizeof(WaypointClassExtension); // Not yet implemented + //version += sizeof(TubeClassExtension); // Not yet implemented + //version += sizeof(LightSourceClassExtension); // Not yet implemented + //version += sizeof(EMPulseClassExtension); // Not yet implemented + version += sizeof(SuperClassExtension); + //version += sizeof(AITriggerClassExtension); // Not yet implemented + //version += sizeof(AITriggerTypeClassExtension); // Not yet implemented + //version += sizeof(NeuronClassExtension); // Not yet implemented + //version += sizeof(FoggedObjectClassExtension); // Not yet implemented + //version += sizeof(AlphaShapeClassExtension); // Not yet implemented + //version += sizeof(VeinholeMonsterClassExtension); // Not yet implemented + + /** + * Global classes. + */ + version += sizeof(TacticalExtension); // We ignore the fact that Tactical is an abstract derived class, as we treat the extension as a global. + version += sizeof(RulesClassExtension); + version += sizeof(ScenarioClassExtension); + version += sizeof(SessionClassExtension); + + /** + * All other classes. + */ + version += sizeof(ThemeControlExtension); + + return version; } diff --git a/src/extensions/extension.h b/src/extensions/extension.h index 90a32814..cc225670 100644 --- a/src/extensions/extension.h +++ b/src/extensions/extension.h @@ -8,7 +8,7 @@ * * @author CCHyper * - * @brief Base class for declaring extended class instances. + * @brief The file contains the functions required for the extension system. * * @license Vinifera is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,219 +28,430 @@ #pragma once #include "always.h" -#include "tibsun_defines.h" -#include "tibsun_globals.h" +#include "vinifera_defines.h" +#include "extension_globals.h" +#include "abstract.h" +#include "abstractext.h" #include "swizzle.h" #include "noinit.h" #include "debughandler.h" +#include "asserthandler.h" + +#include // for IStream +#include +#include + + +class EventClass; +class WWCRCEngine; + + +namespace Extension +{ /** - * Included here so all extended classes don't have to. + * Do not call these directly! Use the template functions below. */ -#include "hooker.h" -#include "hooker_macros.h" +namespace Private +{ -#include // for IStream. +AbstractClassExtension *Make_Internal(const AbstractClass *abstract); +bool Destroy_Internal(const AbstractClass *abstract); +AbstractClassExtension *Fetch_Internal(const AbstractClass *abstract); +}; // namespace "Extension::Private". -class WWCRCEngine; +namespace Utility +{ + +/** + * Erase First Occurrence of given substring from main string. + * + * @author: CCHyper + */ +inline void Erase_Sub_String(std::string &str, const std::string &erase) +{ + /** + * Search for the substring in string. + */ + size_t pos = str.find(erase); + if (pos != std::string::npos) { + + /** + * If found then erase it from string. + */ + str.erase(pos, erase.length()); + } +} + +/** + * Wrapper for "typeid(T).name()", removes the "class" or "struct" prefix on the string. + * + * @author: CCHyper + */ +template +std::string Get_TypeID_Name() +{ + std::string str = typeid(T).name(); + Erase_Sub_String(str, "class "); + Erase_Sub_String(str, "struct "); + return str; +} +static std::string Get_TypeID_Name(const AbstractClass *abstract) +{ + std::string str = typeid(*abstract).name(); + Erase_Sub_String(str, "class "); + return str; +} + +static std::string Get_TypeID_Name(const AbstractClassExtension *abstract_ext) +{ + std::string str = typeid(*abstract_ext).name(); + Erase_Sub_String(str, "class "); + return str; +} + +}; // namespace "Extension::Utility" + +namespace Singleton +{ /** - * For printing out extension debug info. + * Create an isntance of the singleton class. + * + * @author: CCHyper */ -#ifndef NDEBUG -#define EXT_DEBUG_SAY(x, ...) DEV_DEBUG_SAY(x, ##__VA_ARGS__) -#define EXT_DEBUG_INFO(x, ...) DEV_DEBUG_INFO(x, ##__VA_ARGS__) -#define EXT_DEBUG_WARNING(x, ...) DEV_DEBUG_WARNING(x, ##__VA_ARGS__) -#define EXT_DEBUG_ERROR(x, ...) DEV_DEBUG_ERROR(x, ##__VA_ARGS__) -#define EXT_DEBUG_FATAL(x, ...) DEV_DEBUG_FATAL(x, ##__VA_ARGS__) -#define EXT_DEBUG_TRACE(x, ...) DEV_DEBUG_TRACE(x, ##__VA_ARGS__) -#else -#define EXT_DEBUG_SAY(x, ...) ((void)0) -#define EXT_DEBUG_INFO(x, ...) ((void)0) -#define EXT_DEBUG_WARNING(x, ...) ((void)0) -#define EXT_DEBUG_ERROR(x, ...) ((void)0) -#define EXT_DEBUG_FATAL(x, ...) ((void)0) -#define EXT_DEBUG_TRACE(x, ...) ((void)0) -#endif +template +EXT_CLASS *Make(const BASE_CLASS *base) +{ + ASSERT(base != nullptr); + EXT_CLASS *ext_ptr = new EXT_CLASS(base); + ASSERT(ext_ptr != nullptr); + + EXT_DEBUG_INFO("Created \"%s\" extension.\n", Extension::Utility::Get_TypeID_Name().c_str()); + + return ext_ptr; +} /** - * The base class for the extension class which implements save/load. + * Destroy an instance of the singleton class. + * + * @author: CCHyper */ -class ExtensionBase +template +void Destroy(const EXT_CLASS *ext) { - public: - ExtensionBase() : - IsDirty(false) - { - } + ASSERT(ext != nullptr); + + delete ext; + + EXT_DEBUG_INFO("Destroyed \"%s\" extension.\n", Extension::Utility::Get_TypeID_Name().c_str()); +} + +}; // namespace "Extension::Singleton". - ExtensionBase(const NoInitClass &noinit) - { +namespace List +{ + +/** + * Fetch an extension instance from a list whose extension pointer points to the base class. + * + * @author: CCHyper + */ +template +EXT_CLASS *Fetch(const BASE_CLASS *base, DynamicVectorClass &list) +{ + ASSERT(base != nullptr); + + for (int index = 0; index < list.Count(); ++index) { + EXT_CLASS * ext = list[index]; + if (list[index]->This() == base) { + EXT_DEBUG_INFO("Found \"%s\" extension.\n", Extension::Utility::Get_TypeID_Name().c_str()); + return ext; } + } + + return nullptr; +} + +/** + * Creation an instance of the extension class and add it to the list. + * + * @author: CCHyper + */ +template +EXT_CLASS *Make(const BASE_CLASS *base, DynamicVectorClass &list) +{ + ASSERT(base != nullptr); + + EXT_CLASS *ext_ptr = new EXT_CLASS(base); + ASSERT(ext_ptr != nullptr); + + EXT_DEBUG_INFO("Created \"%s\" extension.\n", Extension::Utility::Get_TypeID_Name().c_str()); + + list.Add(ext_ptr); - virtual ~ExtensionBase() - { + return ext_ptr; +} + +/** + * Destroy an instance of the extension and remove it from the list. + * + * @author: CCHyper + */ +template +void Destroy(const BASE_CLASS *base, DynamicVectorClass &list) +{ + ASSERT(base != nullptr); + + for (int index = 0; index < list.Count(); ++index) { + EXT_CLASS * ext = list[index].This(); + if (ext->This() == base) { + EXT_DEBUG_INFO("Found \"%s\" extension.\n", Extension::Utility::Get_TypeID_Name().c_str()); + delete ext; + return; } + } - /** - * Initializes an object from the stream where it was saved previously. - */ - virtual HRESULT Load(IStream *pStm); + EXT_DEBUG_INFO("Destroyed \"%s\" extension.\n", Extension::Utility::Get_TypeID_Name().c_str()); +} - /** - * Saves an object to the specified stream. - */ - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty); +}; // namespace "Extension::List". - /** - * Return the raw size of class data for save/load purposes. - * - * @note: This must be overridden by the extended class! - */ - virtual int Size_Of() const { return -1; } +/** + * Fetch the extension instance linked to this abstract object. + * + * @author: CCHyper + */ +template +EXT_CLASS *Fetch(const AbstractClass *abstract) +{ + ASSERT(abstract != nullptr); - private: - /** - * Has the object changed since the last save? - */ - bool IsDirty; -}; + return (EXT_CLASS *)Extension::Private::Fetch_Internal(abstract); +} + +/** + * Create an instance of the extension class and link it to the abstract object. + * + * @author: CCHyper + */ +template +EXT_CLASS *Make(const AbstractClass *abstract) +{ + ASSERT(abstract != nullptr); + + return (EXT_CLASS *)Extension::Private::Make_Internal(abstract); +} + +/** + * Destory an instance of the extension class linked to this abstract object. + * + * @author: CCHyper + */ +template +void Destroy(const AbstractClass *abstract) +{ + ASSERT(abstract != nullptr); + + Extension::Private::Destroy_Internal(abstract); +} +/** + * Save and load interface. + */ +bool Save(IStream *pStm); +bool Load(IStream *pStm); +bool Request_Pointer_Remap(); +unsigned Get_Save_Version_Number(); /** - * This is the main base class for all class extensions. + * Tracking, announcement, and debugging functions. + */ +void Detach_This_From_All(TARGET target, bool all = true); +bool Register_Class_Factories(); +void Free_Heaps(); +void Print_CRCs(EventClass *ev); +void Print_CRCs(FILE *fp, EventClass *ev); + +}; // namespace "Extension". + + +/** + * + * Base class for all global extension classes. + * */ template -class Extension : public ExtensionBase +class GlobalExtensionClass { public: - Extension(T *this_ptr) : - ExtensionBase(), - IsInitialized(false), - ThisPtr(this_ptr) - { - } + STDMETHOD(Load)(IStream *pStm); + STDMETHOD(Save)(IStream *pStm, BOOL fClearDirty); - Extension(const NoInitClass &noinit) : - ExtensionBase(noinit) - { - } - - virtual ~Extension() - { - IsInitialized = false; - ThisPtr = nullptr; - } + public: + GlobalExtensionClass(const T *this_ptr = nullptr); + GlobalExtensionClass(const NoInitClass &noinit); + virtual ~GlobalExtensionClass(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; + /** + * Return the raw size of class data for save/load purposes. + * + * @note: This must be overridden by the extended class! + */ + virtual int Size_Of() const = 0; /** * Removes the specified target from any targeting and reference trackers. + * + * @note: This must be overridden by the extended class! */ - virtual void Detach(TARGET target, bool all = true) {} + virtual void Detach(TARGET target, bool all = true) = 0; /** * Compute a unique crc value for this instance. + * + * @note: This must be overridden by the extended class! */ - virtual void Compute_CRC(WWCRCEngine &crc) const {} + virtual void Compute_CRC(WWCRCEngine &crc) const = 0; - protected: /** - * Is this instance extended and valid? + * Access to the class instance we extend. */ - bool IsInitialized; + virtual T *This() const { return const_cast(ThisPtr); } + virtual const T *This_Const() const { return ThisPtr; } + + /** + * Assign the class instance that we extend. + */ + virtual void Assign_This(const T *this_ptr) { ASSERT(this_ptr != nullptr); ThisPtr = this_ptr; } - public: /** - * Pointer to the class we are extending. + * Returns the name of this object type. + * + * @note: This must be overridden by the extended class! */ - T *ThisPtr; + virtual const char *Name() const = 0; + + /** + * Returns the full name of this object type. + * + * @note: This must be overridden by the extended class! + */ + virtual const char *Full_Name() const = 0; + + private: + /** + * Pointer to the class we are extending. This provides us with a way of + * quickly referencing the base class without doing a look-up each time. + */ + const T *ThisPtr; private: - Extension(const Extension &) = delete; - void operator = (const Extension &) = delete; + GlobalExtensionClass(const GlobalExtensionClass &) = delete; + void operator = (const GlobalExtensionClass &) = delete; + + public: }; /** - * Loads the object from the stream and requests a new pointer to - * the class we extended post-load. + * Class constructor * * @author: CCHyper */ template -HRESULT Extension::Load(IStream *pStm) +GlobalExtensionClass::GlobalExtensionClass(const T *this_ptr) : + ThisPtr(this_ptr) { - HRESULT hr = ExtensionBase::Load(pStm); - if (FAILED(hr)) { - return E_FAIL; - } + //if (this_ptr) EXT_DEBUG_TRACE("GlobalExtensionClass<%s>::GlobalExtensionClass - 0x%08X\n", typeid(T).name(), (uintptr_t)(ThisPtr)); + //ASSERT(ThisPtr != nullptr); // NULL ThisPtr is valid when performing a Load state operation. +} - LONG id; - hr = pStm->Read(&id, sizeof(id), nullptr); - if (FAILED(hr)) { - return E_FAIL; - } - ULONG size = Size_Of(); - hr = pStm->Read(this, size, nullptr); - if (FAILED(hr)) { - return E_FAIL; - } +/** + * Class no-init constructor. + * + * @author: CCHyper + */ +template +GlobalExtensionClass::GlobalExtensionClass(const NoInitClass &noinit) +{ + //EXT_DEBUG_TRACE("GlobalExtensionClass<%s>::GlobalExtensionClass(NoInitClass) - 0x%08X\n", typeid(T).name(), (uintptr_t)(ThisPtr)); +} - new (this) Extension(NoInitClass()); - /** - * Announce ourself to the swizzle manager. - */ - SWIZZLE_REGISTER_POINTER(id, this); +/** + * Class destructor + * + * @author: CCHyper + */ +template +GlobalExtensionClass::~GlobalExtensionClass() +{ + //EXT_DEBUG_TRACE("GlobalExtensionClass<%s>::~GlobalExtensionClass - 0x%08X\n", typeid(T).name(), (uintptr_t)(ThisPtr)); + + ThisPtr = nullptr; +} + + +/** + * Loads the object from the stream and requests a new pointer to + * the class we extended post-load. + * + * As singleton is static data, we do not need to request + * pointer remap of "ThisPtr" after loading has finished. + * + * @author: CCHyper, tomsons26 + */ +template +HRESULT GlobalExtensionClass::Load(IStream *pStm) +{ + //EXT_DEBUG_TRACE("GlobalExtensionClass<%s>::Load - 0x%08X\n", typeid(T).name(), (uintptr_t)(ThisPtr)); + + if (!pStm) { + return E_POINTER; + } + + HRESULT hr; /** - * Request the pointer to the base class be remapped. + * Read this classes binary blob data directly into this instance. */ - SWIZZLE_REQUEST_POINTER_REMAP(ThisPtr); - -#ifndef NDEBUG - EXT_DEBUG_INFO("Ext Load: ID 0x%08X Ptr 0x%08X ThisPtr 0x%08X\n", id, this, ThisPtr); -#endif + hr = pStm->Read(this, Size_Of(), nullptr); + if (FAILED(hr)) { + return hr; + } - return S_OK; + return hr; } /** * Saves the object to the stream. * - * @author: CCHyper + * @author: CCHyper, tomsons26 */ template -HRESULT Extension::Save(IStream *pStm, BOOL fClearDirty) +HRESULT GlobalExtensionClass::Save(IStream *pStm, BOOL fClearDirty) { - HRESULT hr = ExtensionBase::Save(pStm, fClearDirty); - if (FAILED(hr)) { - return E_FAIL; - } + //EXT_DEBUG_TRACE("GlobalExtensionClass<%s>::Save - 0x%08X\n", typeid(T).name(), (uintptr_t)(ThisPtr)); - LONG id; - SWIZZLE_FETCH_POINTER_ID(this, &id); - hr = pStm->Write(&id, sizeof(id), nullptr); - if (FAILED(hr)) { - return E_FAIL; + if (!pStm) { + return E_POINTER; } - ULONG size = Size_Of(); - hr = pStm->Write(this, size, nullptr); + HRESULT hr; + + /** + * Write this class instance as a binary blob. + */ + hr = pStm->Write(this, Size_Of(), nullptr); if (FAILED(hr)) { - return E_FAIL; + return hr; } - -#ifndef NDEBUG - EXT_DEBUG_INFO("Ext Save: ID 0x%08X Ptr 0x%08X ThisPtr 0x%08X\n", id, this, ThisPtr); -#endif - return S_OK; + return hr; } diff --git a/src/extensions/extension_globals.cpp b/src/extensions/extension_globals.cpp new file mode 100644 index 00000000..2ddd4b2d --- /dev/null +++ b/src/extensions/extension_globals.cpp @@ -0,0 +1,68 @@ +/******************************************************************************* +/* O P E N S O U R C E -- V I N I F E R A ** +/******************************************************************************* + * + * @project Vinifera + * + * @file EXTENSION_GLOBALS.CPP + * + * @author CCHyper + * + * @brief Extension interface global values. + * + * @license Vinifera is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 3 of the License, or (at your option) any later version. + * + * Vinifera is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. + * If not, see . + * + ******************************************************************************/ +#include "extension_globals.h" + + +DynamicVectorClass UnitExtensions; +DynamicVectorClass AircraftExtensions; +DynamicVectorClass AircraftTypeExtensions; +DynamicVectorClass AnimExtensions; +DynamicVectorClass AnimTypeExtensions; +DynamicVectorClass BuildingExtensions; +DynamicVectorClass BuildingTypeExtensions; +DynamicVectorClass BulletTypeExtensions; +DynamicVectorClass CampaignExtensions; +DynamicVectorClass SideExtensions; +DynamicVectorClass HouseExtensions; +DynamicVectorClass HouseTypeExtensions; +DynamicVectorClass InfantryExtensions; +DynamicVectorClass InfantryTypeExtensions; +DynamicVectorClass IsometricTileTypeExtensions; +DynamicVectorClass OverlayTypeExtensions; +DynamicVectorClass ParticleSystemTypeExtensions; +DynamicVectorClass ParticleTypeExtensions; +DynamicVectorClass SmudgeTypeExtensions; +DynamicVectorClass SuperExtensions; +DynamicVectorClass SuperWeaponTypeExtensions; +DynamicVectorClass TerrainExtensions; +DynamicVectorClass TerrainTypeExtensions; +DynamicVectorClass TiberiumExtensions; +DynamicVectorClass UnitTypeExtensions; +DynamicVectorClass VoxelAnimTypeExtensions; +DynamicVectorClass WarheadTypeExtensions; +DynamicVectorClass WaveExtensions; +DynamicVectorClass WeaponTypeExtensions; + +TacticalExtension *TacticalMapExtension = nullptr; + +RulesClassExtension *RuleExtension = nullptr; +ScenarioClassExtension *ScenExtension = nullptr; +SessionClassExtension *SessionExtension = nullptr; +OptionsClassExtension *OptionsExtension = nullptr; + +DynamicVectorClass ThemeControlExtensions; diff --git a/src/extensions/extension_globals.h b/src/extensions/extension_globals.h new file mode 100644 index 00000000..bb50ca3f --- /dev/null +++ b/src/extensions/extension_globals.h @@ -0,0 +1,148 @@ +/******************************************************************************* +/* O P E N S O U R C E -- V I N I F E R A ** +/******************************************************************************* + * + * @project Vinifera + * + * @file EXTENSION_GLOBALS.H + * + * @author CCHyper + * + * @brief Extension interface global values. + * + * @license Vinifera is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 3 of the License, or (at your option) any later version. + * + * Vinifera is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. + * If not, see . + * + ******************************************************************************/ +#pragma once + +#include "always.h" +#include "vinifera_defines.h" +#include "debughandler.h" +#include "asserthandler.h" + + +class AbstractClass; +class AbstractClassExtension; + +class AircraftClassExtension; +class AircraftTypeClassExtension; +class AnimClassExtension; +class AnimTypeClassExtension; +class BuildingClassExtension; +class BuildingTypeClassExtension; +class BulletTypeClassExtension; +class CampaignClassExtension; +class SideClassExtension; +class HouseClassExtension; +class HouseTypeClassExtension; +class InfantryClassExtension; +class InfantryTypeClassExtension; +class IsometricTileTypeClassExtension; +class OverlayTypeClassExtension; +class ParticleSystemTypeClassExtension; +class ParticleTypeClassExtension; +class SmudgeTypeClassExtension; +class SuperClassExtension; +class SuperWeaponTypeClassExtension; +class TerrainClassExtension; +class TerrainTypeClassExtension; +class TiberiumClassExtension; +class UnitClassExtension; +class UnitTypeClassExtension; +class VoxelAnimTypeClassExtension; +class WarheadTypeClassExtension; +class WaveClassExtension; +class WeaponTypeClassExtension; + +class TacticalExtension; + +class RulesClassExtension; +class ScenarioClassExtension; +class SessionClassExtension; +class OptionsClassExtension; + +class ThemeControlExtension; + + +/** + * For printing out extension debug info. + */ +#ifdef VINIFERA_ENABLE_EXTENSION_DEBUG_PRINTING +#define EXT_DEBUG_SAY(x, ...) DEV_DEBUG_SAY(x, ##__VA_ARGS__) +#define EXT_DEBUG_INFO(x, ...) DEV_DEBUG_INFO(x, ##__VA_ARGS__) +#define EXT_DEBUG_WARNING(x, ...) DEV_DEBUG_WARNING(x, ##__VA_ARGS__) +#define EXT_DEBUG_ERROR(x, ...) DEV_DEBUG_ERROR(x, ##__VA_ARGS__) +#define EXT_DEBUG_FATAL(x, ...) DEV_DEBUG_FATAL(x, ##__VA_ARGS__) +#define EXT_DEBUG_TRACE(x, ...) DEV_DEBUG_TRACE(x, ##__VA_ARGS__) +#else +#define EXT_DEBUG_SAY(x, ...) ((void)0) +#define EXT_DEBUG_INFO(x, ...) ((void)0) +#define EXT_DEBUG_WARNING(x, ...) ((void)0) +#define EXT_DEBUG_ERROR(x, ...) ((void)0) +#define EXT_DEBUG_FATAL(x, ...) ((void)0) +#define EXT_DEBUG_TRACE(x, ...) ((void)0) +#endif + + +/** + * Abstract derived classes. + */ +extern DynamicVectorClass UnitExtensions; +extern DynamicVectorClass AircraftExtensions; +extern DynamicVectorClass AircraftTypeExtensions; +extern DynamicVectorClass AnimExtensions; +extern DynamicVectorClass AnimTypeExtensions; +extern DynamicVectorClass BuildingExtensions; +extern DynamicVectorClass BuildingTypeExtensions; +extern DynamicVectorClass BulletTypeExtensions; +extern DynamicVectorClass CampaignExtensions; +extern DynamicVectorClass SideExtensions; +extern DynamicVectorClass HouseExtensions; +extern DynamicVectorClass HouseTypeExtensions; +extern DynamicVectorClass InfantryExtensions; +extern DynamicVectorClass InfantryTypeExtensions; +extern DynamicVectorClass IsometricTileTypeExtensions; +extern DynamicVectorClass OverlayTypeExtensions; +extern DynamicVectorClass ParticleSystemTypeExtensions; +extern DynamicVectorClass ParticleTypeExtensions; +extern DynamicVectorClass SmudgeTypeExtensions; +extern DynamicVectorClass SuperExtensions; +extern DynamicVectorClass SuperWeaponTypeExtensions; +extern DynamicVectorClass TerrainExtensions; +extern DynamicVectorClass TerrainTypeExtensions; +extern DynamicVectorClass TiberiumExtensions; +extern DynamicVectorClass UnitTypeExtensions; +extern DynamicVectorClass VoxelAnimTypeExtensions; +extern DynamicVectorClass WarheadTypeExtensions; +extern DynamicVectorClass WaveExtensions; +extern DynamicVectorClass WeaponTypeExtensions; + +/** + * Abstract derived classes, but only a single instance is required. + */ +extern TacticalExtension *TacticalMapExtension; + +/** + * Global classes that are not abstract derived. + */ +extern RulesClassExtension *RuleExtension; +extern ScenarioClassExtension *ScenExtension; +extern SessionClassExtension *SessionExtension; +extern OptionsClassExtension *OptionsExtension; + +/** + * Classes that require a list, but are not abstract derived. + */ +extern DynamicVectorClass ThemeControlExtensions; diff --git a/src/extensions/extension_hooks.cpp b/src/extensions/extension_hooks.cpp index c38b3534..0136a664 100644 --- a/src/extensions/extension_hooks.cpp +++ b/src/extensions/extension_hooks.cpp @@ -4,7 +4,7 @@ * * @project Vinifera * - * @file EXT_HOOKS.CPP + * @file EXTENSION_HOOKS.CPP * * @author CCHyper * @@ -27,180 +27,218 @@ ******************************************************************************/ #include "extension_hooks.h" -#include "iomap.h" - -/** - * Extended classes here. - */ -#include "initext_hooks.h" -#include "mainloopext_hooks.h" -#include "newmenuext_hooks.h" - -#include "rulesext_hooks.h" -#include "tacticalext_hooks.h" -#include "scenarioext_hooks.h" -#include "displayext_hooks.h" -#include "sidebarext_hooks.h" -#include "tooltipext_hooks.h" -#include "commandext_hooks.h" -#include "optionsext_hooks.h" -#include "msglistext_hooks.h" -#include "sessionext_hooks.h" -#include "cdext_hooks.h" - -#include "playmovie_hooks.h" -#include "vqaext_hooks.h" -#include "themeext_hooks.h" +#include "abstractext_hooks.h" +#include "technoext_hooks.h" +#include "footext_hooks.h" #include "objecttypeext_hooks.h" #include "technotypeext_hooks.h" -#include "buildingtypeext_hooks.h" -#include "unittypeext_hooks.h" -#include "infantrytypeext_hooks.h" + +#include "unitext_hooks.h" +#include "aircraftext_hooks.h" #include "aircrafttypeext_hooks.h" -#include "warheadtypeext_hooks.h" -#include "weapontypeext_hooks.h" -#include "bullettypeext_hooks.h" -#include "supertypeext_hooks.h" -#include "voxelanimtypeext_hooks.h" +#include "animext_hooks.h" #include "animtypeext_hooks.h" -#include "particletypeext_hooks.h" -#include "particlesystypeext_hooks.h" +#include "buildingext_hooks.h" +#include "buildingtypeext_hooks.h" +#include "bulletext_hooks.h" +#include "bullettypeext_hooks.h" +#include "campaignext_hooks.h" +#include "cellext_hooks.h" +#include "factoryext_hooks.h" +#include "houseext_hooks.h" +#include "housetypeext_hooks.h" +#include "infantryext_hooks.h" +#include "infantrytypeext_hooks.h" +//#include "isotileext_hooks.h" #include "isotiletypeext_hooks.h" +//#include "buildinglightext_hooks.h" +//#include "overlayext_hooks.h" #include "overlaytypeext_hooks.h" -#include "smudgetypeext_hooks.h" -#include "terraintypeext_hooks.h" -#include "housetypeext_hooks.h" +//#include "particleext_hooks.h" +#include "particletypeext_hooks.h" +#include "particlesysext_hooks.h" +#include "particlesystypeext_hooks.h" +//#include "scriptext_hooks.h" +//#include "scripttypeext_hooks.h" #include "sideext_hooks.h" -#include "campaignext_hooks.h" -#include "tiberiumext_hooks.h" +//#include "smudgeext_hooks.h" +#include "smudgetypeext_hooks.h" +#include "supertypeext_hooks.h" //#include "taskforceext_hooks.h" -//#include "aitrigtypeext_hooks.h" -//#include "scripttypeext_hooks.h" -//#include "tagtypeext_hooks.h" -//#include "triggertypeext_hooks.h" - -#include "technoext_hooks.h" -#include "footext_hooks.h" - -#include "unitext_hooks.h" -#include "buildingext_hooks.h" -#include "aircraftext_hooks.h" -#include "infantryext_hooks.h" -#include "cellext_hooks.h" -#include "houseext_hooks.h" #include "teamext_hooks.h" -#include "tactionext_hooks.h" -#include "factoryext_hooks.h" -#include "animext_hooks.h" -#include "bulletext_hooks.h" +//#include "teamtypeext_hooks.h" #include "terrainext_hooks.h" +#include "terraintypeext_hooks.h" +//#include "triggerext_hooks.h" +//#include "triggertypeext_hooks.h" +#include "unittypeext_hooks.h" +//#include "voxelanimext_hooks.h" +#include "voxelanimtypeext_hooks.h" +#include "waveext_hooks.h" +//#include "tagext_hooks.h" +//#include "tagtypeext_hooks.h" +#include "tiberiumext_hooks.h" +#include "tactionext_hooks.h" +//#include "teventext_hooks.h" +#include "weapontypeext_hooks.h" +#include "warheadtypeext_hooks.h" +//#include "waypointeext_hooks.h" +//#include "tubeext_hooks.h" +//#include "lightsourceext_hooks.h" +#include "empulseext_hooks.h" +#include "tacticalext_hooks.h" #include "superext_hooks.h" -#include "particlesysext_hooks.h" +//#include "aitriggerext_hooks.h" +//#include "aitriggertypeext_hooks.h" +//#include "neuronext_hooks.h" +//#include "foggedobjectext_hooks.h" +//#include "alphashapeext_hooks.h" +//#include "veinholemonsterext_hooks.h" -#include "combatext_hooks.h" +#include "rulesext_hooks.h" +#include "scenarioext_hooks.h" +#include "sessionext_hooks.h" +#include "optionsext_hooks.h" -#include "empulseext_hooks.h" -#include "waveext_hooks.h" +#include "themeext_hooks.h" + +#include "displayext_hooks.h" +#include "sidebarext_hooks.h" + +#include "initext_hooks.h" +#include "mainloopext_hooks.h" +#include "newmenuext_hooks.h" +#include "commandext_hooks.h" +#include "cdext_hooks.h" +#include "playmovie_hooks.h" +#include "vqaext_hooks.h" +#include "cciniext_hooks.h" +#include "rawfileext_hooks.h" +#include "ccfileext_hooks.h" +#include "msglistext_hooks.h" #include "txtlabelext_hooks.h" +#include "tooltipext_hooks.h" +#include "combatext_hooks.h" #include "dropshipext_hooks.h" #include "endgameext_hooks.h" - #include "mapseedext_hooks.h" #include "multiscoreext_hooks.h" #include "multimissionext_hooks.h" -#include "cciniext_hooks.h" -#include "rawfileext_hooks.h" -#include "ccfileext_hooks.h" - -#include "theatertype_hooks.h" +#include "skirmishdlg_hooks.h" +#include "filepcx_hooks.h" #include "fetchres_hooks.h" -#include "skirmishdlg_hooks.h" +#include "theatertype_hooks.h" -#include "filepcx_hooks.h" +#include "vinifera_globals.h" +#include "tibsun_functions.h" +#include "iomap.h" + +#include "extension.h" +#include "swizzle.h" #include "hooker.h" #include "hooker_macros.h" -extern bool Vinifera_ClassExtensionsDisabled; - - void Extension_Hooks() { - if (!Vinifera_ClassExtensionsDisabled) { - /** - * All game class extensions here. - */ - ObjectTypeClassExtension_Hooks(); - TechnoTypeClassExtension_Hooks(); - BuildingTypeClassExtension_Hooks(); - UnitTypeClassExtension_Hooks(); - InfantryTypeClassExtension_Hooks(); - AircraftTypeClassExtension_Hooks(); - WarheadTypeClassExtension_Hooks(); - WeaponTypeClassExtension_Hooks(); - BulletTypeClassExtension_Hooks(); - SuperWeaponTypeClassExtension_Hooks(); - VoxelAnimTypeClassExtension_Hooks(); - AnimTypeClassExtension_Hooks(); - ParticleTypeClassExtension_Hooks(); - ParticleSystemTypeClassExtension_Hooks(); - IsometricTileTypeClassExtension_Hooks(); - OverlayTypeClassExtension_Hooks(); - SmudgeTypeClassExtension_Hooks(); - TerrainTypeClassExtension_Hooks(); - HouseTypeClassExtension_Hooks(); - SideClassExtension_Hooks(); - CampaignClassExtension_Hooks(); - TiberiumClassExtension_Hooks(); - //TaskForceClassExtension_Hooks(); - //AITriggerTypeClassExtension_Hooks(); - //ScriptTypeClassExtension_Hooks(); - //TagTypeClassExtension_Hooks(); - //TriggerTypeClassExtension_Hooks(); - TechnoClassExtension_Hooks(); - UnitClassExtension_Hooks(); - AircraftClassExtension_Hooks(); - InfantryClassExtension_Hooks(); - BuildingClassExtension_Hooks(); - CellClassExtension_Hooks(); - HouseClassExtension_Hooks(); - TeamClassExtension_Hooks(); - TActionClassExtension_Hooks(); - FactoryClassExtension_Hooks(); - TechnoClassExtension_Hooks(); - FootClassExtension_Hooks(); - AnimClassExtension_Hooks(); - BulletClassExtension_Hooks(); - TerrainClassExtension_Hooks(); - SuperClassExtension_Hooks(); - ParticleSystemClassExtension_Hooks(); - EMPulseClassExtension_Hooks(); - WaveClassExtension_Hooks(); - - /** - * All global class extensions here. - */ - RulesClassExtension_Hooks(); - TacticalExtension_Hooks(); - ScenarioClassExtension_Hooks(); - DisplayClassExtension_Hooks(); - SidebarClassExtension_Hooks(); - OptionsClassExtension_Hooks(); - SessionClassExtension_Hooks(); - ThemeClassExtension_Hooks(); - } + /** + * Abstract and stack class extensions here. + */ + AbstractClassExtension_Hooks(); /** - * New classes and interfaces. + * All game type class extensions here. */ - TheaterTypeClassExtension_Hooks(); + ObjectTypeClassExtension_Hooks(); + TechnoTypeClassExtension_Hooks(); + + /** + * All game class extensions here. + */ + TechnoClassExtension_Hooks(); + FootClassExtension_Hooks(); + + UnitClassExtension_Hooks(); + AircraftClassExtension_Hooks(); + AircraftTypeClassExtension_Hooks(); + AnimClassExtension_Hooks(); + AnimTypeClassExtension_Hooks(); + BuildingClassExtension_Hooks(); + BuildingTypeClassExtension_Hooks(); + BulletClassExtension_Hooks(); + BulletTypeClassExtension_Hooks(); + CampaignClassExtension_Hooks(); + CellClassExtension_Hooks(); + FactoryClassExtension_Hooks(); + HouseClassExtension_Hooks(); + HouseTypeClassExtension_Hooks(); + InfantryClassExtension_Hooks(); + InfantryTypeClassExtension_Hooks(); + //IsometricTileClassExtension_Hooks(); // Not yet implemented + IsometricTileTypeClassExtension_Hooks(); + //BuildingLightExtension_Hooks(); // Not yet implemented + //OverlayClassExtension_Hooks(); // Not yet implemented + OverlayTypeClassExtension_Hooks(); + //ParticleClassExtension_Hooks(); // Not yet implemented + ParticleTypeClassExtension_Hooks(); + ParticleSystemClassExtension_Hooks(); + ParticleSystemTypeClassExtension_Hooks(); + //ScriptClassExtension_Hooks(); // Not yet implemented + //ScriptTypeClassExtension_Hooks(); // Not yet implemented + SideClassExtension_Hooks(); + //SmudgeClassExtension_Hooks(); // Not yet implemented + SmudgeTypeClassExtension_Hooks(); + SuperWeaponTypeClassExtension_Hooks(); + //TaskForceClassExtension_Hooks(); // Not yet implemented + TeamClassExtension_Hooks(); + //TeamTypeClassExtension_Hooks(); // Not yet implemented + TerrainClassExtension_Hooks(); + TerrainTypeClassExtension_Hooks(); + //TriggerTypeExtension_Hooks(); // Not yet implemented + //TriggerTypeClassExtension_Hooks(); // Not yet implemented + UnitTypeClassExtension_Hooks(); + //VoxelAnimClassExtension_Hooks(); // Not yet implemented + VoxelAnimTypeClassExtension_Hooks(); + WaveClassExtension_Hooks(); + //TagClassExtension_Hooks(); // Not yet implemented + //TagTypeClassExtension_Hooks(); // Not yet implemented + TiberiumClassExtension_Hooks(); + //TActionClassExtension_Hooks(); // Not yet implemented + //TEventClassExtension_Hooks(); // Not yet implemented + WeaponTypeClassExtension_Hooks(); + WarheadTypeClassExtension_Hooks(); + //WaypointClassExtension_Hooks(); // Not yet implemented + //TubeClassExtension_Hooks(); // Not yet implemented + //LightSourceClassExtension_Hooks(); // Not yet implemented + EMPulseClassExtension_Hooks(); + TacticalExtension_Hooks(); + SuperClassExtension_Hooks(); + //AITriggerClassExtension_Hooks(); // Not yet implemented + //AITriggerTypeClassExtension_Hooks(); // Not yet implemented + //NeuronClassExtension_Hooks(); // Not yet implemented + //FoggedObjectClassExtension_Hooks(); // Not yet implemented + //AlphaShapeClassExtension_Hooks(); // Not yet implemented + //VeinholeMonsterClassExtension_Hooks(); // Not yet implemented + + /** + * All global class extensions here. + */ + RulesClassExtension_Hooks(); + ScenarioClassExtension_Hooks(); + SessionClassExtension_Hooks(); + OptionsClassExtension_Hooks(); + + ThemeClassExtension_Hooks(); + + DisplayClassExtension_Hooks(); + SidebarClassExtension_Hooks(); /** * Various modules and functions. @@ -237,4 +275,9 @@ void Extension_Hooks() */ FilePCXExtension_Hooks(); FetchRes_Hooks(); + + /** + * New classes and interfaces. + */ + TheaterTypeClassExtension_Hooks(); } diff --git a/src/extensions/extension_hooks.h b/src/extensions/extension_hooks.h index c0079e74..c26dea6e 100644 --- a/src/extensions/extension_hooks.h +++ b/src/extensions/extension_hooks.h @@ -4,7 +4,7 @@ * * @project Vinifera * - * @file EXT_HOOKS.H + * @file EXTENSION_HOOKS.H * * @author CCHyper * diff --git a/src/extensions/extension_saveload.cpp b/src/extensions/extension_saveload.cpp deleted file mode 100644 index 79806135..00000000 --- a/src/extensions/extension_saveload.cpp +++ /dev/null @@ -1,486 +0,0 @@ -/******************************************************************************* -/* O P E N S O U R C E -- V I N I F E R A ** -/******************************************************************************* - * - * @project Vinifera - * - * @file EXT_SAVELOAD.CPP - * - * @author CCHyper - * - * @brief Handles the saving and loading of extended class data. - * - * @license Vinifera is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version - * 3 of the License, or (at your option) any later version. - * - * Vinifera is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. - * If not, see . - * - ******************************************************************************/ -#include "saveload.h" -#include "wwcrc.h" -#include "vinifera_gitinfo.h" -#include "vinifera_util.h" -#include "tibsun_globals.h" -#include "debughandler.h" -#include "asserthandler.h" -#include "fatal.h" -#include // for IStream - -#include "rulesext.h" -#include "sessionext.h" -#include "scenarioext.h" -#include "tacticalext.h" - -#include "objecttypeext.h" -#include "technotypeext.h" -#include "buildingtypeext.h" -#include "unittypeext.h" -#include "infantrytypeext.h" -#include "aircrafttypeext.h" -#include "warheadtypeext.h" -#include "weapontypeext.h" -#include "bullettypeext.h" -#include "supertypeext.h" -#include "voxelanimtypeext.h" -#include "animtypeext.h" -#include "particletypeext.h" -#include "particlesystypeext.h" -#include "isotiletypeext.h" -#include "overlaytypeext.h" -#include "smudgetypeext.h" -#include "terraintypeext.h" -#include "housetypeext.h" -#include "sideext.h" -#include "campaignext.h" -#include "tiberiumext.h" -//#include "taskforceext.h" -//#include "aitrigtypeext.h" -//#include "scripttypeext.h" -//#include "tagtypeext.h" -//#include "triggertypeext.h" - -#include "technoext.h" -#include "aircraftext.h" -#include "buildingext.h" -#include "infantryext.h" -#include "unitext.h" -#include "terrainext.h" -#include "superext.h" - -#include "waveext.h" - -#include "extension.h" - - -/** - * Constant of the current build version number. This number should be - * a sum of all the extended class sizes plus the build date. - */ -unsigned ViniferaSaveGameVersion = - - 10000 - - /** - * Global classes. - */ - + sizeof(RulesClassExtension) - + sizeof(SessionClassExtension) - + sizeof(ScenarioClassExtension) - + sizeof(TacticalExtension) - - /** - * Extended type classes. - */ - + sizeof(BuildingTypeClassExtension) - + sizeof(UnitTypeClassExtension) - + sizeof(InfantryTypeClassExtension) - + sizeof(AircraftTypeClassExtension) - + sizeof(WarheadTypeClassExtension) - + sizeof(WeaponTypeClassExtension) - + sizeof(BulletTypeClassExtension) - + sizeof(SuperWeaponTypeClassExtension) - + sizeof(VoxelAnimTypeClassExtension) - + sizeof(AnimTypeClassExtension) - + sizeof(ParticleTypeClassExtension) - + sizeof(ParticleSystemTypeClassExtension) - + sizeof(IsometricTileTypeClassExtension) - + sizeof(OverlayTypeClassExtension) - + sizeof(SmudgeTypeClassExtension) - + sizeof(TerrainTypeClassExtension) - + sizeof(HouseTypeClassExtension) - + sizeof(SideClassExtension) - + sizeof(CampaignClassExtension) - + sizeof(TiberiumClassExtension) - + sizeof(TechnoClassExtension) - + sizeof(AircraftClassExtension) - + sizeof(BuildingClassExtension) - + sizeof(InfantryClassExtension) - + sizeof(UnitClassExtension) - + sizeof(TerrainClassExtension) - + sizeof(WaveClassExtension) - + sizeof(SuperClassExtension) -; - - -/** - * Save file header. - */ -typedef struct ViniferaSaveFileHeaderStruct -{ - // Header marker. - char Marker[20]; - - // Git commit hash. - char CommitHash[40]; - - // Constant header marker to check for. - static const char * Marker_String() { return "VINIFERA_SAVE_FILE"; } - -private: - char _padding[1024 - - sizeof(Marker) - - sizeof(CommitHash)]; -}; -static_assert(sizeof(ViniferaSaveFileHeaderStruct), "ViniferaSaveFileHeaderStruct must be 1024 bytes in size!"); - -static ViniferaSaveFileHeaderStruct ViniferaSaveFileHeader; - - -/** - * Saves the header marker for validating data on load. - * - * @author: CCHyper - */ -static bool Vinifera_Save_Header(IStream *pStm) -{ - if (!pStm) { - return false; - } - - HRESULT hr; - - /** - * Save the new header. - */ - std::memset(&ViniferaSaveFileHeader, 0, sizeof(ViniferaSaveFileHeader)); - - strncpy(ViniferaSaveFileHeader.Marker, ViniferaSaveFileHeaderStruct::Marker_String(), sizeof(ViniferaSaveFileHeader.Marker)); - strncpy(ViniferaSaveFileHeader.CommitHash, Vinifera_Git_Hash(), sizeof(ViniferaSaveFileHeader.CommitHash)); - - hr = pStm->Write(&ViniferaSaveFileHeader, sizeof(ViniferaSaveFileHeader), nullptr); - if (FAILED(hr)) { - return false; - } - - return true; -} - - -/** - * Loads the save data header marker. - * - * @author: CCHyper - */ -static bool Vinifera_Load_Header(IStream *pStm) -{ - if (!pStm) { - return false; - } - - HRESULT hr; - - /** - * Load the new header. - */ - std::memset(&ViniferaSaveFileHeader, 0, sizeof(ViniferaSaveFileHeader)); - - hr = pStm->Read(&ViniferaSaveFileHeader, sizeof(ViniferaSaveFileHeader), nullptr); - if (FAILED(hr)) { - return false; - } - - return true; -} - - -static bool Vinifera_Save_RulesExtension(IStream *pStm) -{ - if (!pStm) { - return false; - } - - if (!RulesExtension) { - return false; - } - - RulesExtension->Save(pStm, true); - - return true; -} - - -static bool Vinifera_Load_RulesExtension(IStream *pStm) -{ - if (!pStm) { - return false; - } - - if (!RulesExtension) { - return false; - } - - RulesExtension->Load(pStm); - - return true; -} - - -static bool Vinifera_Save_SessionExtension(IStream *pStm) -{ - if (!pStm) { - return false; - } - - if (!SessionExtension) { - return false; - } - - SessionExtension->Save(pStm, true); - - return true; -} - - -static bool Vinifera_Load_SessionExtension(IStream *pStm) -{ - if (!pStm) { - return false; - } - - if (!SessionExtension) { - return false; - } - - SessionExtension->Load(pStm); - - return true; -} - - -static bool Vinifera_Save_ScenarioExtension(IStream *pStm) -{ - if (!pStm) { - return false; - } - - if (!ScenarioExtension) { - return false; - } - - ScenarioExtension->Save(pStm, true); - - return true; -} - - -static bool Vinifera_Load_ScenarioExtension(IStream *pStm) -{ - if (!pStm) { - return false; - } - - if (!ScenarioExtension) { - return false; - } - - ScenarioExtension->Load(pStm); - - return true; -} - - -static bool Vinifera_Save_TacticalExtension(IStream *pStm) -{ - if (!pStm) { - return false; - } - - if (!TacticalExtension) { - return false; - } - - TacticalExtension->Save(pStm, true); - - return true; -} - - -static bool Vinifera_Load_TacticalExtension(IStream *pStm) -{ - if (!pStm) { - return false; - } - - if (!TacticalExtension) { - return false; - } - - TacticalExtension->Load(pStm); - - return true; -} - - -/** - * Save all Vinifera data to the file stream. - * - * @author: CCHyper - */ -bool Vinifera_Put_All(IStream *pStm) -{ -#if 0 - /** - * Save the Vinifera data marker which can be used to verify - * the state of the data to follow on load. - */ - DEBUG_INFO("Saving Vinifera header\n"); - if (!Vinifera_Save_Header(pStm)) { - DEBUG_ERROR("\t***** FAILED!\n"); - return false; - } - - /** - * Save class extensions here. - */ - DEBUG_INFO("Saving extended class data...\n"); - - DEBUG_INFO("Saving RulesExtension\n"); - if (!Vinifera_Save_RulesExtension(pStm)) { - DEBUG_ERROR("\t***** FAILED!\n"); - return false; - } - - DEBUG_INFO("Saving SessionExtension\n"); - if (!Vinifera_Save_SessionExtension(pStm)) { - DEBUG_ERROR("\t***** FAILED!\n"); - return false; - } - - DEBUG_INFO("Saving ScenarioExtension\n"); - if (!Vinifera_Save_ScenarioExtension(pStm)) { - DEBUG_ERROR("\t***** FAILED!\n"); - return false; - } - - DEBUG_INFO("Saving TacticalExtension\n"); - if (!Vinifera_Save_TacticalExtension(pStm)) { - DEBUG_ERROR("\t***** FAILED!\n"); - return false; - } - - DEBUG_INFO("Saving class extensions\n"); - if (!Save_Extensions(pStm)) { - DEBUG_ERROR("\t***** FAILED!\n"); - return false; - } - - /** - * Save global data and values here. - */ - DEBUG_INFO("Saving global data...\n"); -#endif - return true; -} - - -/** - * Load all Vinifera data from the file stream. - * - * @author: CCHyper - */ -bool Vinifera_Load_All(IStream *pStm) -{ -#if 0 - /** - * Load the Vinifera data marker which can be used to verify - * the state of the data to follow. - */ - DEBUG_INFO("Loading Vinifera header\n"); - if (!Vinifera_Load_Header(pStm)) { - DEBUG_ERROR("\t***** FAILED!\n"); - - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to load Vinifera save-file header!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to load Vinifera save-file header!\n"); - - return false; - } - - if (std::strncmp(ViniferaSaveFileHeader.Marker, ViniferaSaveFileHeaderStruct::Marker_String(), sizeof(ViniferaSaveFileHeader.Marker)) != 0) { - DEBUG_WARNING("Invalid header in save file!"); - - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Invalid header in save file!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Invalid header in save file!\n"); - - return false; - } - - if (std::strncmp(ViniferaSaveFileHeader.CommitHash, Vinifera_Git_Hash(), sizeof(ViniferaSaveFileHeader.CommitHash)) != 0) { - DEBUG_WARNING("Git hash mismatch in save file!"); - //return false; - } - - /** - * Load class extensions here. - */ - DEBUG_INFO("Loading extended class data...\n"); - - DEBUG_INFO("Loading RulesExtension\n"); - if (!Vinifera_Load_RulesExtension(pStm)) { - DEBUG_ERROR("\t***** FAILED!\n"); - return false; - } - - DEBUG_INFO("Loading SessionExtension\n"); - if (!Vinifera_Load_SessionExtension(pStm)) { - DEBUG_ERROR("\t***** FAILED!\n"); - return false; - } - - DEBUG_INFO("Loading ScenarioExtension\n"); - if (!Vinifera_Load_ScenarioExtension(pStm)) { - DEBUG_ERROR("\t***** FAILED!\n"); - return false; - } - - DEBUG_INFO("Loading TacticalExtension\n"); - if (!Vinifera_Load_TacticalExtension(pStm)) { - DEBUG_ERROR("\t***** FAILED!\n"); - return false; - } - - DEBUG_INFO("Loading class extensions\n"); - if (!Load_Extensions(pStm)) { - DEBUG_ERROR("\t***** FAILED!\n"); - return false; - } - - /** - * Load global data and values here. - */ - DEBUG_INFO("Loading global data...\n"); -#endif - return true; -} diff --git a/src/extensions/foot/footext.cpp b/src/extensions/foot/footext.cpp new file mode 100644 index 00000000..41e35f30 --- /dev/null +++ b/src/extensions/foot/footext.cpp @@ -0,0 +1,127 @@ +/******************************************************************************* +/* O P E N S O U R C E -- V I N I F E R A ** +/******************************************************************************* + * + * @project Vinifera + * + * @file FOOTEXT.H + * + * @author CCHyper + * + * @brief Extended FootClass class. + * + * @license Vinifera is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 3 of the License, or (at your option) any later version. + * + * Vinifera is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. + * If not, see . + * + ******************************************************************************/ +#pragma once + +#include "footext.h" + + +/** + * Class constructor. + * + * @author: CCHyper + */ +FootClassExtension::FootClassExtension(const FootClass *this_ptr) : + TechnoClassExtension(this_ptr) +{ + //if (this_ptr) EXT_DEBUG_TRACE("FootClassExtension::FootClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); +} + + +/** + * Class no-init constructor. + * + * @author: CCHyper + */ +FootClassExtension::FootClassExtension(const NoInitClass &noinit) : + TechnoClassExtension(noinit) +{ + //EXT_DEBUG_TRACE("FootClassExtension::FootClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); +} + + +/** + * Class destructor. + * + * @author: CCHyper + */ +FootClassExtension::~FootClassExtension() +{ + //EXT_DEBUG_TRACE("FootClassExtension::~FootClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); +} + + +/** + * Initializes an object from the stream where it was saved previously. + * + * @author: CCHyper + */ +HRESULT FootClassExtension::Load(IStream *pStm) +{ + //EXT_DEBUG_TRACE("FootClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + HRESULT hr = TechnoClassExtension::Load(pStm); + if (FAILED(hr)) { + return E_FAIL; + } + + return hr; +} + + +/** + * Saves an object to the specified stream. + * + * @author: CCHyper + */ +HRESULT FootClassExtension::Save(IStream *pStm, BOOL fClearDirty) +{ + //EXT_DEBUG_TRACE("FootClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + HRESULT hr = TechnoClassExtension::Save(pStm, fClearDirty); + if (FAILED(hr)) { + return hr; + } + + return hr; +} + + +/** + * Removes the specified target from any targeting and reference trackers. + * + * @author: CCHyper + */ +void FootClassExtension::Detach(TARGET target, bool all) +{ + //EXT_DEBUG_TRACE("FootClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + TechnoClassExtension::Detach(target, all); +} + + +/** + * Compute a unique crc value for this instance. + * + * @author: CCHyper + */ +void FootClassExtension::Compute_CRC(WWCRCEngine &crc) const +{ + //EXT_DEBUG_TRACE("FootClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + TechnoClassExtension::Compute_CRC(crc); +} diff --git a/src/extensions/technotype/technotypeext_init.h b/src/extensions/foot/footext.h similarity index 65% rename from src/extensions/technotype/technotypeext_init.h rename to src/extensions/foot/footext.h index d7c4b074..97d898b5 100644 --- a/src/extensions/technotype/technotypeext_init.h +++ b/src/extensions/foot/footext.h @@ -4,11 +4,11 @@ * * @project Vinifera * - * @file TECHNOTYPEEXT_INIT.H + * @file FOOTEXT.H * * @author CCHyper * - * @brief Contains the hooks for initialising the extended TechnoTypeClass. + * @brief Extended FootClass class. * * @license Vinifera is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,5 +27,26 @@ ******************************************************************************/ #pragma once +#include "technoext.h" +#include "foot.h" -void TechnoTypeClassExtension_Init(); + +class FootClassExtension : public TechnoClassExtension +{ + public: + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + FootClassExtension(const FootClass *this_ptr); + FootClassExtension(const NoInitClass &noinit); + virtual ~FootClassExtension(); + + virtual void Detach(TARGET target, bool all = true) override; + virtual void Compute_CRC(WWCRCEngine &crc) const override; + + public: +}; diff --git a/src/extensions/foot/footext_hooks.cpp b/src/extensions/foot/footext_hooks.cpp index 97d7c868..7f477198 100644 --- a/src/extensions/foot/footext_hooks.cpp +++ b/src/extensions/foot/footext_hooks.cpp @@ -30,6 +30,7 @@ #include "technoext.h" #include "technotype.h" #include "technotypeext.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" @@ -51,12 +52,12 @@ DECLARE_PATCH(_FootClass_Mission_Move_Can_Passive_Acquire_Patch) GET_REGISTER_STATIC(FootClass *, this_ptr, esi); static TechnoClassExtension *technoclassext; - technoclassext = TechnoClassExtensions.find(this_ptr); + technoclassext = Extension::Fetch(this_ptr); /** * Can this unit passively acquire new targets? */ - if (technoclassext && !technoclassext->Can_Passive_Acquire()) { + if (!technoclassext->Can_Passive_Acquire()) { goto finish_mission_process; } @@ -82,12 +83,12 @@ DECLARE_PATCH(_FootClass_Mission_Guard_Can_Passive_Acquire_Patch) GET_REGISTER_STATIC(FootClass *, this_ptr, esi); static TechnoClassExtension *technoclassext; - technoclassext = TechnoClassExtensions.find(this_ptr); + technoclassext = Extension::Fetch(this_ptr); /** * Can this unit passively acquire new targets? */ - if (technoclassext && !technoclassext->Can_Passive_Acquire()) { + if (!technoclassext->Can_Passive_Acquire()) { goto continue_check; } @@ -119,12 +120,12 @@ DECLARE_PATCH(_FootClass_Mission_Guard_Area_Can_Passive_Acquire_Patch) GET_REGISTER_STATIC(FootClass *, this_ptr, esi); static TechnoClassExtension *technoclassext; - technoclassext = TechnoClassExtensions.find(this_ptr); + technoclassext = Extension::Fetch(this_ptr); /** * Can this unit passively acquire new targets? */ - if (technoclassext && !technoclassext->Can_Passive_Acquire()) { + if (!technoclassext->Can_Passive_Acquire()) { goto tarcom_check; } @@ -152,7 +153,7 @@ DECLARE_PATCH(_FootClass_AI_IdleRate_Patch) GET_REGISTER_STATIC(ILocomotion *, loco, edi); static TechnoTypeClassExtension *technotypeext; - technotypeext = TechnoTypeClassExtensions.find(this_ptr->Techno_Type_Class()); + technotypeext = Extension::Fetch(this_ptr->Techno_Type_Class()); /** * Stolen bytes/code. @@ -165,11 +166,9 @@ DECLARE_PATCH(_FootClass_AI_IdleRate_Patch) /** * Otherwise, if the object is not currently moving, check to see if its time to update its idle frame. */ - } else if (technotypeext) { - if (technotypeext->IdleRate > 0) { - if (!Locomotion_Is_Moving_Now(this_ptr) && !(Frame % technotypeext->IdleRate)) { - ++this_ptr->TotalFramesWalked; - } + } else if (technotypeext->IdleRate > 0) { + if (!Locomotion_Is_Moving_Now(this_ptr) && !(Frame % technotypeext->IdleRate)) { + ++this_ptr->TotalFramesWalked; } } diff --git a/src/extensions/house/houseext.cpp b/src/extensions/house/houseext.cpp index 030aca64..a927baf7 100644 --- a/src/extensions/house/houseext.cpp +++ b/src/extensions/house/houseext.cpp @@ -28,29 +28,22 @@ #include "houseext.h" #include "house.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all HouseTypeClass extension instances. - */ -ExtensionMap HouseClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -HouseClassExtension::HouseClassExtension(HouseClass *this_ptr) : - Extension(this_ptr) +HouseClassExtension::HouseClassExtension(const HouseClass *this_ptr) : + AbstractClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("HouseClassExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("HouseClassExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("HouseClassExtension::HouseClassExtension - 0x%08X\n", (uintptr_t)(This())); - IsInitialized = true; + HouseExtensions.Add(this); } @@ -60,9 +53,9 @@ HouseClassExtension::HouseClassExtension(HouseClass *this_ptr) : * @author: CCHyper */ HouseClassExtension::HouseClassExtension(const NoInitClass &noinit) : - Extension(noinit) + AbstractClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("HouseClassExtension::HouseClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ HouseClassExtension::HouseClassExtension(const NoInitClass &noinit) : */ HouseClassExtension::~HouseClassExtension() { - //EXT_DEBUG_TRACE("HouseClassExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("HouseClassExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("HouseClassExtension::~HouseClassExtension - 0x%08X\n", (uintptr_t)(This())); + + HouseExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT HouseClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("HouseClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); - IsInitialized = false; + return S_OK; } @@ -87,10 +98,9 @@ HouseClassExtension::~HouseClassExtension() */ HRESULT HouseClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("HouseClassExtension::Load - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("HouseClassExtension::Load - 0x%08X\n", (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = AbstractClassExtension::Internal_Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT HouseClassExtension::Load(IStream *pStm) */ HRESULT HouseClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("HouseClassExtension::Save - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("HouseClassExtension::Save - 0x%08X\n", (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = AbstractClassExtension::Internal_Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT HouseClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int HouseClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("HouseClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("HouseClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int HouseClassExtension::Size_Of() const */ void HouseClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("HouseClassExtension::Detach - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("HouseClassExtension::Detach - 0x%08X\n", (uintptr_t)(This())); } @@ -153,6 +160,5 @@ void HouseClassExtension::Detach(TARGET target, bool all) */ void HouseClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("HouseClassExtension::Compute_CRC - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("HouseClassExtension::Compute_CRC - 0x%08X\n", (uintptr_t)(This())); } diff --git a/src/extensions/house/houseext.h b/src/extensions/house/houseext.h index 2d114413..83acebde 100644 --- a/src/extensions/house/houseext.h +++ b/src/extensions/house/houseext.h @@ -27,31 +27,41 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "abstractext.h" +#include "house.h" +#include "housetype.h" -class HouseClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_HOUSE_EXTENSION) +HouseClassExtension final : public AbstractClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class HouseClassExtension final : public Extension -{ public: - HouseClassExtension(HouseClass *this_ptr); + HouseClassExtension(const HouseClass *this_ptr = nullptr); HouseClassExtension(const NoInitClass &noinit); - ~HouseClassExtension(); + virtual ~HouseClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - public: + virtual const char *Name() const override { return reinterpret_cast(This())->Class->Name(); } + virtual const char *Full_Name() const override { return reinterpret_cast(This())->Class->Full_Name(); } + + virtual HouseClass *This() const override { return reinterpret_cast(AbstractClassExtension::This()); } + virtual const HouseClass *This_Const() const override { return reinterpret_cast(AbstractClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_HOUSE; } + public: }; - - -extern ExtensionMap HouseClassExtensions; diff --git a/src/extensions/house/houseext_hooks.cpp b/src/extensions/house/houseext_hooks.cpp index 96dd3ff7..534fe313 100644 --- a/src/extensions/house/houseext_hooks.cpp +++ b/src/extensions/house/houseext_hooks.cpp @@ -147,8 +147,7 @@ DECLARE_PATCH(_HouseClass_Can_Build_BuildCheat_Patch) _asm { mov ecx, vector_count } _asm { test ecx, ecx } - _asm { mov ecx, 0x004BBD2E }; // Need to use ECX as EAX is used later on. - _asm { jmp ecx }; + JMP_REG(ecx, 0x004BBD2E); // Need to use ECX as EAX is used later on. return_true: JMP(0x004BBD17); diff --git a/src/extensions/house/houseext_init.cpp b/src/extensions/house/houseext_init.cpp index 3c058d65..cbf3bfed 100644 --- a/src/extensions/house/houseext_init.cpp +++ b/src/extensions/house/houseext_init.cpp @@ -30,10 +30,15 @@ #include "house.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,48 +51,19 @@ DECLARE_PATCH(_HouseClass_Constructor_Patch) { GET_REGISTER_STATIC(HouseClass *, this_ptr, ebp); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0xC); // ini name. - static HouseClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating HouseClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = HouseClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create HouseClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create HouseClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create HouseClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { add esp, 0x2C } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_HouseClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(HouseClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. @@ -98,7 +74,7 @@ DECLARE_PATCH(_HouseClass_NoInit_Constructor_Patch) _asm { pop esi } _asm { pop ebp } _asm { pop ebx } - _asm { pop ecx } + _asm { add esp, 0x2C } _asm { ret 4 } } @@ -117,92 +93,14 @@ DECLARE_PATCH(_HouseClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - HouseClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { pop ecx } - _asm { ret } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_HouseClass_Detach_Patch) -{ - GET_REGISTER_STATIC(HouseClass *, this_ptr, edi); - GET_STACK_STATIC(TARGET, target, esp, 0x4); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static HouseClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = HouseClassExtensions.find(this_ptr, false); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class detach. - */ - exttype_ptr->Detach(target, all); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop ebp } - _asm { pop ebx } - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_HouseClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(HouseClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0x10); - static HouseClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = HouseClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class detach. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } + _asm { mov edx, ds:0x007E1558 } // Houses.vtble + JMP_REG(eax, 0x004BB9BD); } @@ -212,8 +110,5 @@ DECLARE_PATCH(_HouseClass_Compute_CRC_Patch) void HouseClassExtension_Init() { Patch_Jump(0x004BAEBE, &_HouseClass_Constructor_Patch); - Patch_Jump(0x004BA0A3, &_HouseClass_NoInit_Constructor_Patch); - Patch_Jump(0x004BBBF5, &_HouseClass_Destructor_Patch); - Patch_Jump(0x004BF0FA, &_HouseClass_Detach_Patch); - Patch_Jump(0x004C49F1, &_HouseClass_Compute_CRC_Patch); + Patch_Jump(0x004BB9B7, &_HouseClass_Destructor_Patch); } diff --git a/src/extensions/housetype/housetypeext.cpp b/src/extensions/housetype/housetypeext.cpp index 1f983226..07dc9d06 100644 --- a/src/extensions/housetype/housetypeext.cpp +++ b/src/extensions/housetype/housetypeext.cpp @@ -28,29 +28,22 @@ #include "housetypeext.h" #include "housetype.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all HouseTypeClass extension instances. - */ -ExtensionMap HouseTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -HouseTypeClassExtension::HouseTypeClassExtension(HouseTypeClass *this_ptr) : - Extension(this_ptr) +HouseTypeClassExtension::HouseTypeClassExtension(const HouseTypeClass *this_ptr) : + AbstractTypeClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("HouseTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("HouseTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("HouseTypeClassExtension::HouseTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + HouseTypeExtensions.Add(this); } @@ -60,9 +53,9 @@ HouseTypeClassExtension::HouseTypeClassExtension(HouseTypeClass *this_ptr) : * @author: CCHyper */ HouseTypeClassExtension::HouseTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + AbstractTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("HouseTypeClassExtension::HouseTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ HouseTypeClassExtension::HouseTypeClassExtension(const NoInitClass &noinit) : */ HouseTypeClassExtension::~HouseTypeClassExtension() { - //EXT_DEBUG_TRACE("HouseTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("HouseTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("HouseTypeClassExtension::~HouseTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + HouseTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT HouseTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("HouseTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -87,10 +98,9 @@ HouseTypeClassExtension::~HouseTypeClassExtension() */ HRESULT HouseTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("HouseTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("HouseTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = AbstractTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT HouseTypeClassExtension::Load(IStream *pStm) */ HRESULT HouseTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("HouseTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("HouseTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = AbstractTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT HouseTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int HouseTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("HouseTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("HouseTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int HouseTypeClassExtension::Size_Of() const */ void HouseTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("HouseTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("HouseTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,8 +160,7 @@ void HouseTypeClassExtension::Detach(TARGET target, bool all) */ void HouseTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("HouseTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("HouseTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -165,11 +171,13 @@ void HouseTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool HouseTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("HouseTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("HouseTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("HouseTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (!AbstractTypeClassExtension::Read_INI(ini)) { + return false; + } - const char *ini_name = ThisPtr->Name(); + const char *ini_name = Name(); if (!ini.Is_Present(ini_name)) { return false; diff --git a/src/extensions/housetype/housetypeext.h b/src/extensions/housetype/housetypeext.h index 2d464711..cd688358 100644 --- a/src/extensions/housetype/housetypeext.h +++ b/src/extensions/housetype/housetypeext.h @@ -27,33 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "abstracttypeext.h" +#include "housetype.h" -class HouseTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_HOUSETYPE_EXTENSION) +HouseTypeClassExtension final : public AbstractTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class HouseTypeClassExtension final : public Extension -{ public: - HouseTypeClassExtension(HouseTypeClass *this_ptr); + HouseTypeClassExtension(const HouseTypeClass *this_ptr = nullptr); HouseTypeClassExtension(const NoInitClass &noinit); - ~HouseTypeClassExtension(); + virtual ~HouseTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + + virtual HouseTypeClass *This() const override { return reinterpret_cast(AbstractTypeClassExtension::This()); } + virtual const HouseTypeClass *This_Const() const override { return reinterpret_cast(AbstractTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_HOUSETYPE; } - bool Read_INI(CCINIClass &ini); + virtual bool Read_INI(CCINIClass &ini) override; public: - }; - - -extern ExtensionMap HouseTypeClassExtensions; diff --git a/src/extensions/housetype/housetypeext_init.cpp b/src/extensions/housetype/housetypeext_init.cpp index a5eaf4b4..9d1aa9b2 100644 --- a/src/extensions/housetype/housetypeext_init.cpp +++ b/src/extensions/housetype/housetypeext_init.cpp @@ -30,10 +30,15 @@ #include "housetype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,45 +51,19 @@ DECLARE_PATCH(_HouseTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(HouseTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0xC); // ini name. - static HouseTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating HouseTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = HouseTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create HouseTypeClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create HouseTypeClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create HouseTypeClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_HouseTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(HouseTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. @@ -92,6 +71,7 @@ DECLARE_PATCH(_HouseTypeClass_NoInit_Constructor_Patch) original_code: _asm { mov eax, this_ptr } _asm { pop esi } + _asm { pop ebx } _asm { ret 4 } } @@ -110,15 +90,14 @@ DECLARE_PATCH(_HouseTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - HouseTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007E21D0 } // HouseTypes.vtble + JMP_REG(eax, 0x004CDE9E); } @@ -136,92 +115,14 @@ DECLARE_PATCH(_HouseTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - HouseTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_HouseTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(HouseTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0x10); - static HouseTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = HouseTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class detach. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_HouseTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(HouseTypeClass *, this_ptr, ebx); - GET_STACK_STATIC(CCINIClass *, ini, ebp, 0x8); // Can't use ESI as its reused by this point. - static HouseTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = HouseTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov al, 1 } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { mov esp, ebp } - _asm { pop ebp } - _asm { ret 4 } + _asm { mov edx, ds:0x007E21D0 } // HouseTypes.vtble + JMP_REG(eax, 0x004CE60E); } @@ -231,9 +132,6 @@ DECLARE_PATCH(_HouseTypeClass_Read_INI_Patch) void HouseTypeClassExtension_Init() { Patch_Jump(0x004CDE57, &_HouseTypeClass_Constructor_Patch); - Patch_Jump(0x004CDE7A, &_HouseTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x004CDEE8, &_HouseTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x004CE668, &_HouseTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x004CE2FE, &_HouseTypeClass_Compute_CRC_Patch); - Patch_Jump(0x004CE1F3, &_HouseTypeClass_Read_INI_Patch); + //Patch_Jump(0x004CDE98, &_HouseTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x004CE608, &_HouseTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/infantry/infantryext.cpp b/src/extensions/infantry/infantryext.cpp index d7180a97..ff5e60a5 100644 --- a/src/extensions/infantry/infantryext.cpp +++ b/src/extensions/infantry/infantryext.cpp @@ -28,29 +28,22 @@ #include "infantryext.h" #include "infantry.h" #include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all InfantryClass extension instances. - */ -ExtensionMap InfantryClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -InfantryClassExtension::InfantryClassExtension(InfantryClass *this_ptr) : - Extension(this_ptr) +InfantryClassExtension::InfantryClassExtension(const InfantryClass *this_ptr) : + FootClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("InfantryClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("InfantryClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("InfantryClassExtension::InfantryClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + InfantryExtensions.Add(this); } @@ -60,9 +53,9 @@ InfantryClassExtension::InfantryClassExtension(InfantryClass *this_ptr) : * @author: CCHyper */ InfantryClassExtension::InfantryClassExtension(const NoInitClass &noinit) : - Extension(noinit) + FootClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("InfantryClassExtension::InfantryClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ InfantryClassExtension::InfantryClassExtension(const NoInitClass &noinit) : */ InfantryClassExtension::~InfantryClassExtension() { - //EXT_DEBUG_TRACE("InfantryClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("InfantryClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("InfantryClassExtension::~InfantryClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + InfantryExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT InfantryClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("InfantryClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); - IsInitialized = false; + return S_OK; } @@ -87,10 +98,9 @@ InfantryClassExtension::~InfantryClassExtension() */ HRESULT InfantryClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("InfantryClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("InfantryClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = FootClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT InfantryClassExtension::Load(IStream *pStm) */ HRESULT InfantryClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("InfantryClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("InfantryClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = FootClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT InfantryClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int InfantryClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("InfantryClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("InfantryClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int InfantryClassExtension::Size_Of() const */ void InfantryClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("InfantryClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("InfantryClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,6 +160,5 @@ void InfantryClassExtension::Detach(TARGET target, bool all) */ void InfantryClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("InfantryClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("InfantryClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } diff --git a/src/extensions/infantry/infantryext.h b/src/extensions/infantry/infantryext.h index 563bd77b..bf12c33d 100644 --- a/src/extensions/infantry/infantryext.h +++ b/src/extensions/infantry/infantryext.h @@ -27,30 +27,41 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "footext.h" +#include "infantry.h" class InfantryClass; class HouseClass; -class InfantryClassExtension final : public Extension +class DECLSPEC_UUID(UUID_INFANTRY_EXTENSION) +InfantryClassExtension final : public FootClassExtension { public: - InfantryClassExtension(InfantryClass *this_ptr); + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + InfantryClassExtension(const InfantryClass *this_ptr = nullptr); InfantryClassExtension(const NoInitClass &noinit); - ~InfantryClassExtension(); + virtual ~InfantryClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + virtual InfantryClass *This() const override { return reinterpret_cast(FootClassExtension::This()); } + virtual const InfantryClass *This_Const() const override { return reinterpret_cast(FootClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_INFANTRY; } + public: }; - - -extern ExtensionMap InfantryClassExtensions; diff --git a/src/extensions/infantry/infantryext_hooks.cpp b/src/extensions/infantry/infantryext_hooks.cpp index 199ffef0..6810cf74 100644 --- a/src/extensions/infantry/infantryext_hooks.cpp +++ b/src/extensions/infantry/infantryext_hooks.cpp @@ -35,6 +35,7 @@ #include "target.h" #include "voc.h" #include "tibsun_globals.h" +#include "extension.h" #include "options.h" #include "wwkeyboard.h" #include "fatal.h" @@ -66,8 +67,8 @@ DECLARE_PATCH(_InfantryClass_Per_Cell_Process_Transport_Attach_Sound_Patch) /** * If this transport we are entering has a passenger entering sound, play it now. */ - radio_technotypeext = TechnoTypeClassExtensions.find(techno->Techno_Type_Class()); - if (radio_technotypeext && radio_technotypeext->EnterTransportSound != VOC_NONE) { + radio_technotypeext = Extension::Fetch(techno->Techno_Type_Class()); + if (radio_technotypeext->EnterTransportSound != VOC_NONE) { Sound_Effect(radio_technotypeext->EnterTransportSound, techno->Coord); } @@ -88,12 +89,12 @@ DECLARE_PATCH(_InfantryClass_Firing_AI_Mechanic_Patch) GET_REGISTER_STATIC(ObjectClass *, targ, esi); // TarCom as ObjectClass. static InfantryTypeClassExtension *infantrytypeext; - infantrytypeext = InfantryTypeClassExtensions.find(this_ptr->Class); + infantrytypeext = Extension::Fetch(this_ptr->Class); /** * Is this infantry a "dual healer" (can it heal both infantry and units)? */ - if (infantrytypeext && infantrytypeext->IsOmniHealer) { + if (infantrytypeext->IsOmniHealer) { /** * Is the target being queried a unit, aircraft or infantry? If so, make @@ -106,7 +107,7 @@ DECLARE_PATCH(_InfantryClass_Firing_AI_Mechanic_Patch) /** * Is this infantry a mechanic? */ - } else if (infantrytypeext && infantrytypeext->IsMechanic) { + } else if (infantrytypeext->IsMechanic) { /** * Is the target being queried a unit or aircraft? If so, make sure this @@ -147,12 +148,12 @@ DECLARE_PATCH(_InfantryClass_What_Action_Mechanic_Patch) GET_REGISTER_STATIC(/*const */ObjectClass *, object, esi); // target static InfantryTypeClassExtension *infantrytypeext; - infantrytypeext = InfantryTypeClassExtensions.find(this_ptr->Class); + infantrytypeext = Extension::Fetch(this_ptr->Class); /** * Is this infantry a "dual healer" (can it heal both infantry and units)? */ - if (infantrytypeext && infantrytypeext->IsOmniHealer) { + if (infantrytypeext->IsOmniHealer) { /** * If the mouse is over ourself, show the guard area cursor. @@ -185,7 +186,7 @@ DECLARE_PATCH(_InfantryClass_What_Action_Mechanic_Patch) /** * Is this infantry a mechanic? */ - } else if (infantrytypeext && infantrytypeext->IsMechanic) { + } else if (infantrytypeext->IsMechanic) { /** * If the mouse is over ourself, show the guard area cursor. diff --git a/src/extensions/infantry/infantryext_init.cpp b/src/extensions/infantry/infantryext_init.cpp index 2914a87f..b95228b9 100644 --- a/src/extensions/infantry/infantryext_init.cpp +++ b/src/extensions/infantry/infantryext_init.cpp @@ -29,10 +29,16 @@ #include "infantrytypeext.h" #include "infantry.h" #include "infantrytype.h" +#include "vinifera_util.h" +#include "vinifera_globals.h" +#include "tibsun_globals.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" -#include "vinifera_util.h" + +#include "hooker.h" +#include "hooker_macros.h" /** @@ -45,21 +51,20 @@ DECLARE_PATCH(_InfantryClass_Constructor_Patch) { GET_REGISTER_STATIC(InfantryClass *, this_ptr, esi); // Current "this" pointer. - static InfantryClassExtension *exttype_ptr; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = InfantryClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create InfantryClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create InfantryClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create InfantryClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * Stolen bytes here. */ @@ -72,28 +77,6 @@ DECLARE_PATCH(_InfantryClass_Constructor_Patch) } -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_InfantryClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(InfantryClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit, esp, 0x20); - static InfantryClassExtension *ext_ptr; - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov dword ptr [esi], 0x006D211C } // this->vftable = const InfantryClass::`vftable'; - JMP(0x004D9415); -} - - /** * Patch for including the extended class members in the destruction process. * @@ -108,84 +91,14 @@ DECLARE_PATCH(_InfantryClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - InfantryClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { add esp, 0x8 } - _asm { ret } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_InfantryClass_Detach_Patch) -{ - GET_REGISTER_STATIC(InfantryClass *, this_ptr, esi); - GET_STACK_STATIC(TARGET, target, esp, 0x10); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static InfantryClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = InfantryClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Detach(target, all); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members to the base class crc calculation. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_InfantryClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(InfantryClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static InfantryClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = InfantryClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } + _asm { mov eax, ds:0x007E2300 } // Infantry.vtble + JMP_REG(edx, 0x004D22E6); } @@ -195,8 +108,5 @@ DECLARE_PATCH(_InfantryClass_Compute_CRC_Patch) void InfantryClassExtension_Init() { Patch_Jump(0x004D21E1, &_InfantryClass_Constructor_Patch); - Patch_Jump(0x004D940F, &_InfantryClass_NoInit_Constructor_Patch); - Patch_Jump(0x004D23F2, &_InfantryClass_Destructor_Patch); - Patch_Jump(0x004D40E5, &_InfantryClass_Detach_Patch); - Patch_Jump(0x004D96DB, &_InfantryClass_Compute_CRC_Patch); + Patch_Jump(0x004D22E1, &_InfantryClass_Destructor_Patch); } diff --git a/src/extensions/infantrytype/infantrytypeext.cpp b/src/extensions/infantrytype/infantrytypeext.cpp index 9571998a..328b4945 100644 --- a/src/extensions/infantrytype/infantrytypeext.cpp +++ b/src/extensions/infantrytype/infantrytypeext.cpp @@ -28,31 +28,25 @@ #include "infantrytypeext.h" #include "infantrytype.h" #include "ccini.h" +#include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all InfantryTypeClass extension instances. - */ -ExtensionMap InfantryTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -InfantryTypeClassExtension::InfantryTypeClassExtension(InfantryTypeClass *this_ptr) : - Extension(this_ptr), +InfantryTypeClassExtension::InfantryTypeClassExtension(const InfantryTypeClass *this_ptr) : + TechnoTypeClassExtension(this_ptr), IsMechanic(false), IsOmniHealer(false) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("InfantryTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("InfantryTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("InfantryTypeClassExtension::InfantryTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + InfantryTypeExtensions.Add(this); } @@ -62,9 +56,9 @@ InfantryTypeClassExtension::InfantryTypeClassExtension(InfantryTypeClass *this_p * @author: CCHyper */ InfantryTypeClassExtension::InfantryTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + TechnoTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("InfantryTypeClassExtension::InfantryTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -75,10 +69,28 @@ InfantryTypeClassExtension::InfantryTypeClassExtension(const NoInitClass &noinit */ InfantryTypeClassExtension::~InfantryTypeClassExtension() { - //EXT_DEBUG_TRACE("InfantryTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("InfantryTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("InfantryTypeClassExtension::~InfantryTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + InfantryTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT InfantryTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("InfantryTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -89,10 +101,9 @@ InfantryTypeClassExtension::~InfantryTypeClassExtension() */ HRESULT InfantryTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("InfantryTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("InfantryTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = TechnoTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -110,10 +121,9 @@ HRESULT InfantryTypeClassExtension::Load(IStream *pStm) */ HRESULT InfantryTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("InfantryTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("InfantryTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = TechnoTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -129,8 +139,7 @@ HRESULT InfantryTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int InfantryTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("InfantryTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("InfantryTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -143,8 +152,7 @@ int InfantryTypeClassExtension::Size_Of() const */ void InfantryTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("InfantryTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("InfantryTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -155,8 +163,7 @@ void InfantryTypeClassExtension::Detach(TARGET target, bool all) */ void InfantryTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("InfantryTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("InfantryTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); crc(IsMechanic); crc(IsOmniHealer); @@ -170,16 +177,14 @@ void InfantryTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool InfantryTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("InfantryTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("InfantryTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("InfantryTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - const char *ini_name = ThisPtr->Name(); - - if (!ini.Is_Present(ini_name)) { + if (!TechnoTypeClassExtension::Read_INI(ini)) { return false; } + const char *ini_name = Name(); + IsMechanic = ini.Get_Bool(ini_name, "Mechanic", IsMechanic); IsOmniHealer = ini.Get_Bool(ini_name, "OmniHealer", IsOmniHealer); diff --git a/src/extensions/infantrytype/infantrytypeext.h b/src/extensions/infantrytype/infantrytypeext.h index 0403e401..c66ac550 100644 --- a/src/extensions/infantrytype/infantrytypeext.h +++ b/src/extensions/infantrytype/infantrytypeext.h @@ -27,29 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "technotypeext.h" +#include "infantrytype.h" -class InfantryTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_INFANTRYTYPE_EXTENSION) +InfantryTypeClassExtension final : public TechnoTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class InfantryTypeClassExtension final : public Extension -{ public: - InfantryTypeClassExtension(InfantryTypeClass *this_ptr); + InfantryTypeClassExtension(const InfantryTypeClass *this_ptr = nullptr); InfantryTypeClassExtension(const NoInitClass &noinit); - ~InfantryTypeClassExtension(); + virtual ~InfantryTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + + virtual InfantryTypeClass *This() const override { return reinterpret_cast(TechnoTypeClassExtension::This()); } + virtual const InfantryTypeClass *This_Const() const override { return reinterpret_cast(TechnoTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_INFANTRYTYPE; } - bool Read_INI(CCINIClass &ini); + virtual bool Read_INI(CCINIClass &ini) override; public: /** @@ -64,6 +74,3 @@ class InfantryTypeClassExtension final : public Extension */ bool IsOmniHealer; }; - - -extern ExtensionMap InfantryTypeClassExtensions; diff --git a/src/extensions/infantrytype/infantrytypeext_init.cpp b/src/extensions/infantrytype/infantrytypeext_init.cpp index d66713fe..e98534db 100644 --- a/src/extensions/infantrytype/infantrytypeext_init.cpp +++ b/src/extensions/infantrytype/infantrytypeext_init.cpp @@ -30,10 +30,15 @@ #include "infantrytype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,45 +51,19 @@ DECLARE_PATCH(_InfantryTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(InfantryTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0x0C); // ini name. - static InfantryTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating InfantryTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = InfantryTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create InfantryTypeClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create InfantryTypeClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create InfantryTypeClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_InfantryTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(InfantryTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. @@ -92,6 +71,7 @@ DECLARE_PATCH(_InfantryTypeClass_NoInit_Constructor_Patch) original_code: _asm { mov eax, this_ptr } _asm { pop esi } + _asm { pop ebx } _asm { ret 4 } } @@ -110,16 +90,14 @@ DECLARE_PATCH(_InfantryTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - InfantryTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ebx } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007E4010 } // InfantryType.vtble + JMP_REG(eax, 0x004DA3BF); } @@ -137,92 +115,14 @@ DECLARE_PATCH(_InfantryTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - InfantryTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_InfantryTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(InfantryTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static InfantryTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = InfantryTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_InfantryTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(InfantryTypeClass *, this_ptr, esi); - GET_REGISTER_STATIC(CCINIClass *, ini, ebp); - static InfantryTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = InfantryTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov al, 1 } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { add esp, 0x1C } - _asm { ret 4 } + _asm { mov edx, ds:0x007E4010 } // InfantryType.vtble + JMP_REG(eax, 0x004DB13E); } @@ -232,9 +132,6 @@ DECLARE_PATCH(_InfantryTypeClass_Read_INI_Patch) void InfantryTypeClassExtension_Init() { Patch_Jump(0x004DA360, &_InfantryTypeClass_Constructor_Patch); - Patch_Jump(0x004DA394, &_InfantryTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x004DA457, &_InfantryTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x004DB1E9, &_InfantryTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x004DAE11, &_InfantryTypeClass_Compute_CRC_Patch); - Patch_Jump(0x004DAC2F, &_InfantryTypeClass_Read_INI_Patch); + //Patch_Jump(0x004DA3B9, &_InfantryTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x004DB138, &_InfantryTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/isotiletype/isotiletypeext.cpp b/src/extensions/isotiletype/isotiletypeext.cpp index bba079f4..cd4b4ac4 100644 --- a/src/extensions/isotiletype/isotiletypeext.cpp +++ b/src/extensions/isotiletype/isotiletypeext.cpp @@ -31,30 +31,23 @@ #include "scenario.h" #include "theatertype.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all IsometricTileTypeClass extension instances. - */ -ExtensionMap IsometricTileTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -IsometricTileTypeClassExtension::IsometricTileTypeClassExtension(IsometricTileTypeClass *this_ptr) : - Extension(this_ptr), +IsometricTileTypeClassExtension::IsometricTileTypeClassExtension(const IsometricTileTypeClass *this_ptr) : + ObjectTypeClassExtension(this_ptr), TileSetName(nullptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("IsometricTileTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::~IsometricTileTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + IsometricTileTypeExtensions.Add(this); } @@ -64,9 +57,9 @@ IsometricTileTypeClassExtension::IsometricTileTypeClassExtension(IsometricTileTy * @author: CCHyper */ IsometricTileTypeClassExtension::IsometricTileTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::~IsometricTileTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -77,10 +70,28 @@ IsometricTileTypeClassExtension::IsometricTileTypeClassExtension(const NoInitCla */ IsometricTileTypeClassExtension::~IsometricTileTypeClassExtension() { - //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("IsometricTileTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::~IsometricTileTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + IsometricTileTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT IsometricTileTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -91,10 +102,9 @@ IsometricTileTypeClassExtension::~IsometricTileTypeClassExtension() */ HRESULT IsometricTileTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -112,10 +122,9 @@ HRESULT IsometricTileTypeClassExtension::Load(IStream *pStm) */ HRESULT IsometricTileTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -131,8 +140,7 @@ HRESULT IsometricTileTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int IsometricTileTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -145,8 +153,7 @@ int IsometricTileTypeClassExtension::Size_Of() const */ void IsometricTileTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -157,8 +164,7 @@ void IsometricTileTypeClassExtension::Detach(TARGET target, bool all) */ void IsometricTileTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -169,11 +175,13 @@ void IsometricTileTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool IsometricTileTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::Read_INI - Name: %s, TileSetName %s (0x%08X)\n", ThisPtr->Name(), TileSetName, (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("IsometricTileTypeClassExtension::Read_INI - Name: %s, TileSetName %s (0x%08X)\n", ThisPtr->Name(), TileSetName, (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("IsometricTileTypeClassExtension::Read_INI - Name: %s, TileSetName %s (0x%08X)\n", Name(), TileSetName, (uintptr_t)(This())); + + if (!ObjectTypeClassExtension::Read_INI(ini)) { + return false; + } - const char *ini_name = ThisPtr->Name(); + const char *ini_name = Name(); if (!ini.Is_Present(ini_name)) { return false; diff --git a/src/extensions/isotiletype/isotiletypeext.h b/src/extensions/isotiletype/isotiletypeext.h index 9e49d6f9..4a5b4411 100644 --- a/src/extensions/isotiletype/isotiletypeext.h +++ b/src/extensions/isotiletype/isotiletypeext.h @@ -27,29 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "objecttypeext.h" +#include "isotiletype.h" -class IsometricTileTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_ISOTILE_EXTENSION) +IsometricTileTypeClassExtension final : public ObjectTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class IsometricTileTypeClassExtension final : public Extension -{ public: - IsometricTileTypeClassExtension(IsometricTileTypeClass *this_ptr); + IsometricTileTypeClassExtension(const IsometricTileTypeClass *this_ptr = nullptr); IsometricTileTypeClassExtension(const NoInitClass &noinit); - ~IsometricTileTypeClassExtension(); + virtual ~IsometricTileTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual IsometricTileTypeClass *This() const override { return reinterpret_cast(ObjectTypeClassExtension::This()); } + virtual const IsometricTileTypeClass *This_Const() const override { return reinterpret_cast(ObjectTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_ISOTILETYPE; } + + virtual bool Read_INI(CCINIClass &ini) override; /** * Initialises theater control file globals. @@ -61,8 +71,4 @@ class IsometricTileTypeClassExtension final : public Extension IsometricTileTypeClassExtensions; diff --git a/src/extensions/isotiletype/isotiletypeext_hooks.cpp b/src/extensions/isotiletype/isotiletypeext_hooks.cpp index f5dd12d6..d0eaf996 100644 --- a/src/extensions/isotiletype/isotiletypeext_hooks.cpp +++ b/src/extensions/isotiletype/isotiletypeext_hooks.cpp @@ -33,6 +33,9 @@ #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * A fake class for implementing new member functions which allow @@ -41,7 +44,7 @@ * @note: This must not contain a constructor or deconstructor! * @note: All functions must be prefixed with "_" to prevent accidental virtualization. */ -static class IsometricTileTypeClassFake final : public IsometricTileTypeClass +static class IsometricTileTypeClassExt final : public IsometricTileTypeClass { public: const ShapeFileStruct * _Get_Image_Data(); @@ -53,7 +56,7 @@ static class IsometricTileTypeClassFake final : public IsometricTileTypeClass * * @author: CCHyper */ -const ShapeFileStruct * IsometricTileTypeClassFake::_Get_Image_Data() +const ShapeFileStruct * IsometricTileTypeClassExt::_Get_Image_Data() { if (Image) { return Image; @@ -81,5 +84,5 @@ void IsometricTileTypeClassExtension_Hooks() */ IsometricTileTypeClassExtension_Init(); - Patch_Jump(0x004F3570, &IsometricTileTypeClassFake::_Get_Image_Data); + Patch_Jump(0x004F3570, &IsometricTileTypeClassExt::_Get_Image_Data); } diff --git a/src/extensions/isotiletype/isotiletypeext_init.cpp b/src/extensions/isotiletype/isotiletypeext_init.cpp index 220829f8..0c198cd7 100644 --- a/src/extensions/isotiletype/isotiletypeext_init.cpp +++ b/src/extensions/isotiletype/isotiletypeext_init.cpp @@ -30,10 +30,15 @@ #include "isotiletype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,22 +51,22 @@ DECLARE_PATCH(_IsometricTileTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(IsometricTileTypeClass *, this_ptr, ebp); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0x50); // ini name. - static IsometricTileTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating IsometricTileTypeClassExtension instance for \"%s\".\n", ini_name); + // IsoTileTypes's are not saved to file, so this case is not required. +#if 0 /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = IsometricTileTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create IsometricTileTypeClassExtension instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create IsometricTileTypeClassExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create IsometricTileTypeClassExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } +#endif + + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); /** * Stolen bytes here. @@ -76,28 +81,6 @@ DECLARE_PATCH(_IsometricTileTypeClass_Constructor_Patch) } -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_IsometricTileTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(IsometricTileTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { ret 4 } -} - - /** * Patch for including the extended class members in the destruction process. * @@ -112,87 +95,14 @@ DECLARE_PATCH(_IsometricTileTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - IsometricTileTypeClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop esi } - _asm { pop ebx } - _asm { pop ecx } - _asm { ret } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_IsometricTileTypeClass_Detach_Patch) -{ - GET_REGISTER_STATIC(IsometricTileTypeClass *, this_ptr, esi); - GET_STACK_STATIC(TARGET, target, esp, 0x4); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static IsometricTileTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = IsometricTileTypeClassExtensions.find(this_ptr, false); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class detach. - */ - exttype_ptr->Detach(target, all); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_IsometricTileTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(IsometricTileTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static IsometricTileTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = IsometricTileTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } + _asm { mov edx, ds:0x0080F588 } // Neuron vector vtble + JMP_REG(eax, 0x004F33CC); } @@ -244,12 +154,9 @@ DECLARE_PATCH(_IsometricTileTypeClass_Read_INI_Patch_1) _asm { mov [esp+0x20], ebp } /** - * Find the extension instance. + * Fetch the extension instance. */ - exttype_ptr = IsometricTileTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } + exttype_ptr = Extension::Fetch(this_ptr); /** * Read type class ini. @@ -293,12 +200,9 @@ DECLARE_PATCH(_IsometricTileTypeClass_Read_INI_Patch_2) _asm { mov [esp+0x20], ebp } // Must be before to retain stack. /** - * Find the extension instance. + * Fetch the extension instance. */ - exttype_ptr = IsometricTileTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } + exttype_ptr = Extension::Fetch(this_ptr); /** * Read type class ini. @@ -321,10 +225,7 @@ DECLARE_PATCH(_IsometricTileTypeClass_Read_INI_Patch_2) void IsometricTileTypeClassExtension_Init() { Patch_Jump(0x004F32C4, &_IsometricTileTypeClass_Constructor_Patch); - Patch_Jump(0x004F331F, &_IsometricTileTypeClass_NoInit_Constructor_Patch); - Patch_Jump(0x004F34A2, &_IsometricTileTypeClass_Destructor_Patch); - //Patch_Jump(0x004F872E, &_IsometricTileTypeClass_Detach_Patch); - Patch_Jump(0x004F85AA, &_IsometricTileTypeClass_Compute_CRC_Patch); + Patch_Jump(0x004F33C6, &_IsometricTileTypeClass_Destructor_Patch); Patch_Jump(0x004F55F2, &_IsometricTileTypeClass_Init_Patch); Patch_Jump(0x004F50AE, &_IsometricTileTypeClass_Read_INI_Patch_1); Patch_Jump(0x004F53E9, &_IsometricTileTypeClass_Read_INI_Patch_2); diff --git a/src/extensions/movie/playmovie_hooks.cpp b/src/extensions/movie/playmovie_hooks.cpp index 1cd06bae..6c52bd0f 100644 --- a/src/extensions/movie/playmovie_hooks.cpp +++ b/src/extensions/movie/playmovie_hooks.cpp @@ -36,6 +36,7 @@ #include "playmovie.h" #include "cd.h" #include "wstring.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" @@ -186,7 +187,7 @@ static bool Play_Intro_Movie(CampaignType campaign_id) */ bool is_original_gdi = (cd_num == DISK_GDI && (Wstring(campaign->IniName) == "GDI1" || Wstring(campaign->IniName) == "GDI1A") && Wstring(campaign->Scenario) == "GDI1A.MAP"); bool is_original_nod = (cd_num == DISK_NOD && (Wstring(campaign->IniName) == "NOD1" || Wstring(campaign->IniName) == "NOD1A") && Wstring(campaign->Scenario) == "NOD1A.MAP"); - + /** * #issue-762 * @@ -194,8 +195,8 @@ static bool Play_Intro_Movie(CampaignType campaign_id) * * @author: CCHyper */ - CampaignClassExtension *campaignext = CampaignClassExtensions.find(campaign); - if (campaignext && campaignext->IntroMovie[0] != '\0') { + CampaignClassExtension *campaignext = Extension::Fetch(campaign); + if (campaignext->IntroMovie[0] != '\0') { std::snprintf(movie_filename, sizeof(movie_filename), "%s.VQA", campaignext->IntroMovie); DEBUG_INFO("About to play \"%s\".\n", movie_filename); Play_Movie(movie_filename); diff --git a/src/extensions/object/objectext.cpp b/src/extensions/object/objectext.cpp new file mode 100644 index 00000000..fd9134e2 --- /dev/null +++ b/src/extensions/object/objectext.cpp @@ -0,0 +1,151 @@ +/******************************************************************************* +/* O P E N S O U R C E -- V I N I F E R A ** +/******************************************************************************* + * + * @project Vinifera + * + * @file OBJECTEXT.H + * + * @author CCHyper + * + * @brief Extended ObjectClass class. + * + * @license Vinifera is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 3 of the License, or (at your option) any later version. + * + * Vinifera is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. + * If not, see . + * + ******************************************************************************/ +#pragma once + +#include "objectext.h" +#include "objecttype.h" + + +/** + * Class constructor. + * + * @author: CCHyper + */ +ObjectClassExtension::ObjectClassExtension(const ObjectClass *this_ptr) : + AbstractClassExtension(this_ptr) +{ + //if (this_ptr) EXT_DEBUG_TRACE("ObjectClassExtension::ObjectClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); +} + + +/** + * Class no-init constructor. + * + * @author: CCHyper + */ +ObjectClassExtension::ObjectClassExtension(const NoInitClass &noinit) : + AbstractClassExtension(noinit) +{ + //EXT_DEBUG_TRACE("ObjectClassExtension::ObjectClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); +} + + +/** + * Class destructor. + * + * @author: CCHyper + */ +ObjectClassExtension::~ObjectClassExtension() +{ + //EXT_DEBUG_TRACE("ObjectClassExtension::~ObjectClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); +} + + +/** + * Initializes an object from the stream where it was saved previously. + * + * @author: CCHyper + */ +HRESULT ObjectClassExtension::Load(IStream *pStm) +{ + //EXT_DEBUG_TRACE("ObjectClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + HRESULT hr = AbstractClassExtension::Internal_Load(pStm); + if (FAILED(hr)) { + return E_FAIL; + } + + return hr; +} + + + +/** + * Saves an object to the specified stream. + * + * @author: CCHyper + */ +HRESULT ObjectClassExtension::Save(IStream *pStm, BOOL fClearDirty) +{ + //EXT_DEBUG_TRACE("ObjectClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + HRESULT hr = AbstractClassExtension::Internal_Save(pStm, fClearDirty); + if (FAILED(hr)) { + return hr; + } + + return hr; +} + + +/** + * Removes the specified target from any targeting and reference trackers. + * + * @author: CCHyper + */ +void ObjectClassExtension::Detach(TARGET target, bool all) +{ + //EXT_DEBUG_TRACE("ObjectClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); +} + + +/** + * Compute a unique crc value for this instance. + * + * @author: CCHyper + */ +void ObjectClassExtension::Compute_CRC(WWCRCEngine &crc) const +{ + //EXT_DEBUG_TRACE("ObjectClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); +} + + +/** + * Returns the name of this object type. + * + * @author: CCHyper + */ +const char *ObjectClassExtension::Name() const +{ + //EXT_DEBUG_TRACE("ObjectClassExtension::Name - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + return reinterpret_cast(This())->Class_Of()->Name(); +} + + +/** + * Returns the full name of this object type. + * + * @author: CCHyper + */ +const char *ObjectClassExtension::Full_Name() const +{ + //EXT_DEBUG_TRACE("ObjectClassExtension::Full_Name - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + return reinterpret_cast(This())->Class_Of()->Full_Name(); +} diff --git a/src/extensions/object/objectext.h b/src/extensions/object/objectext.h new file mode 100644 index 00000000..f1fb59b7 --- /dev/null +++ b/src/extensions/object/objectext.h @@ -0,0 +1,59 @@ +/******************************************************************************* +/* O P E N S O U R C E -- V I N I F E R A ** +/******************************************************************************* + * + * @project Vinifera + * + * @file BUILDINGEXT.H + * + * @author CCHyper + * + * @brief Extended AircraftClass class. + * + * @license Vinifera is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 3 of the License, or (at your option) any later version. + * + * Vinifera is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. + * If not, see . + * + ******************************************************************************/ +#pragma once + +#include "abstractext.h" +#include "object.h" + + +class AircraftClass; +class HouseClass; + + +class ObjectClassExtension : public AbstractClassExtension +{ + public: + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + ObjectClassExtension(const ObjectClass *this_ptr); + ObjectClassExtension(const NoInitClass &noinit); + virtual ~ObjectClassExtension(); + + virtual void Detach(TARGET target, bool all = true) override; + virtual void Compute_CRC(WWCRCEngine &crc) const override; + + virtual const char *Name() const override; + virtual const char *Full_Name() const override; + + public: +}; diff --git a/src/extensions/objecttype/objecttypeext.cpp b/src/extensions/objecttype/objecttypeext.cpp index 563d663a..45d915dc 100644 --- a/src/extensions/objecttype/objecttypeext.cpp +++ b/src/extensions/objecttype/objecttypeext.cpp @@ -32,25 +32,17 @@ #include "debughandler.h" -/** - * Provides the map for all ObjectTypeClass extension instances. - */ -ExtensionMap ObjectTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -ObjectTypeClassExtension::ObjectTypeClassExtension(ObjectTypeClass *this_ptr) : - Extension(this_ptr) +ObjectTypeClassExtension::ObjectTypeClassExtension(const ObjectTypeClass *this_ptr) : + AbstractTypeClassExtension(this_ptr), + GraphicName(), + AlphaGraphicName() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ObjectTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("ObjectTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - - IsInitialized = true; + //if (this_ptr) EXT_DEBUG_TRACE("ObjectTypeClassExtension::ObjectTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -60,9 +52,9 @@ ObjectTypeClassExtension::ObjectTypeClassExtension(ObjectTypeClass *this_ptr) : * @author: CCHyper */ ObjectTypeClassExtension::ObjectTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + AbstractTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("ObjectTypeClassExtension::ObjectTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +65,7 @@ ObjectTypeClassExtension::ObjectTypeClassExtension(const NoInitClass &noinit) : */ ObjectTypeClassExtension::~ObjectTypeClassExtension() { - //EXT_DEBUG_TRACE("ObjectTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("ObjectTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - - IsInitialized = false; + //EXT_DEBUG_TRACE("ObjectTypeClassExtension::~ObjectTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -87,15 +76,12 @@ ObjectTypeClassExtension::~ObjectTypeClassExtension() */ HRESULT ObjectTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ObjectTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ObjectTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = AbstractTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } - - new (this) ObjectTypeClassExtension(NoInitClass()); return hr; } @@ -108,10 +94,15 @@ HRESULT ObjectTypeClassExtension::Load(IStream *pStm) */ HRESULT ObjectTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ObjectTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ObjectTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + /** + * Store the graphic name strings as raw data, these are used by the load operation. + */ + std::strncpy(GraphicName, Graphic_Name(), sizeof(GraphicName)); + std::strncpy(AlphaGraphicName, Alpha_Graphic_Name(), sizeof(AlphaGraphicName)); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = AbstractTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -120,20 +111,6 @@ HRESULT ObjectTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) } -/** - * Return the raw size of class data for save/load purposes. - * - * @author: CCHyper - */ -int ObjectTypeClassExtension::Size_Of() const -{ - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ObjectTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - - return sizeof(*this); -} - - /** * Removes the specified target from any targeting and reference trackers. * @@ -141,8 +118,7 @@ int ObjectTypeClassExtension::Size_Of() const */ void ObjectTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ObjectTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ObjectTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,8 +129,7 @@ void ObjectTypeClassExtension::Detach(TARGET target, bool all) */ void ObjectTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ObjectTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ObjectTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -165,11 +140,13 @@ void ObjectTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool ObjectTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ObjectTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("ObjectTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ObjectTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (!AbstractTypeClassExtension::Read_INI(ini)) { + return false; + } - const char *ini_name = ThisPtr->Name(); + const char *ini_name = Name(); if (!ini.Is_Present(ini_name)) { return false; diff --git a/src/extensions/objecttype/objecttypeext.h b/src/extensions/objecttype/objecttypeext.h index 82391b73..050711b1 100644 --- a/src/extensions/objecttype/objecttypeext.h +++ b/src/extensions/objecttype/objecttypeext.h @@ -27,33 +27,44 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "abstracttypeext.h" +#include "objecttype.h" -class ObjectTypeClass; -class CCINIClass; - - -class ObjectTypeClassExtension final : public Extension +class ObjectTypeClassExtension : public AbstractTypeClassExtension { public: - ObjectTypeClassExtension(ObjectTypeClass *this_ptr); - ObjectTypeClassExtension(const NoInitClass &noinit); - ~ObjectTypeClassExtension(); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; - virtual int Size_Of() const override; + public: + ObjectTypeClassExtension(const ObjectTypeClass *this_ptr); + ObjectTypeClassExtension(const NoInitClass &noinit); + virtual ~ObjectTypeClassExtension(); virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual const char *Name() const override { return reinterpret_cast(This())->Name(); } + virtual const char *Full_Name() const override { return reinterpret_cast(This())->Full_Name(); } - public: + virtual ObjectTypeClass *This() const override { return reinterpret_cast(AbstractTypeClassExtension::This()); } + virtual const ObjectTypeClass *This_Const() const override { return reinterpret_cast(AbstractTypeClassExtension::This_Const()); } -}; + virtual const char *Graphic_Name() const { return reinterpret_cast(This())->Graphic_Name(); } + virtual const char *Alpha_Graphic_Name() const { return reinterpret_cast(This())->Alpha_Graphic_Name(); } + + virtual bool Read_INI(CCINIClass &ini) override; + protected: + /** + * These are only to be accessed for save and load operations! + */ + char GraphicName[24 + 1]; + char AlphaGraphicName[24 + 1]; -extern ExtensionMap ObjectTypeClassExtensions; + public: +}; diff --git a/src/extensions/objecttype/objecttypeext_hooks.cpp b/src/extensions/objecttype/objecttypeext_hooks.cpp index 65ce0b36..312083c5 100644 --- a/src/extensions/objecttype/objecttypeext_hooks.cpp +++ b/src/extensions/objecttype/objecttypeext_hooks.cpp @@ -26,7 +26,6 @@ * ******************************************************************************/ #include "objecttypeext_hooks.h" -#include "objecttypeext_init.h" #include "objecttypeext.h" #include "objecttype.h" #include "theatertype.h" @@ -39,7 +38,9 @@ #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" -#include + +#include "hooker.h" +#include "hooker_macros.h" /** @@ -49,7 +50,7 @@ * @note: This must not contain a constructor or deconstructor! * @note: All functions must be prefixed with "_" to prevent accidental virtualization. */ -static class ObjectTypeClassFake final : public ObjectTypeClass +static class ObjectTypeClassExt final : public ObjectTypeClass { public: void _Assign_Theater_Name(char *buffer, TheaterType theater); @@ -62,7 +63,7 @@ static class ObjectTypeClassFake final : public ObjectTypeClass * * @author: CCHyper */ -void ObjectTypeClassFake::_Assign_Theater_Name(char *fname, TheaterType theater) +void ObjectTypeClassExt::_Assign_Theater_Name(char *fname, TheaterType theater) { /** * Make sure filename is uppercase. @@ -115,7 +116,6 @@ void ObjectTypeClassFake::_Assign_Theater_Name(char *fname, TheaterType theater) } else { DEV_DEBUG_WARNING("Failed to remap \"%s\" to current theater (%s)!\n", fname, TheaterTypeClass::Name_From(theater)); } - } } @@ -143,7 +143,7 @@ DECLARE_PATCH(_ObjectTypeClass_Load_Theater_Art_Assign_Theater_Name_Theater_Patc * * @author: CCHyper */ -const ShapeFileStruct * ObjectTypeClassFake::_Get_Image_Data() const +const ShapeFileStruct * ObjectTypeClassExt::_Get_Image_Data() const { if (Image == nullptr) { DEBUG_WARNING("Object %s has NULL image data!\n", Name()); @@ -158,12 +158,7 @@ const ShapeFileStruct * ObjectTypeClassFake::_Get_Image_Data() const */ void ObjectTypeClassExtension_Hooks() { - /** - * Initialises the extended class. - */ - ObjectTypeClassExtension_Init(); - - //Patch_Jump(0x004101A0, &ObjectTypeClassFake::_Get_Image_Data); - Patch_Jump(0x00588D00, &ObjectTypeClassFake::_Assign_Theater_Name); + //Patch_Jump(0x004101A0, &ObjectTypeClassExt::_Get_Image_Data); + Patch_Jump(0x00588D00, &ObjectTypeClassExt::_Assign_Theater_Name); Patch_Jump(0x0058891D, &_ObjectTypeClass_Load_Theater_Art_Assign_Theater_Name_Theater_Patch); } diff --git a/src/extensions/objecttype/objecttypeext_init.cpp b/src/extensions/objecttype/objecttypeext_init.cpp deleted file mode 100644 index 7ac8a8b9..00000000 --- a/src/extensions/objecttype/objecttypeext_init.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/******************************************************************************* -/* O P E N S O U R C E -- V I N I F E R A ** -/******************************************************************************* - * - * @project Vinifera - * - * @file OBJECTTYPEEXT_INIT.CPP - * - * @author CCHyper - * - * @brief Contains the hooks for initialising the extended ObjectTypeClass. - * - * @license Vinifera is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version - * 3 of the License, or (at your option) any later version. - * - * Vinifera is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. - * If not, see . - * - ******************************************************************************/ -#include "objecttypeext_hooks.h" -#include "objecttypeext.h" -#include "objecttype.h" -#include "tibsun_globals.h" -#include "vinifera_util.h" -#include "fatal.h" -#include "debughandler.h" -#include "asserthandler.h" - - -/** - * Patch for including the extended class members in the creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_ObjectTypeClass_Constructor_Patch) -{ - GET_REGISTER_STATIC(ObjectTypeClass *, this_ptr, ebp); // "this" pointer. - GET_STACK_STATIC(const char *, ini_name, esp, 0x30); // ini name. - static ObjectTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating ObjectTypeClassExtension instance for \"%s\".\n", ini_name); - - /** - * Find existing or create an extended class instance. - */ - exttype_ptr = ObjectTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create ObjectTypeClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create ObjectTypeClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create ObjectTypeClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. - } - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { add esp, 0x1C } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_ObjectTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(ObjectTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the destruction process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_ObjectTypeClass_Destructor_Patch) -{ - GET_REGISTER_STATIC(ObjectTypeClass *, this_ptr, esi); - - /** - * Remove the extended class from the global index. - */ - ObjectTypeClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop esi } - _asm { pop ebx } - _asm { pop ecx } - _asm { ret } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -#include "ccini.h" -DECLARE_PATCH(_ObjectTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(ObjectTypeClass *, this_ptr, ebx); - GET_STACK_STATIC(CCINIClass *, ini, esp, 0x1AC); // Can't use ESI as its been popped of the stack. - static ObjectTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = ObjectTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov al, 1 } - _asm { pop ebx } - _asm { add esp, 0x1A4 } - _asm { ret 4 } -} - - -/** - * Main function for patching the hooks. - */ -void ObjectTypeClassExtension_Init() -{ - Patch_Jump(0x005877FC, &_ObjectTypeClass_Constructor_Patch); - Patch_Jump(0x005878A7, &_ObjectTypeClass_NoInit_Constructor_Patch); - Patch_Jump(0x005879DA, &_ObjectTypeClass_Destructor_Patch); - Patch_Jump(0x00588CE2, &_ObjectTypeClass_Read_INI_Patch); -} diff --git a/src/extensions/options/optionsext.cpp b/src/extensions/options/optionsext.cpp index 79f12713..063aaf2b 100644 --- a/src/extensions/options/optionsext.cpp +++ b/src/extensions/options/optionsext.cpp @@ -36,22 +36,15 @@ #include "debughandler.h" -OptionsClassExtension *OptionsExtension = nullptr; - - /** * Class constructor. * * @author: CCHyper */ -OptionsClassExtension::OptionsClassExtension(OptionsClass *this_ptr) : - Extension(this_ptr) +OptionsClassExtension::OptionsClassExtension(const OptionsClass *this_ptr) : + GlobalExtensionClass(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("OptionsClassExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("OptionsClassExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - - IsInitialized = true; + //EXT_DEBUG_TRACE("OptionsClassExtension::OptionsClassExtension - 0x%08X\n", (uintptr_t)(This())); } @@ -61,9 +54,9 @@ OptionsClassExtension::OptionsClassExtension(OptionsClass *this_ptr) : * @author: CCHyper */ OptionsClassExtension::OptionsClassExtension(const NoInitClass &noinit) : - Extension(noinit) + GlobalExtensionClass(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("OptionsClassExtension::OptionsClassExtension(NoInitClass) - 0x%08X\n", (uintptr_t)(This())); } @@ -74,10 +67,45 @@ OptionsClassExtension::OptionsClassExtension(const NoInitClass &noinit) : */ OptionsClassExtension::~OptionsClassExtension() { - //EXT_DEBUG_TRACE("OptionsClassExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("OptionsClassExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("OptionsClassExtension::~OptionsClassExtension - 0x%08X\n", (uintptr_t)(This())); +} + + +/** + * Initializes an object from the stream where it was saved previously. + * + * @author: CCHyper + */ +HRESULT OptionsClassExtension::Load(IStream *pStm) +{ + //EXT_DEBUG_TRACE("OptionsClassExtension::Load - 0x%08X\n", (uintptr_t)(This())); + + HRESULT hr = GlobalExtensionClass::Load(pStm); + if (FAILED(hr)) { + return E_FAIL; + } + + new (this) OptionsClassExtension(NoInitClass()); + + return hr; +} + + +/** + * Saves an object to the specified stream. + * + * @author: CCHyper + */ +HRESULT OptionsClassExtension::Save(IStream *pStm, BOOL fClearDirty) +{ + //EXT_DEBUG_TRACE("OptionsClassExtension::Save - 0x%08X\n", (uintptr_t)(This())); + + HRESULT hr = GlobalExtensionClass::Save(pStm, fClearDirty); + if (FAILED(hr)) { + return hr; + } - IsInitialized = false; + return hr; } @@ -88,13 +116,34 @@ OptionsClassExtension::~OptionsClassExtension() */ int OptionsClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("OptionsClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("OptionsClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(This())); return sizeof(*this); } +/** + * Removes the specified target from any targeting and reference trackers. + * + * @author: CCHyper + */ +void OptionsClassExtension::Detach(TARGET target, bool all) +{ + //EXT_DEBUG_TRACE("OptionsClassExtension::Detach - 0x%08X\n", (uintptr_t)(This())); +} + + +/** + * Compute a unique crc value for this instance. + * + * @author: CCHyper + */ +void OptionsClassExtension::Compute_CRC(WWCRCEngine &crc) const +{ + //EXT_DEBUG_TRACE("OptionsClassExtension::Compute_CRC - 0x%08X\n", (uintptr_t)(This())); +} + + /** * Fetches the extension data from the INI database. * @@ -102,9 +151,7 @@ int OptionsClassExtension::Size_Of() const */ void OptionsClassExtension::Load_Settings() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("OptionsClassExtension::Load_Settings - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("OptionsClassExtension::Load_Settings - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("OptionsClassExtension::Load_Settings - 0x%08X\n", (uintptr_t)(This())); RawFileClass file("SUN.INI"); } @@ -117,9 +164,7 @@ void OptionsClassExtension::Load_Settings() */ void OptionsClassExtension::Load_Init_Settings() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("OptionsClassExtension::Load_Settings - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("OptionsClassExtension::Load_Settings - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("OptionsClassExtension::Load_Settings - 0x%08X\n", (uintptr_t)(This())); RawFileClass file("SUN.INI"); } @@ -132,9 +177,7 @@ void OptionsClassExtension::Load_Init_Settings() */ void OptionsClassExtension::Save_Settings() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("OptionsClassExtension::Save_Settings - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("OptionsClassExtension::Save_Settings - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("OptionsClassExtension::Save_Settings - 0x%08X\n", (uintptr_t)(This())); RawFileClass file("SUN.INI"); } @@ -147,8 +190,5 @@ void OptionsClassExtension::Save_Settings() */ void OptionsClassExtension::Set() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("OptionsClassExtension::Save_Settings - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("OptionsClassExtension::Save_Settings - 0x%08X\n", (uintptr_t)(ThisPtr)); - + //EXT_DEBUG_TRACE("OptionsClassExtension::Set - 0x%08X\n", (uintptr_t)(This())); } diff --git a/src/extensions/options/optionsext.h b/src/extensions/options/optionsext.h index f60c87b1..4a7f9610 100644 --- a/src/extensions/options/optionsext.h +++ b/src/extensions/options/optionsext.h @@ -27,27 +27,35 @@ ******************************************************************************/ #pragma once +#include "always.h" #include "extension.h" -#include "container.h" +#include "options.h" -class OptionsClass; class CCINIClass; -class OptionsClassExtension final : public Extension +class OptionsClassExtension final : public GlobalExtensionClass { public: - OptionsClassExtension(OptionsClass *this_ptr); + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + OptionsClassExtension(const OptionsClass *this_ptr); OptionsClassExtension(const NoInitClass &noinit); - ~OptionsClassExtension(); + virtual ~OptionsClassExtension(); - virtual HRESULT Load(IStream *pStm) override { return S_OK; } - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override { return S_OK; } + /** + * OptionsClass extension does not require these to be used, but we + * implement them for completeness. + */ virtual int Size_Of() const override; + virtual void Detach(TARGET target, bool all = true) override; + virtual void Compute_CRC(WWCRCEngine &crc) const override; - virtual void Detach(TARGET target, bool all = true) override {} - virtual void Compute_CRC(WWCRCEngine &crc) const override {} + virtual const char *Name() const override { return "Options"; } + virtual const char *Full_Name() const override { return "Options"; } void Load_Settings(); void Load_Init_Settings(); @@ -57,6 +65,3 @@ class OptionsClassExtension final : public Extension public: }; - - -extern OptionsClassExtension *OptionsExtension; diff --git a/src/extensions/options/optionsext_init.cpp b/src/extensions/options/optionsext_init.cpp index 91ed7ebf..4d96f097 100644 --- a/src/extensions/options/optionsext_init.cpp +++ b/src/extensions/options/optionsext_init.cpp @@ -27,39 +27,18 @@ ******************************************************************************/ #include "optionsext_hooks.h" #include "optionsext.h" +#include "tibsun_globals.h" #include "vinifera_util.h" +#include "extension.h" +#include "extension_globals.h" #include "options.h" #include "techno.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" - -/** - * "new" operations must be done within a new function for patched code. - * - * @author: CCHyper - */ -static void New_Options_Extension(OptionsClass *this_ptr) -{ - /** - * Delete existing instance (should never be the case). - */ - delete OptionsExtension; - - OptionsExtension = new OptionsClassExtension(this_ptr); -} - - -/** - * "delete" operations must be done within a new function for patched code. - * - * @author: CCHyper - */ -static void Delete_Options_Extension() -{ - delete OptionsExtension; -} +#include "hooker.h" +#include "hooker_macros.h" /** @@ -85,15 +64,7 @@ DECLARE_PATCH(_OptionsClass_Constructor_Patch) /** * Create the extended class instance. */ - New_Options_Extension(this_ptr); - if (!OptionsExtension) { - DEBUG_ERROR("Failed to create OptionsExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create OptionsExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create OptionsExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. - } + OptionsExtension = Extension::Singleton::Make(this_ptr); /** * Stolen bytes here. @@ -123,7 +94,8 @@ DECLARE_PATCH(_OptionsClass_Constructor_Patch) /** - * OptionsClass has no destructor! + * OptionsClass has no destructor to hook! See Vinifera shutdown for cleaning + * up the extension instance. */ #if 0 /** @@ -138,17 +110,9 @@ DECLARE_PATCH(_OptionsClass_Destructor_Patch) GET_REGISTER_STATIC(OptionsClass *, this_ptr, esi); /** - * Create the extended class instance. + * Remove the extended class instance. */ - New_Options_Extension(this_ptr); - if (!OptionsExtension) { - DEBUG_ERROR("Failed to create OptionsExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create OptionsExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create OptionsExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. - } + Extension::Singleton::Destroy(OptionsExtension); /** * Stolen bytes here. @@ -175,9 +139,7 @@ DECLARE_PATCH(_OptionsClass_Load_Settings_Patch) /** * Load ini. */ - if (OptionsExtension) { - OptionsExtension->Load_Settings(); - } + OptionsExtension->Load_Settings(); /** * Stolen bytes here. @@ -202,9 +164,7 @@ DECLARE_PATCH(_WinMain_Load_Init_Options_Settings_Patch) /** * Load ini. */ - if (OptionsExtension) { - OptionsExtension->Load_Init_Settings(); - } + OptionsExtension->Load_Init_Settings(); /** * Stolen bytes here. @@ -229,9 +189,7 @@ DECLARE_PATCH(_OptionsClass_Save_Settings_Patch) /** * Save ini. */ - if (OptionsExtension) { - OptionsExtension->Save_Settings(); - } + OptionsExtension->Save_Settings(); /** * Stolen bytes here. @@ -257,9 +215,7 @@ DECLARE_PATCH(_OptionsClass_Set_Patch) /** * Set options. */ - if (OptionsExtension) { - OptionsExtension->Set(); - } + OptionsExtension->Set(); /** * Stolen bytes here. diff --git a/src/extensions/overlaytype/overlaytypeext.cpp b/src/extensions/overlaytype/overlaytypeext.cpp index e3affbe8..bf231d0e 100644 --- a/src/extensions/overlaytype/overlaytypeext.cpp +++ b/src/extensions/overlaytype/overlaytypeext.cpp @@ -28,29 +28,22 @@ #include "overlaytypeext.h" #include "overlaytype.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all OverlayTypeClass extension instances. - */ -ExtensionMap OverlayTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -OverlayTypeClassExtension::OverlayTypeClassExtension(OverlayTypeClass *this_ptr) : - Extension(this_ptr) +OverlayTypeClassExtension::OverlayTypeClassExtension(const OverlayTypeClass *this_ptr) : + ObjectTypeClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("OverlayTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("OverlayTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("OverlayTypeClassExtension::OverlayTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + OverlayTypeExtensions.Add(this); } @@ -60,9 +53,9 @@ OverlayTypeClassExtension::OverlayTypeClassExtension(OverlayTypeClass *this_ptr) * @author: CCHyper */ OverlayTypeClassExtension::OverlayTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("OverlayTypeClassExtension::OverlayTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ OverlayTypeClassExtension::OverlayTypeClassExtension(const NoInitClass &noinit) */ OverlayTypeClassExtension::~OverlayTypeClassExtension() { - //EXT_DEBUG_TRACE("OverlayTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("OverlayTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("OverlayTypeClassExtension::~OverlayTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + OverlayTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT OverlayTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("OverlayTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -87,10 +98,9 @@ OverlayTypeClassExtension::~OverlayTypeClassExtension() */ HRESULT OverlayTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("OverlayTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("OverlayTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT OverlayTypeClassExtension::Load(IStream *pStm) */ HRESULT OverlayTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("OverlayTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("OverlayTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT OverlayTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int OverlayTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("OverlayTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("OverlayTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int OverlayTypeClassExtension::Size_Of() const */ void OverlayTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("OverlayTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("OverlayTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,8 +160,7 @@ void OverlayTypeClassExtension::Detach(TARGET target, bool all) */ void OverlayTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("OverlayTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("OverlayTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -165,11 +171,13 @@ void OverlayTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool OverlayTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("OverlayTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("OverlayTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("OverlayTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (!ObjectTypeClassExtension::Read_INI(ini)) { + return false; + } - const char *ini_name = ThisPtr->Name(); + const char *ini_name = Name(); if (!ini.Is_Present(ini_name)) { return false; diff --git a/src/extensions/overlaytype/overlaytypeext.h b/src/extensions/overlaytype/overlaytypeext.h index 41fb6999..949cd241 100644 --- a/src/extensions/overlaytype/overlaytypeext.h +++ b/src/extensions/overlaytype/overlaytypeext.h @@ -27,33 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "objecttypeext.h" +#include "overlaytype.h" -class OverlayTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_OVERLAYTYPE_EXTENSION) +OverlayTypeClassExtension final : public ObjectTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class OverlayTypeClassExtension final : public Extension -{ public: - OverlayTypeClassExtension(OverlayTypeClass *this_ptr); + OverlayTypeClassExtension(const OverlayTypeClass *this_ptr = nullptr); OverlayTypeClassExtension(const NoInitClass &noinit); - ~OverlayTypeClassExtension(); + virtual ~OverlayTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual bool Read_INI(CCINIClass &ini) override; - public: + virtual OverlayTypeClass *This() const override { return reinterpret_cast(ObjectTypeClassExtension::This()); } + virtual const OverlayTypeClass *This_Const() const override { return reinterpret_cast(ObjectTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_INFANTRYTYPE; } + public: }; - - -extern ExtensionMap OverlayTypeClassExtensions; diff --git a/src/extensions/overlaytype/overlaytypeext_hooks.cpp b/src/extensions/overlaytype/overlaytypeext_hooks.cpp index 1127dedf..59282662 100644 --- a/src/extensions/overlaytype/overlaytypeext_hooks.cpp +++ b/src/extensions/overlaytype/overlaytypeext_hooks.cpp @@ -33,6 +33,9 @@ #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patches in an assertion check for image data. diff --git a/src/extensions/overlaytype/overlaytypeext_init.cpp b/src/extensions/overlaytype/overlaytypeext_init.cpp index 459c8356..8a6ef8df 100644 --- a/src/extensions/overlaytype/overlaytypeext_init.cpp +++ b/src/extensions/overlaytype/overlaytypeext_init.cpp @@ -30,10 +30,15 @@ #include "overlaytype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,45 +51,19 @@ DECLARE_PATCH(_OverlayTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(OverlayTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0xC); // ini name. - static OverlayTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating OverlayTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = OverlayTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create OverlayTypeClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create OverlayTypeClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create OverlayTypeClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_OverlayTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(OverlayTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. @@ -92,6 +71,7 @@ DECLARE_PATCH(_OverlayTypeClass_NoInit_Constructor_Patch) original_code: _asm { mov eax, this_ptr } _asm { pop esi } + _asm { pop ebx } _asm { ret 4 } } @@ -110,15 +90,14 @@ DECLARE_PATCH(_OverlayTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - OverlayTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007E22A0 } // OverlayTypes.vtble + JMP_REG(eax, 0x0058D1A1); } @@ -136,95 +115,14 @@ DECLARE_PATCH(_OverlayTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - OverlayTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_OverlayTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(OverlayTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static OverlayTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = OverlayTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_OverlayTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(bool, is_a_rock, al); // Return from INIClass::Get_Bool() for "IsARock". - GET_REGISTER_STATIC(OverlayTypeClass *, this_ptr, esi); - GET_REGISTER_STATIC(CCINIClass *, ini, ebx); - static OverlayTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = OverlayTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); - - /** - * Stolen bytes here. - */ -original_code: - this_ptr->IsARock = is_a_rock; - - _asm { mov al, 1 } - _asm { pop edi } - _asm { pop ebp } - _asm { pop esi } - _asm { pop ebx } - _asm { add esp, 0x280 } - _asm { ret 4 } + _asm { mov edx, ds:0x007E22A0 } // OverlayTypes.vtble + JMP_REG(eax, 0x0058DC91); } @@ -235,9 +133,6 @@ void OverlayTypeClassExtension_Init() { Patch_Jump(0x0058D120, &_OverlayTypeClass_Constructor_Patch); Patch_Jump(0x0058D12D, &_OverlayTypeClass_Constructor_Patch); - Patch_Jump(0x0058D15A, &_OverlayTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x0058D1EB, &_OverlayTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x0058DCEB, &_OverlayTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x0058D7EA, &_OverlayTypeClass_Compute_CRC_Patch); - Patch_Jump(0x0058D709, &_OverlayTypeClass_Read_INI_Patch); + //Patch_Jump(0x0058D19B, &_OverlayTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x0058DC8B, &_OverlayTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/particlesystype/particlesystypeext.cpp b/src/extensions/particlesystype/particlesystypeext.cpp index ff402ac4..a0fc26a7 100644 --- a/src/extensions/particlesystype/particlesystypeext.cpp +++ b/src/extensions/particlesystype/particlesystypeext.cpp @@ -28,29 +28,22 @@ #include "particlesystypeext.h" #include "particlesystype.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all ParticleSystemTypeClass extension instances. - */ -ExtensionMap ParticleSystemTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -ParticleSystemTypeClassExtension::ParticleSystemTypeClassExtension(ParticleSystemTypeClass *this_ptr) : - Extension(this_ptr) +ParticleSystemTypeClassExtension::ParticleSystemTypeClassExtension(const ParticleSystemTypeClass *this_ptr) : + ObjectTypeClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("ParticleSystemTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::ParticleSystemTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + ParticleSystemTypeExtensions.Add(this); } @@ -60,9 +53,9 @@ ParticleSystemTypeClassExtension::ParticleSystemTypeClassExtension(ParticleSyste * @author: CCHyper */ ParticleSystemTypeClassExtension::ParticleSystemTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::ParticleSystemTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ ParticleSystemTypeClassExtension::ParticleSystemTypeClassExtension(const NoInitC */ ParticleSystemTypeClassExtension::~ParticleSystemTypeClassExtension() { - //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("ParticleSystemTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::~ParticleSystemTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + ParticleSystemTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT ParticleSystemTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -87,10 +98,9 @@ ParticleSystemTypeClassExtension::~ParticleSystemTypeClassExtension() */ HRESULT ParticleSystemTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT ParticleSystemTypeClassExtension::Load(IStream *pStm) */ HRESULT ParticleSystemTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT ParticleSystemTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int ParticleSystemTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int ParticleSystemTypeClassExtension::Size_Of() const */ void ParticleSystemTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,8 +160,7 @@ void ParticleSystemTypeClassExtension::Detach(TARGET target, bool all) */ void ParticleSystemTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -165,11 +171,13 @@ void ParticleSystemTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool ParticleSystemTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - DEV_DEBUG_WARNING("ParticleSystemTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleSystemTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (!ObjectTypeClassExtension::Read_INI(ini)) { + return false; + } - const char *ini_name = ThisPtr->Name(); + const char *ini_name = Name(); if (!ini.Is_Present(ini_name)) { return false; diff --git a/src/extensions/particlesystype/particlesystypeext.h b/src/extensions/particlesystype/particlesystypeext.h index 49e422e9..8150de4e 100644 --- a/src/extensions/particlesystype/particlesystypeext.h +++ b/src/extensions/particlesystype/particlesystypeext.h @@ -27,33 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "objecttypeext.h" +#include "particlesystype.h" -class ParticleSystemTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_PARTICLESYSTEMTYPE_EXTENSION) +ParticleSystemTypeClassExtension final : public ObjectTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class ParticleSystemTypeClassExtension final : public Extension -{ public: - ParticleSystemTypeClassExtension(ParticleSystemTypeClass *this_ptr); + ParticleSystemTypeClassExtension(const ParticleSystemTypeClass *this_ptr = nullptr); ParticleSystemTypeClassExtension(const NoInitClass &noinit); - ~ParticleSystemTypeClassExtension(); + virtual ~ParticleSystemTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual ParticleSystemTypeClass *This() const override { return reinterpret_cast(ObjectTypeClassExtension::This()); } + virtual const ParticleSystemTypeClass *This_Const() const override { return reinterpret_cast(ObjectTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_PARTICLESYSTEMTYPE; } - public: + virtual bool Read_INI(CCINIClass &ini) override; + public: }; - - -extern ExtensionMap ParticleSystemTypeClassExtensions; diff --git a/src/extensions/particlesystype/particlesystypeext_init.cpp b/src/extensions/particlesystype/particlesystypeext_init.cpp index e06ea897..a8dcef9a 100644 --- a/src/extensions/particlesystype/particlesystypeext_init.cpp +++ b/src/extensions/particlesystype/particlesystypeext_init.cpp @@ -30,10 +30,15 @@ #include "particlesystype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,45 +51,19 @@ DECLARE_PATCH(_ParticleSystemTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(ParticleSystemTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0xC); // ini name. - static ParticleSystemTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating ParticleSystemTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = ParticleSystemTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create ParticleSystemTypeClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create ParticleSystemTypeClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create ParticleSystemTypeClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_ParticleSystemTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(ParticleSystemTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. @@ -92,6 +71,7 @@ DECLARE_PATCH(_ParticleSystemTypeClass_NoInit_Constructor_Patch) original_code: _asm { mov eax, this_ptr } _asm { pop esi } + _asm { pop ebx } _asm { ret 4 } } @@ -110,15 +90,14 @@ DECLARE_PATCH(_ParticleSystemTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - ParticleSystemTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007E2288 } // ParticleSystemTypes.vtble + JMP_REG(eax, 0x005AE57E); } @@ -136,92 +115,14 @@ DECLARE_PATCH(_ParticleSystemTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - ParticleSystemTypeClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_ParticleSystemTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(ParticleSystemTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static ParticleSystemTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = ParticleSystemTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_ParticleSystemTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(ParticleSystemTypeClass *, this_ptr, esi); - GET_STACK_STATIC(CCINIClass *, ini, esp, 0x90); - static ParticleSystemTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = ParticleSystemTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov al, 1 } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { add esp, ebp } - _asm { pop ebp } - _asm { ret 4 } + _asm { mov edx, ds:0x007E2288 } // ParticleSystemTypes.vtble + JMP_REG(eax, 0x005AEC6E); } @@ -231,9 +132,6 @@ DECLARE_PATCH(_ParticleSystemTypeClass_Read_INI_Patch) void ParticleSystemTypeClassExtension_Init() { Patch_Jump(0x005AE537, &_ParticleSystemTypeClass_Constructor_Patch); - Patch_Jump(0x005AE55A, &_ParticleSystemTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x005AE5C8, &_ParticleSystemTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x005AECC8, &_ParticleSystemTypeClass_Scalar_Destructor_Patch); - //Patch_Jump(0x005AEA9A, &_ParticleSystemTypeClass_Compute_CRC_Patch); - //Patch_Jump(0x005AE90C, &_ParticleSystemTypeClass_Read_INI_Patch); + //Patch_Jump(0x005AE578, &_ParticleSystemTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x005AEC68, &_ParticleSystemTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/particletype/particletypeext.cpp b/src/extensions/particletype/particletypeext.cpp index bd7c9993..0fa1553e 100644 --- a/src/extensions/particletype/particletypeext.cpp +++ b/src/extensions/particletype/particletypeext.cpp @@ -28,29 +28,22 @@ #include "particletypeext.h" #include "particletype.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all ParticleTypeClass extension instances. - */ -ExtensionMap ParticleTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -ParticleTypeClassExtension::ParticleTypeClassExtension(ParticleTypeClass *this_ptr) : - Extension(this_ptr) +ParticleTypeClassExtension::ParticleTypeClassExtension(const ParticleTypeClass *this_ptr) : + ObjectTypeClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("ParticleTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("ParticleTypeClassExtension::ParticleTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + ParticleTypeExtensions.Add(this); } @@ -60,9 +53,9 @@ ParticleTypeClassExtension::ParticleTypeClassExtension(ParticleTypeClass *this_p * @author: CCHyper */ ParticleTypeClassExtension::ParticleTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("ParticleTypeClassExtension::ParticleTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ ParticleTypeClassExtension::ParticleTypeClassExtension(const NoInitClass &noinit */ ParticleTypeClassExtension::~ParticleTypeClassExtension() { - //EXT_DEBUG_TRACE("ParticleTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("ParticleTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleTypeClassExtension::~ParticleTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + ParticleTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT ParticleTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("ParticleTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -87,10 +98,9 @@ ParticleTypeClassExtension::~ParticleTypeClassExtension() */ HRESULT ParticleTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT ParticleTypeClassExtension::Load(IStream *pStm) */ HRESULT ParticleTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT ParticleTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int ParticleTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int ParticleTypeClassExtension::Size_Of() const */ void ParticleTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,8 +160,7 @@ void ParticleTypeClassExtension::Detach(TARGET target, bool all) */ void ParticleTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -165,11 +171,13 @@ void ParticleTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool ParticleTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ParticleTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("ParticleTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ParticleTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (!ObjectTypeClassExtension::Read_INI(ini)) { + return false; + } - const char *ini_name = ThisPtr->Name(); + const char *ini_name = Name(); if (!ini.Is_Present(ini_name)) { return false; diff --git a/src/extensions/particletype/particletypeext.h b/src/extensions/particletype/particletypeext.h index aa5a49f6..8e6cd82a 100644 --- a/src/extensions/particletype/particletypeext.h +++ b/src/extensions/particletype/particletypeext.h @@ -27,33 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "objecttypeext.h" +#include "particletype.h" -class ParticleTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_PARTICLETYPE_EXTENSION) +ParticleTypeClassExtension final : public ObjectTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class ParticleTypeClassExtension final : public Extension -{ public: - ParticleTypeClassExtension(ParticleTypeClass *this_ptr); + ParticleTypeClassExtension(const ParticleTypeClass *this_ptr = nullptr); ParticleTypeClassExtension(const NoInitClass &noinit); - ~ParticleTypeClassExtension(); + virtual ~ParticleTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual ParticleTypeClass *This() const override { return reinterpret_cast(ObjectTypeClassExtension::This()); } + virtual const ParticleTypeClass *This_Const() const override { return reinterpret_cast(ObjectTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_PARTICLETYPE; } - public: + virtual bool Read_INI(CCINIClass &ini) override; + public: }; - - -extern ExtensionMap ParticleTypeClassExtensions; diff --git a/src/extensions/particletype/particletypeext_init.cpp b/src/extensions/particletype/particletypeext_init.cpp index c2de5d75..1fc024a6 100644 --- a/src/extensions/particletype/particletypeext_init.cpp +++ b/src/extensions/particletype/particletypeext_init.cpp @@ -30,10 +30,15 @@ #include "particletype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,54 +51,29 @@ DECLARE_PATCH(_ParticleTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(ParticleTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0x14); // ini name. - static ParticleTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating ParticleTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = ParticleTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create ParticleTypeClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create ParticleTypeClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create ParticleTypeClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_ParticleTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(ParticleTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. */ original_code: _asm { mov eax, this_ptr } + _asm { pop edi } _asm { pop esi } + _asm { pop ebp } + _asm { pop ebx } _asm { ret 4 } } @@ -112,15 +92,14 @@ DECLARE_PATCH(_ParticleTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - ParticleTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007E22B8 } // ParticleTypes.vtble + JMP_REG(eax, 0x005AF1A7); } @@ -138,127 +117,14 @@ DECLARE_PATCH(_ParticleTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - ParticleTypeClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_ParticleTypeClass_Detach_Patch) -{ - GET_REGISTER_STATIC(ParticleTypeClass *, this_ptr, ecx); - GET_STACK_STATIC(TARGET, target, esp, 0x4); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static ParticleTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = ParticleTypeClassExtensions.find(this_ptr, false); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class detach. - */ - exttype_ptr->Detach(target, all); - - /** - * Stolen bytes here. - */ -original_code: - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_ParticleTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(ParticleTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static ParticleTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = ParticleTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_ParticleTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(ParticleTypeClass *, this_ptr, esi); - GET_STACK_STATIC(CCINIClass *, ini, esp, 0xE0); - static ParticleTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = ParticleTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { mov al, 1 } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { add esp, 0x0CC } - _asm { ret 4 } + _asm { mov edx, ds:0x007E22B8 } // ParticleTypes.vtble + JMP_REG(eax, 0x005AFC87); } @@ -268,10 +134,6 @@ DECLARE_PATCH(_ParticleTypeClass_Read_INI_Patch) void ParticleTypeClassExtension_Init() { Patch_Jump(0x005AF0CD, &_ParticleTypeClass_Constructor_Patch); - Patch_Jump(0x005AF12F, &_ParticleTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x005AF233, &_ParticleTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x005AFD23, &_ParticleTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x005AFB98, &_ParticleTypeClass_Detach_Patch); - Patch_Jump(0x005AF8F1, &_ParticleTypeClass_Compute_CRC_Patch); - Patch_Jump(0x005AF6EC, &_ParticleTypeClass_Read_INI_Patch); + //Patch_Jump(0x005AF1A1, &_ParticleTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x005AFC81, &_ParticleTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/rawfile/rawfileext_hooks.cpp b/src/extensions/rawfile/rawfileext_hooks.cpp index 20ea0a8d..f3c471ab 100644 --- a/src/extensions/rawfile/rawfileext_hooks.cpp +++ b/src/extensions/rawfile/rawfileext_hooks.cpp @@ -43,7 +43,7 @@ * @note: This must not contain a constructor or destructor! * @note: All functions must be prefixed with "_" to prevent accidental virtualization. */ -class RawFileClassFake final : public RawFileClass +class RawFileClassExt final : public RawFileClass { public: long _Read(void *buffer, int length); @@ -57,7 +57,7 @@ class RawFileClassFake final : public RawFileClass * @author: 10/18/1994 JLB - Red Alert source code. * CCHyper - Adjustments for Tiberian Sun, minor bug fix. */ -long RawFileClassFake::_Read(void *buffer, int length) +long RawFileClassExt::_Read(void *buffer, int length) { ASSERT_PRINT(buffer != nullptr, "Filename -> %s", Get_Safe_File_Name()); ASSERT_PRINT(length > 0, "Filename -> %s", Get_Safe_File_Name()); @@ -133,7 +133,7 @@ long RawFileClassFake::_Read(void *buffer, int length) * @author: 10/17/1994 JLB - Red Alert source code. * CCHyper - Adjustments for Tiberian Sun, minor bug fix. */ -void RawFileClassFake::_Error(FileErrorType error, bool can_retry, const char *filename) +void RawFileClassExt::_Error(FileErrorType error, bool can_retry, const char *filename) { static char buffer[2048]; @@ -173,6 +173,6 @@ void RawFileClassFake::_Error(FileErrorType error, bool can_retry, const char *f */ void RawFileClassExtension_Hooks() { - Patch_Jump(0x005BE560, &RawFileClassFake::_Read); - Patch_Jump(0x005BE300, &RawFileClassFake::_Error); + Patch_Jump(0x005BE560, &RawFileClassExt::_Read); + Patch_Jump(0x005BE300, &RawFileClassExt::_Error); } diff --git a/src/extensions/rules/rulesext.cpp b/src/extensions/rules/rulesext.cpp index f7f4617d..8d01fe9a 100644 --- a/src/extensions/rules/rulesext.cpp +++ b/src/extensions/rules/rulesext.cpp @@ -34,9 +34,33 @@ #include "housetype.h" #include "side.h" #include "wstring.h" +#include "wwcrc.h" +#include "noinit.h" +#include "swizzle.h" +#include "vinifera_saveload.h" #include "asserthandler.h" #include "debughandler.h" +#include "housetypeext.h" +#include "supertypeext.h" +#include "animtypeext.h" +#include "buildingtypeext.h" +#include "aircrafttypeext.h" +#include "unittypeext.h" +#include "infantrytypeext.h" +#include "weapontypeext.h" +#include "bullettypeext.h" +#include "warheadtypeext.h" +#include "terraintypeext.h" +#include "smudgetypeext.h" +#include "overlaytypeext.h" +#include "particletypeext.h" +#include "particlesystypeext.h" +#include "voxelanimtypeext.h" + +#include "extension.h" +#include "extension_globals.h" + RulesClassExtension *RulesExtension = nullptr; @@ -46,18 +70,14 @@ RulesClassExtension *RulesExtension = nullptr; * * @author: CCHyper */ -RulesClassExtension::RulesClassExtension(RulesClass *this_ptr) : - Extension(this_ptr), +RulesClassExtension::RulesClassExtension(const RulesClass *this_ptr) : + GlobalExtensionClass(this_ptr), IsMPAutoDeployMCV(false), IsMPPrePlacedConYards(false), IsBuildOffAlly(true), IsShowSuperWeaponTimers(true) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("RulesClassExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("RulesClassExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - - IsInitialized = true; + //if (this_ptr) EXT_DEBUG_TRACE("RulesClassExtension::RulesClassExtension - 0x%08X\n", (uintptr_t)(ThisPtr)); } @@ -67,9 +87,9 @@ RulesClassExtension::RulesClassExtension(RulesClass *this_ptr) : * @author: CCHyper */ RulesClassExtension::RulesClassExtension(const NoInitClass &noinit) : - Extension(noinit) + GlobalExtensionClass(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("RulesClassExtension::RulesClassExtension(NoInitClass) - 0x%08X\n", (uintptr_t)(ThisPtr)); } @@ -80,52 +100,27 @@ RulesClassExtension::RulesClassExtension(const NoInitClass &noinit) : */ RulesClassExtension::~RulesClassExtension() { - //EXT_DEBUG_TRACE("RulesClassExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("RulesClassExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - - IsInitialized = false; + //EXT_DEBUG_TRACE("RulesClassExtension::~RulesClassExtension - 0x%08X\n", (uintptr_t)(ThisPtr)); } /** * Initializes an object from the stream where it was saved previously. - * - * As RulesClassExtension is static data, we do not need to request - * pointer remap of "ThisPtr" after loading has finished. * * @author: CCHyper */ HRESULT RulesClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("RulesClassExtension::Load - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("RulesClassExtension::Load - 0x%08X\n", (uintptr_t)(This())); - HRESULT hr = ExtensionBase::Load(pStm); - if (FAILED(hr)) { - return E_FAIL; - } - - LONG id; - hr = pStm->Read(&id, sizeof(id), nullptr); - if (FAILED(hr)) { - return E_FAIL; - } - - ULONG size = Size_Of(); - hr = pStm->Read(this, size, nullptr); + HRESULT hr = GlobalExtensionClass::Load(pStm); if (FAILED(hr)) { return E_FAIL; } new (this) RulesClassExtension(NoInitClass()); - - SWIZZLE_REGISTER_POINTER(id, this); - -#ifndef NDEBUG - EXT_DEBUG_INFO("RulesExt Load: ID 0x%08X Ptr 0x%08X\n", id, this); -#endif - - return S_OK; + + return hr; } @@ -136,10 +131,9 @@ HRESULT RulesClassExtension::Load(IStream *pStm) */ HRESULT RulesClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("RulesClassExtension::Save - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("RulesClassExtension::Save - 0x%08X\n", (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = GlobalExtensionClass::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -155,8 +149,7 @@ HRESULT RulesClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int RulesClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("RulesClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("RulesClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(This())); return sizeof(*this); } @@ -169,9 +162,7 @@ int RulesClassExtension::Size_Of() const */ void RulesClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("RulesClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(ThisPtr)); - + //EXT_DEBUG_TRACE("RulesClassExtension::Detach - 0x%08X\n", (uintptr_t)(This())); } @@ -182,8 +173,7 @@ void RulesClassExtension::Detach(TARGET target, bool all) */ void RulesClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("RulesClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("RulesClassExtension::Compute_CRC - 0x%08X\n", (uintptr_t)(This())); crc(IsMPAutoDeployMCV); crc(IsMPPrePlacedConYards); @@ -199,18 +189,17 @@ void RulesClassExtension::Compute_CRC(WWCRCEngine &crc) const */ void RulesClassExtension::Process(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("RulesClassExtension::Process - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("RulesClassExtension::Process - 0x%08X\n", (uintptr_t)(This())); /** * This function replaces the original rules process, so we need to duplicate * the its behaviour here first. */ - ThisPtr->Colors(ini); - ThisPtr->Houses(ini); - ThisPtr->Sides(ini); - ThisPtr->Overlays(ini); + This()->Colors(ini); + This()->Houses(ini); + This()->Sides(ini); + This()->Overlays(ini); /** * #issue-117 @@ -222,25 +211,25 @@ void RulesClassExtension::Process(CCINIClass &ini) */ Weapons(ini); - ThisPtr->SuperWeapons(ini); - ThisPtr->Warheads(ini); - ThisPtr->Smudges(ini); - ThisPtr->Terrains(ini); - ThisPtr->Buildings(ini); - ThisPtr->Vehicles(ini); - ThisPtr->Aircraft(ini); - ThisPtr->Infantry(ini); - ThisPtr->Animations(ini); - ThisPtr->VoxelAnims(ini); - ThisPtr->Particles(ini); - ThisPtr->ParticleSystems(ini); - ThisPtr->JumpjetControls(ini); - ThisPtr->MPlayer(ini); - ThisPtr->AI(ini); - ThisPtr->Powerups(ini); - ThisPtr->Land_Types(ini); - ThisPtr->IQ(ini); - ThisPtr->General(ini); + This()->SuperWeapons(ini); + This()->Warheads(ini); + This()->Smudges(ini); + This()->Terrains(ini); + This()->Buildings(ini); + This()->Vehicles(ini); + This()->Aircraft(ini); + This()->Infantry(ini); + This()->Animations(ini); + This()->VoxelAnims(ini); + This()->Particles(ini); + This()->ParticleSystems(ini); + This()->JumpjetControls(ini); + This()->MPlayer(ini); + This()->AI(ini); + This()->Powerups(ini); + This()->Land_Types(ini); + This()->IQ(ini); + This()->General(ini); /** * This is a edge case issue we exposed in the original RULES.INI where the @@ -257,12 +246,12 @@ void RulesClassExtension::Process(CCINIClass &ini) } } - ThisPtr->Objects(ini); - ThisPtr->Difficulty(ini); - ThisPtr->CrateRules(ini); - ThisPtr->CombatDamage(ini); - ThisPtr->AudioVisual(ini); - ThisPtr->SpecialWeapons(ini); + This()->Objects(ini); + This()->Difficulty(ini); + This()->CrateRules(ini); + This()->CombatDamage(ini); + This()->AudioVisual(ini); + This()->SpecialWeapons(ini); TiberiumClass::Process(ini); /** @@ -274,6 +263,11 @@ void RulesClassExtension::Process(CCINIClass &ini) MPlayer(ini); AudioVisual(ini); + /** + * Process the objects (extension classes). + */ + Objects(ini); + /** * Run some checks to ensure certain values are as expected. */ @@ -293,9 +287,105 @@ void RulesClassExtension::Process(CCINIClass &ini) */ void RulesClassExtension::Initialize(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("RulesClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("RulesClassExtension::Initialize - 0x%08X\n", (uintptr_t)(This())); + +} + + +/** + * Fetch all the object characteristic values. + * + * @author: CCHyper + */ +bool RulesClassExtension::Objects(CCINIClass &ini) +{ + //EXT_DEBUG_TRACE("RulesClassExtension::Objects - 0x%08X\n", (uintptr_t)(This())); + + /** + * Fetch the game object (extension) values from the rules file. + */ + DEBUG_INFO("Rules: Processing HouseTypeExtensions (Count: %d)...\n", HouseTypeExtensions.Count()); + for (int index = 0; index < HouseTypeExtensions.Count(); ++index) { + HouseTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing SuperWeaponTypeExtensions (Count: %d)...\n", SuperWeaponTypeExtensions.Count()); + for (int index = 0; index < SuperWeaponTypeExtensions.Count(); ++index) { + SuperWeaponTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing AnimTypeExtensions (Count: %d)...\n", AnimTypeExtensions.Count()); + for (int index = 0; index < AnimTypeExtensions.Count(); ++index) { + AnimTypeExtensions[index]->Read_INI(ArtINI); // Animations are loaded explicitly from the ArtINI. + } + + DEBUG_INFO("Rules: Processing BuildingTypeExtensions (Count: %d)...\n", BuildingTypeExtensions.Count()); + for (int index = 0; index < BuildingTypeExtensions.Count(); ++index) { + BuildingTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing AircraftTypeExtensions (Count: %d)...\n", AircraftTypeExtensions.Count()); + for (int index = 0; index < AircraftTypeExtensions.Count(); ++index) { + AircraftTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing UnitTypeExtensions (Count: %d)...\n", UnitTypeExtensions.Count()); + for (int index = 0; index < UnitTypeExtensions.Count(); ++index) { + UnitTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing InfantryTypeExtensions (Count: %d)...\n", InfantryTypeExtensions.Count()); + for (int index = 0; index < InfantryTypeExtensions.Count(); ++index) { + InfantryTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing WeaponTypeExtensions (Count: %d)...\n", WeaponTypeExtensions.Count()); + for (int index = 0; index < WeaponTypeExtensions.Count(); ++index) { + WeaponTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing BulletTypeExtensions (Count: %d)...\n", BulletTypeExtensions.Count()); + for (int index = 0; index < BulletTypeExtensions.Count(); ++index) { + BulletTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing WarheadTypeExtensions (Count: %d)...\n", WarheadTypeExtensions.Count()); + for (int index = 0; index < WarheadTypeExtensions.Count(); ++index) { + WarheadTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing TerrainTypeExtensions (Count: %d)...\n", TerrainTypeExtensions.Count()); + for (int index = 0; index < TerrainTypeExtensions.Count(); ++index) { + TerrainTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing SmudgeTypeExtensions (Count: %d)...\n", SmudgeTypeExtensions.Count()); + for (int index = 0; index < SmudgeTypeExtensions.Count(); ++index) { + SmudgeTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing OverlayTypeExtensions (Count: %d)...\n", OverlayTypeExtensions.Count()); + for (int index = 0; index < OverlayTypeExtensions.Count(); ++index) { + OverlayTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing ParticleTypeExtensions (Count: %d)...\n", ParticleTypeExtensions.Count()); + for (int index = 0; index < ParticleTypeExtensions.Count(); ++index) { + ParticleTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing ParticleSystemTypeExtensions (Count: %d)...\n", ParticleSystemTypeExtensions.Count()); + for (int index = 0; index < ParticleSystemTypeExtensions.Count(); ++index) { + ParticleSystemTypeExtensions[index]->Read_INI(ini); + } + + DEBUG_INFO("Rules: Processing VoxelAnimTypeExtensions (Count: %d)...\n", VoxelAnimTypeExtensions.Count()); + for (int index = 0; index < VoxelAnimTypeExtensions.Count(); ++index) { + VoxelAnimTypeExtensions[index]->Read_INI(ini); + } + + return true; } @@ -306,8 +396,7 @@ void RulesClassExtension::Initialize(CCINIClass &ini) */ bool RulesClassExtension::General(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("RulesClassExtension::General - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("RulesClassExtension::General - 0x%08X\n", (uintptr_t)(This())); static char const * const GENERAL = "General"; @@ -326,8 +415,7 @@ bool RulesClassExtension::General(CCINIClass &ini) */ bool RulesClassExtension::AudioVisual(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("RulesClassExtension::General - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("RulesClassExtension::General - 0x%08X\n", (uintptr_t)(This())); static char const * const AUDIOVISUAL = "AudioVisual"; @@ -348,8 +436,7 @@ bool RulesClassExtension::AudioVisual(CCINIClass &ini) */ bool RulesClassExtension::MPlayer(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("RulesClassExtension::MPlayer - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("RulesClassExtension::MPlayer - 0x%08X\n", (uintptr_t)(This())); static char const * const MPLAYER = "MultiplayerDefaults"; @@ -372,8 +459,7 @@ bool RulesClassExtension::MPlayer(CCINIClass &ini) */ bool RulesClassExtension::Weapons(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("RulesClassExtension::Weapons - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("RulesClassExtension::Weapons - 0x%08X\n", (uintptr_t)(This())); static const char * const WEAPONS = "Weapons"; @@ -414,7 +500,7 @@ bool RulesClassExtension::Weapons(CCINIClass &ini) */ void RulesClassExtension::Check() { - ASSERT_PRINT(ThisPtr->CreditTicks.Count() == 2, "CreditTicks must contain 2 valid entries!"); + ASSERT_PRINT(This()->CreditTicks.Count() == 2, "CreditTicks must contain 2 valid entries!"); } diff --git a/src/extensions/rules/rulesext.h b/src/extensions/rules/rulesext.h index 9f3b4e68..d8c32ba2 100644 --- a/src/extensions/rules/rulesext.h +++ b/src/extensions/rules/rulesext.h @@ -27,34 +27,39 @@ ******************************************************************************/ #pragma once +#include "always.h" +#include "tibsun_defines.h" +#include "rules.h" #include "extension.h" -#include "container.h" - -#include "noinit.h" #include "tpoint.h" class CCINIClass; -class RulesClass; -class RulesClassExtension final : public Extension +class RulesClassExtension final : public GlobalExtensionClass { public: - RulesClassExtension(RulesClass *this_ptr); + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + RulesClassExtension(const RulesClass *this_ptr); RulesClassExtension(const NoInitClass &noinit); - ~RulesClassExtension(); + virtual ~RulesClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + virtual const char *Name() const override { return "Rule"; } + virtual const char *Full_Name() const override { return "Rule"; } + void Process(CCINIClass &ini); void Initialize(CCINIClass &ini); + bool Objects(CCINIClass &ini); + bool General(CCINIClass &ini); bool MPlayer(CCINIClass &ini); bool AudioVisual(CCINIClass &ini); @@ -86,9 +91,3 @@ class RulesClassExtension final : public Extension */ bool IsShowSuperWeaponTimers; }; - - -/** - * Global instance of the extended class. - */ -extern RulesClassExtension *RulesExtension; diff --git a/src/extensions/rules/rulesext_hooks.cpp b/src/extensions/rules/rulesext_hooks.cpp index d8f71cb5..fdcbc79a 100644 --- a/src/extensions/rules/rulesext_hooks.cpp +++ b/src/extensions/rules/rulesext_hooks.cpp @@ -37,6 +37,7 @@ #include "addon.h" #include "wwmouse.h" #include "windialog.h" +#include "extension_globals.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" @@ -56,7 +57,7 @@ extern HMODULE DLLInstance; * @note: This must not contain a constructor or destructor! * @note: All functions must be prefixed with "_" to prevent accidental virtualization. */ -class RulesClassFake final : public RulesClass +class RulesClassExt final : public RulesClass { public: void _Process(CCINIClass &ini); @@ -68,18 +69,14 @@ class RulesClassFake final : public RulesClass * * @author: CCHyper */ -void RulesClassFake::_Process(CCINIClass &ini) +void RulesClassExt::_Process(CCINIClass &ini) { /** * Process the rules extension. * * #NOTE: This must be last! */ - if (RulesExtension) { - RulesExtension->Process(ini); - } else { - Process(ini); - } + RuleExtension->Process(ini); } @@ -193,11 +190,9 @@ DECLARE_PATCH(_Init_Rules_Extended_Class_Patch) /** * Store extended class values. */ - if (SessionExtension && RulesExtension) { - SessionExtension->ExtOptions.IsAutoDeployMCV = RulesExtension->IsMPAutoDeployMCV; - SessionExtension->ExtOptions.IsPrePlacedConYards = RulesExtension->IsMPPrePlacedConYards; - SessionExtension->ExtOptions.IsBuildOffAlly = RulesExtension->IsBuildOffAlly; - } + SessionExtension->ExtOptions.IsAutoDeployMCV = RuleExtension->IsMPAutoDeployMCV; + SessionExtension->ExtOptions.IsPrePlacedConYards = RuleExtension->IsMPPrePlacedConYards; + SessionExtension->ExtOptions.IsBuildOffAlly = RuleExtension->IsBuildOffAlly; /** * Stolen bytes/code. @@ -219,7 +214,7 @@ void RulesClassExtension_Hooks() */ RulesClassExtension_Init(); - Patch_Jump(0x005C6710, &RulesClassFake::_Process); + Patch_Jump(0x005C6710, &RulesClassExt::_Process); Patch_Jump(0x004E138B, &_Init_Rules_Extended_Class_Patch); Patch_Jump(0x004E12EB, &_Init_Rules_Show_Rules_Select_Dialog_Patch); diff --git a/src/extensions/rules/rulesext_init.cpp b/src/extensions/rules/rulesext_init.cpp index 27b6a6f4..7df97ea2 100644 --- a/src/extensions/rules/rulesext_init.cpp +++ b/src/extensions/rules/rulesext_init.cpp @@ -30,36 +30,14 @@ #include "rules.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "extension.h" +#include "extension_globals.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" - -/** - * "new" operations must be done within a new function for patched code. - * - * @author: CCHyper - */ -static void New_Rules_Extension(RulesClass *this_ptr) -{ - /** - * Delete existing instance (should never be the case). - */ - delete RulesExtension; - - RulesExtension = new RulesClassExtension(this_ptr); -} - - -/** - * "delete" operations must be done within a new function for patched code. - * - * @author: CCHyper - */ -static void Delete_Rules_Extension() -{ - delete RulesExtension; -} +#include "hooker.h" +#include "hooker_macros.h" /** @@ -76,15 +54,7 @@ DECLARE_PATCH(_RulesClass_Constructor_Patch) /** * Create the extended class instance. */ - New_Rules_Extension(this_ptr); - if (!RulesExtension) { - DEBUG_ERROR("Failed to create RulesExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create RulesExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create RulesExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. - } + RuleExtension = Extension::Singleton::Make(this_ptr); /** * Stolen bytes here. @@ -99,42 +69,6 @@ DECLARE_PATCH(_RulesClass_Constructor_Patch) } -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_RulesClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(RulesClass *, this_ptr, esi); // "this" pointer. - GET_STACK_STATIC(const NoInitClass *, noinit, esp, 0x4); - - /** - * Create the extended class instance. - */ - New_Rules_Extension(this_ptr); - if (!RulesExtension) { - DEBUG_ERROR("Failed to create RulesExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create RulesExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create RulesExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. - } - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - /** * Patch for including the extended class members in the destruction process. * @@ -149,7 +83,7 @@ DECLARE_PATCH(_RulesClass_Destructor_Patch) /** * Remove the extended class instance. */ - Delete_Rules_Extension(); + Extension::Singleton::Destroy(RuleExtension); /** * Stolen bytes here. @@ -175,14 +109,7 @@ DECLARE_PATCH(_RulesClass_Initialize_Patch) GET_STACK_STATIC(RulesClass *, this_ptr, esp, 0x10); GET_STACK_STATIC(CCINIClass *, ini, esp, 0x44); - /** - * Find the extension instance. - */ - if (!RulesExtension) { - goto original_code; - } - - RulesExtension->Initialize(*ini); + RuleExtension->Initialize(*ini); /** * Stolen bytes here. @@ -209,14 +136,7 @@ DECLARE_PATCH(_RulesClass_Process_Patch) GET_REGISTER_STATIC(RulesClass *, this_ptr, ebp); GET_REGISTER_STATIC(CCINIClass *, ini, esi); - /** - * Find the extension instance. - */ - if (!RulesExtension) { - goto original_code; - } - - RulesExtension->Process(*ini); + RuleExtension->Process(*ini); /** * Stolen bytes here. @@ -231,39 +151,6 @@ DECLARE_PATCH(_RulesClass_Process_Patch) } -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_RulesClass_Detach_Patch) -{ - GET_REGISTER_STATIC(RulesClass *, this_ptr, esi); - GET_STACK_STATIC(TARGET, target, esp, 0x4); - GET_STACK_STATIC8(bool, all, esp, 0x8); - - /** - * Find the extension instance. - */ - if (!RulesExtension) { - goto original_code; - } - - RulesExtension->Detach(target, all); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 8 } -} - - /** * Patch for including the extended class members when processing the MPlayer section. * @@ -276,14 +163,7 @@ DECLARE_PATCH(_RulesClass_MPlayer_Patch) GET_REGISTER_STATIC(RulesClass *, this_ptr, esi); GET_REGISTER_STATIC(CCINIClass *, ini, edi); - /** - * Find the extension instance. - */ - if (!RulesExtension) { - goto original_code; - } - - RulesExtension->MPlayer(*ini); + RuleExtension->MPlayer(*ini); /** * Stolen bytes here. @@ -302,10 +182,8 @@ DECLARE_PATCH(_RulesClass_MPlayer_Patch) void RulesClassExtension_Init() { Patch_Jump(0x005C59A1, &_RulesClass_Constructor_Patch); - Patch_Jump(0x005C4347, &_RulesClass_NoInit_Constructor_Patch); Patch_Jump(0x005C6120, &_RulesClass_Destructor_Patch); Patch_Jump(0x005C66FF, &_RulesClass_Initialize_Patch); Patch_Jump(0x005C6A4D, &_RulesClass_Process_Patch); - Patch_Jump(0x005D17F5, &_RulesClass_Detach_Patch); Patch_Jump(0x005CC3BF, &_RulesClass_MPlayer_Patch); } diff --git a/src/extensions/scenario/scenarioext.cpp b/src/extensions/scenario/scenarioext.cpp index 6ebab7b6..bcf5f38e 100644 --- a/src/extensions/scenario/scenarioext.cpp +++ b/src/extensions/scenario/scenarioext.cpp @@ -26,31 +26,29 @@ * ******************************************************************************/ #include "scenarioext.h" +#include "tibsun_globals.h" +#include "tibsun_defines.h" +#include "noinit.h" +#include "swizzle.h" +#include "vinifera_saveload.h" #include "asserthandler.h" #include "debughandler.h" -ScenarioClassExtension *ScenarioExtension = nullptr; - - /** * Class constructor. * * @author: CCHyper */ -ScenarioClassExtension::ScenarioClassExtension(ScenarioClass *this_ptr) : - Extension(this_ptr) +ScenarioClassExtension::ScenarioClassExtension(const ScenarioClass *this_ptr) : + GlobalExtensionClass(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ScenarioClassExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("ScenarioClassExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("ScenarioClassExtension::ScenarioClassExtension - 0x%08X\n", (uintptr_t)(ThisPtr)); /** * This copies the behavior of the games ScenarioClass. */ Init_Clear(); - - IsInitialized = true; } @@ -60,9 +58,9 @@ ScenarioClassExtension::ScenarioClassExtension(ScenarioClass *this_ptr) : * @author: CCHyper */ ScenarioClassExtension::ScenarioClassExtension(const NoInitClass &noinit) : - Extension(noinit) + GlobalExtensionClass(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("ScenarioClassExtension::ScenarioClassExtension(NoInitClass) - 0x%08X\n", (uintptr_t)(ThisPtr)); } @@ -73,52 +71,27 @@ ScenarioClassExtension::ScenarioClassExtension(const NoInitClass &noinit) : */ ScenarioClassExtension::~ScenarioClassExtension() { - //EXT_DEBUG_TRACE("ScenarioClassExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("ScenarioClassExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - - IsInitialized = false; + //EXT_DEBUG_TRACE("ScenarioClassExtension::~ScenarioClassExtension - 0x%08X\n", (uintptr_t)(ThisPtr)); } /** * Initializes an object from the stream where it was saved previously. - * - * As ScenarioClassExtension is static data, we do not need to request - * pointer remap of "ThisPtr" after loading has finished. * * @author: CCHyper */ HRESULT ScenarioClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ScenarioClassExtension::Load - 0x%08X\n", (uintptr_t)(ThisPtr)); - - HRESULT hr = ExtensionBase::Load(pStm); - if (FAILED(hr)) { - return E_FAIL; - } - - LONG id; - hr = pStm->Read(&id, sizeof(id), nullptr); - if (FAILED(hr)) { - return E_FAIL; - } + //EXT_DEBUG_TRACE("ScenarioClassExtension::Load - 0x%08X\n", (uintptr_t)(This())); - ULONG size = Size_Of(); - hr = pStm->Read(this, size, nullptr); + HRESULT hr = GlobalExtensionClass::Load(pStm); if (FAILED(hr)) { return E_FAIL; } new (this) ScenarioClassExtension(NoInitClass()); - - SWIZZLE_REGISTER_POINTER(id, this); - -#ifndef NDEBUG - EXT_DEBUG_INFO("ScenarioExt Load: ID 0x%08X Ptr 0x%08X\n", id, this); -#endif - - return S_OK; + + return hr; } @@ -129,10 +102,9 @@ HRESULT ScenarioClassExtension::Load(IStream *pStm) */ HRESULT ScenarioClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ScenarioClassExtension::Save - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ScenarioClassExtension::Save - 0x%08X\n", (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = GlobalExtensionClass::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -148,8 +120,7 @@ HRESULT ScenarioClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int ScenarioClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ScenarioClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ScenarioClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(This())); return sizeof(*this); } @@ -162,9 +133,7 @@ int ScenarioClassExtension::Size_Of() const */ void ScenarioClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ScenarioClassExtension::Detach - 0x%08X\n", (uintptr_t)(ThisPtr)); - + //EXT_DEBUG_TRACE("ScenarioClassExtension::Detach - 0x%08X\n", (uintptr_t)(This())); } @@ -175,9 +144,7 @@ void ScenarioClassExtension::Detach(TARGET target, bool all) */ void ScenarioClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ScenarioClassExtension::Compute_CRC - 0x%08X\n", (uintptr_t)(ThisPtr)); - + //EXT_DEBUG_TRACE("ScenarioClassExtension::Compute_CRC - 0x%08X\n", (uintptr_t)(This())); } @@ -188,7 +155,5 @@ void ScenarioClassExtension::Compute_CRC(WWCRCEngine &crc) const */ void ScenarioClassExtension::Init_Clear() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ScenarioClassExtension::Init - 0x%08X\n", (uintptr_t)(ThisPtr)); - + //EXT_DEBUG_TRACE("ScenarioClassExtension::Init_Clear - 0x%08X\n", (uintptr_t)(This())); } diff --git a/src/extensions/scenario/scenarioext.h b/src/extensions/scenario/scenarioext.h index 4959eca5..67af04b0 100644 --- a/src/extensions/scenario/scenarioext.h +++ b/src/extensions/scenario/scenarioext.h @@ -27,37 +27,31 @@ ******************************************************************************/ #pragma once +#include "always.h" #include "extension.h" -#include "container.h" +#include "scenario.h" -#include "noinit.h" - -class ScenarioClass; - - -class ScenarioClassExtension final : public Extension +class ScenarioClassExtension final : public GlobalExtensionClass { public: - ScenarioClassExtension(ScenarioClass *this_ptr); + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + ScenarioClassExtension(const ScenarioClass *this_ptr); ScenarioClassExtension(const NoInitClass &noinit); - ~ScenarioClassExtension(); + virtual ~ScenarioClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + virtual const char *Name() const override { return "Scenario"; } + virtual const char *Full_Name() const override { return "Scenario"; } + void Init_Clear(); public: }; - - -/** - * Global instance of the extended class. - */ -extern ScenarioClassExtension *ScenarioExtension; diff --git a/src/extensions/scenario/scenarioext_functions.cpp b/src/extensions/scenario/scenarioext_functions.cpp index 7f2694cb..b69a4e34 100644 --- a/src/extensions/scenario/scenarioext_functions.cpp +++ b/src/extensions/scenario/scenarioext_functions.cpp @@ -44,6 +44,7 @@ #include "building.h" #include "buildingtype.h" #include "language.h" +#include "extension_globals.h" #include "sessionext.h" #include "session.h" #include "fatal.h" @@ -843,7 +844,7 @@ void Vinifera_Create_Units(bool official) * * @author: CCHyper */ - if (SessionExtension && SessionExtension->ExtOptions.IsPrePlacedConYards) { + if (SessionExtension->ExtOptions.IsPrePlacedConYards) { /** * Create a construction yard (decided from the base unit). @@ -922,7 +923,7 @@ void Vinifera_Create_Units(bool official) * @author: CCHyper */ if (Session.Options.UnitCount == 1) { - if (SessionExtension && SessionExtension->ExtOptions.IsAutoDeployMCV) { + if (SessionExtension->ExtOptions.IsAutoDeployMCV) { if (hptr->Is_Human_Control()) { obj->Set_Mission(MISSION_UNLOAD); } diff --git a/src/extensions/scenario/scenarioext_init.cpp b/src/extensions/scenario/scenarioext_init.cpp index 380069cd..80868ca6 100644 --- a/src/extensions/scenario/scenarioext_init.cpp +++ b/src/extensions/scenario/scenarioext_init.cpp @@ -30,36 +30,14 @@ #include "scenario.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "extension.h" +#include "extension_globals.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" - -/** - * "new" operations must be done within a new function for patched code. - * - * @author: CCHyper - */ -static void New_Scenario_Extension(ScenarioClass *this_ptr) -{ - /** - * Delete existing instance (should never be the case). - */ - delete ScenarioExtension; - - ScenarioExtension = new ScenarioClassExtension(this_ptr); -} - - -/** - * "delete" operations must be done within a new function for patched code. - * - * @author: CCHyper - */ -static void Delete_Scenario_Extension() -{ - delete ScenarioExtension; -} +#include "hooker.h" +#include "hooker_macros.h" /** @@ -76,15 +54,7 @@ DECLARE_PATCH(_ScenarioClass_Constructor_Patch) /** * Create the extended class instance. */ - New_Scenario_Extension(this_ptr); - if (!ScenarioExtension) { - DEBUG_ERROR("Failed to create ScenarioExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create ScenarioExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create ScenarioExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. - } + ScenExtension = Extension::Singleton::Make(this_ptr); /** * Stolen bytes here. @@ -105,43 +75,6 @@ DECLARE_PATCH(_ScenarioClass_Constructor_Patch) } -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_ScenarioClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(ScenarioClass *, this_ptr, esi); // "this" pointer. - GET_STACK_STATIC(const NoInitClass *, noinit, esp, 0x4); - - /** - * Create the extended class instance. - */ - New_Scenario_Extension(this_ptr); - if (!ScenarioExtension) { - DEBUG_ERROR("Failed to create ScenarioExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create ScenarioExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create ScenarioExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. - } - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 4 } -} - - /** * Patch for including the extended class members in the destruction process. * @@ -156,7 +89,7 @@ DECLARE_PATCH(_ScenarioClass_Destructor_Patch) /** * Remove the extended class instance. */ - Delete_Scenario_Extension(); + Extension::Singleton::Destroy(ScenExtension); /** * Stolen bytes here. @@ -180,14 +113,15 @@ DECLARE_PATCH(_ScenarioClass_Init_Clear_Patch) GET_REGISTER_STATIC(ScenarioClass *, this_ptr, esi); /** - * Find the extension instance. + * This is a odd case; ScenarioClass::Init_Clear is called within the class + * constructor, so the first time this patch is called, ScenExtension is NULL. + * The ScenarioClassExtension calls it's Init_Clear to mirror this behaviour + * so we can just check if the extension has be created first to catch this. */ - if (!ScenarioExtension) { - goto original_code; + if (ScenExtension) { + ScenExtension->Init_Clear(); } - ScenarioExtension->Init_Clear(); - /** * Stolen bytes here. */ @@ -201,48 +135,12 @@ DECLARE_PATCH(_ScenarioClass_Init_Clear_Patch) } -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_ScenarioClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(OverlayTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - - /** - * Find the extension instance. - */ - if (!ScenarioExtension) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - ScenarioExtension->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - /** * Main function for patching the hooks. */ void ScenarioClassExtension_Init() { Patch_Jump(0x005DADDE, &_ScenarioClass_Constructor_Patch); - Patch_Jump(0x005DAE87, &_ScenarioClass_NoInit_Constructor_Patch); Patch_Jump(0x006023CC, &_ScenarioClass_Destructor_Patch); // Inlined in game shutdown. Patch_Jump(0x005DB166, &_ScenarioClass_Init_Clear_Patch); - Patch_Jump(0x005E1440, &_ScenarioClass_Compute_CRC_Patch); } diff --git a/src/extensions/session/sessionext.cpp b/src/extensions/session/sessionext.cpp index 73b19ffd..d902ebf6 100644 --- a/src/extensions/session/sessionext.cpp +++ b/src/extensions/session/sessionext.cpp @@ -33,24 +33,22 @@ #include "rawfile.h" #include "voc.h" #include "rules.h" +#include "swizzle.h" +#include "vinifera_saveload.h" #include "asserthandler.h" #include "debughandler.h" -SessionClassExtension *SessionExtension = nullptr; - - /** * Class constructor. * * @author: CCHyper */ -SessionClassExtension::SessionClassExtension(SessionClass *this_ptr) : - Extension(this_ptr) +SessionClassExtension::SessionClassExtension(const SessionClass *this_ptr) : + GlobalExtensionClass(this_ptr), + ExtOptions() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SessionClassExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("SessionClassExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("SessionClassExtension::SessionClassExtension - 0x%08X\n", (uintptr_t)(ThisPtr)); /** * Initialises the default game options. @@ -58,8 +56,6 @@ SessionClassExtension::SessionClassExtension(SessionClass *this_ptr) : ExtOptions.IsAutoDeployMCV = false; ExtOptions.IsPrePlacedConYards = false; ExtOptions.IsBuildOffAlly = true; - - IsInitialized = true; } @@ -69,9 +65,9 @@ SessionClassExtension::SessionClassExtension(SessionClass *this_ptr) : * @author: CCHyper */ SessionClassExtension::SessionClassExtension(const NoInitClass &noinit) : - Extension(noinit) + GlobalExtensionClass(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("SessionClassExtension::SessionClassExtension(NoInitClass) - 0x%08X\n", (uintptr_t)(ThisPtr)); } @@ -82,10 +78,45 @@ SessionClassExtension::SessionClassExtension(const NoInitClass &noinit) : */ SessionClassExtension::~SessionClassExtension() { - //EXT_DEBUG_TRACE("SessionClassExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("SessionClassExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SessionClassExtension::~SessionClassExtension - 0x%08X\n", (uintptr_t)(ThisPtr)); +} + + +/** + * Initializes an object from the stream where it was saved previously. + * + * @author: CCHyper + */ +HRESULT SessionClassExtension::Load(IStream *pStm) +{ + //EXT_DEBUG_TRACE("SessionClassExtension::Load - 0x%08X\n", (uintptr_t)(This())); + + HRESULT hr = GlobalExtensionClass::Load(pStm); + if (FAILED(hr)) { + return E_FAIL; + } - IsInitialized = false; + new (this) SessionClassExtension(NoInitClass()); + + return hr; +} + + +/** + * Saves an object to the specified stream. + * + * @author: CCHyper + */ +HRESULT SessionClassExtension::Save(IStream *pStm, BOOL fClearDirty) +{ + //EXT_DEBUG_TRACE("SessionClassExtension::Save - 0x%08X\n", (uintptr_t)(This())); + + HRESULT hr = GlobalExtensionClass::Save(pStm, fClearDirty); + if (FAILED(hr)) { + return hr; + } + + return hr; } @@ -96,13 +127,34 @@ SessionClassExtension::~SessionClassExtension() */ int SessionClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SessionClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SessionClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(This())); return sizeof(*this); } +/** + * Removes the specified target from any targeting and reference trackers. + * + * @author: CCHyper + */ +void SessionClassExtension::Detach(TARGET target, bool all) +{ + //EXT_DEBUG_TRACE("SessionClassExtension::Detach - 0x%08X\n", (uintptr_t)(This())); +} + + +/** + * Compute a unique crc value for this instance. + * + * @author: CCHyper + */ +void SessionClassExtension::Compute_CRC(WWCRCEngine &crc) const +{ + //EXT_DEBUG_TRACE("SessionClassExtension::Compute_CRC - 0x%08X\n", (uintptr_t)(This())); +} + + /** * Fetches the extension data from the INI database. * @@ -110,9 +162,7 @@ int SessionClassExtension::Size_Of() const */ void SessionClassExtension::Read_MultiPlayer_Settings() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SessionClassExtension::Read_MultiPlayer_Settings - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("SessionClassExtension::Read_MultiPlayer_Settings - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SessionClassExtension::Read_MultiPlayer_Settings - 0x%08X\n", (uintptr_t)(This())); } @@ -123,7 +173,5 @@ void SessionClassExtension::Read_MultiPlayer_Settings() */ void SessionClassExtension::Write_MultiPlayer_Settings() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SessionClassExtension::Write_MultiPlayer_Settings - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("SessionClassExtension::Write_MultiPlayer_Settings - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SessionClassExtension::Write_MultiPlayer_Settings - 0x%08X\n", (uintptr_t)(This())); } diff --git a/src/extensions/session/sessionext.h b/src/extensions/session/sessionext.h index c084d031..391c2ba7 100644 --- a/src/extensions/session/sessionext.h +++ b/src/extensions/session/sessionext.h @@ -27,27 +27,28 @@ ******************************************************************************/ #pragma once +#include "always.h" #include "extension.h" -#include "container.h" +#include "session.h" -class SessionClass; -class CCINIClass; - - -class SessionClassExtension final : public Extension +class SessionClassExtension final : public GlobalExtensionClass { public: - SessionClassExtension(SessionClass *this_ptr); + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + SessionClassExtension(const SessionClass *this_ptr); SessionClassExtension(const NoInitClass &noinit); - ~SessionClassExtension(); + virtual ~SessionClassExtension(); - virtual HRESULT Load(IStream *pStm) override { return S_OK; } - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override { return S_OK; } virtual int Size_Of() const override; + virtual void Detach(TARGET target, bool all = true) override; + virtual void Compute_CRC(WWCRCEngine &crc) const override; - virtual void Detach(TARGET target, bool all = true) override {} - virtual void Compute_CRC(WWCRCEngine &crc) const override {} + virtual const char *Name() const override { return "Session"; } + virtual const char *Full_Name() const override { return "Session"; } void Read_MultiPlayer_Settings(); void Write_MultiPlayer_Settings(); @@ -74,6 +75,3 @@ class SessionClassExtension final : public Extension ExtGameOptionsType ExtOptions; }; - - -extern SessionClassExtension *SessionExtension; diff --git a/src/extensions/session/sessionext_init.cpp b/src/extensions/session/sessionext_init.cpp index 3fa142ad..533b84cd 100644 --- a/src/extensions/session/sessionext_init.cpp +++ b/src/extensions/session/sessionext_init.cpp @@ -27,37 +27,16 @@ ******************************************************************************/ #include "sessionext_hooks.h" #include "sessionext.h" +#include "tibsun_globals.h" #include "vinifera_util.h" +#include "extension.h" +#include "extension_globals.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" - -/** - * "new" operations must be done within a new function for patched code. - * - * @author: CCHyper - */ -static void New_Session_Extension(SessionClass *this_ptr) -{ - /** - * Delete existing instance (should never be the case). - */ - delete SessionExtension; - - SessionExtension = new SessionClassExtension(this_ptr); -} - - -/** - * "delete" operations must be done within a new function for patched code. - * - * @author: CCHyper - */ -static void Delete_Session_Extension() -{ - delete SessionExtension; -} +#include "hooker.h" +#include "hooker_macros.h" /** @@ -74,15 +53,7 @@ DECLARE_PATCH(_SessionClass_Constructor_Patch) /** * Create the extended class instance. */ - New_Session_Extension(this_ptr); - if (!SessionExtension) { - DEBUG_ERROR("Failed to create SessionExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create SessionExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create SessionExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. - } + SessionExtension = Extension::Singleton::Make(this_ptr); /** * Stolen bytes here. @@ -110,17 +81,9 @@ DECLARE_PATCH(_SessionClass_Destructor_Patch) GET_REGISTER_STATIC(SessionClass *, this_ptr, esi); /** - * Create the extended class instance. + * Remove the extended class instance. */ - New_Session_Extension(this_ptr); - if (!SessionExtension) { - DEBUG_ERROR("Failed to create SessionExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create SessionExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create SessionExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. - } + Extension::Singleton::Destroy(SessionExtension); /** * Stolen bytes here. @@ -146,10 +109,8 @@ DECLARE_PATCH(_SessionClass_Read_MultiPlayer_Settings_Patch) /** * Load ini. */ - if (SessionExtension) { - //DEBUG_INFO("Reading extended session settings\n"); - SessionExtension->Read_MultiPlayer_Settings(); - } + //DEBUG_INFO("Reading extended session settings\n"); + SessionExtension->Read_MultiPlayer_Settings(); /** * Stolen bytes here. @@ -176,10 +137,8 @@ DECLARE_PATCH(_SessionClass_Write_MultiPlayer_Settings_Patch) /** * Save ini. */ - if (SessionExtension) { - //DEBUG_INFO("Writing extended session settings\n"); - SessionExtension->Write_MultiPlayer_Settings(); - } + //DEBUG_INFO("Writing extended session settings\n"); + SessionExtension->Write_MultiPlayer_Settings(); /** * Stolen bytes here. diff --git a/src/extensions/side/sideext.cpp b/src/extensions/side/sideext.cpp index 49337556..efddf9c1 100644 --- a/src/extensions/side/sideext.cpp +++ b/src/extensions/side/sideext.cpp @@ -28,29 +28,22 @@ #include "sideext.h" #include "side.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all SideClass extension instances. - */ -ExtensionMap SideClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -SideClassExtension::SideClassExtension(SideClass *this_ptr) : - Extension(this_ptr) +SideClassExtension::SideClassExtension(const SideClass *this_ptr) : + AbstractTypeClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SideClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("SideClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("SideClassExtension::SideClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + SideExtensions.Add(this); } @@ -60,9 +53,9 @@ SideClassExtension::SideClassExtension(SideClass *this_ptr) : * @author: CCHyper */ SideClassExtension::SideClassExtension(const NoInitClass &noinit) : - Extension(noinit) + AbstractTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("SideClassExtension::SideClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ SideClassExtension::SideClassExtension(const NoInitClass &noinit) : */ SideClassExtension::~SideClassExtension() { - //EXT_DEBUG_TRACE("SideClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("SideClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SideClassExtension::~SideClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + SideExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT SideClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("SideClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -87,10 +98,9 @@ SideClassExtension::~SideClassExtension() */ HRESULT SideClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SideClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SideClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = AbstractTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT SideClassExtension::Load(IStream *pStm) */ HRESULT SideClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SideClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SideClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = AbstractTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT SideClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int SideClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SideClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SideClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int SideClassExtension::Size_Of() const */ void SideClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SideClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SideClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,8 +160,7 @@ void SideClassExtension::Detach(TARGET target, bool all) */ void SideClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SideClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SideClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -165,11 +171,13 @@ void SideClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool SideClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SideClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - DEV_DEBUG_WARNING("SideClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + DEV_DEBUG_WARNING("SideClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (!AbstractTypeClassExtension::Read_INI(ini)) { + return false; + } - const char *ini_name = ThisPtr->Name(); + const char *ini_name = Name(); if (!ini.Is_Present(ini_name)) { return false; diff --git a/src/extensions/side/sideext.h b/src/extensions/side/sideext.h index c4e44b4a..fedc55ee 100644 --- a/src/extensions/side/sideext.h +++ b/src/extensions/side/sideext.h @@ -27,33 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "abstracttypeext.h" +#include "side.h" -class SideClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_SIDE_EXTENSION) +SideClassExtension final : public AbstractTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class SideClassExtension final : public Extension -{ public: - SideClassExtension(SideClass *this_ptr); + SideClassExtension(const SideClass *this_ptr = nullptr); SideClassExtension(const NoInitClass &noinit); - ~SideClassExtension(); + virtual ~SideClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual SideClass *This() const override { return reinterpret_cast(AbstractTypeClassExtension::This()); } + virtual const SideClass *This_Const() const override { return reinterpret_cast(AbstractTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_SIDE; } - public: + virtual bool Read_INI(CCINIClass &ini) override; + public: }; - - -extern ExtensionMap SideClassExtensions; diff --git a/src/extensions/side/sideext_init.cpp b/src/extensions/side/sideext_init.cpp index 3ea26a0b..7fb94205 100644 --- a/src/extensions/side/sideext_init.cpp +++ b/src/extensions/side/sideext_init.cpp @@ -30,10 +30,15 @@ #include "side.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,23 +51,20 @@ DECLARE_PATCH(_SideClass_Constructor_Patch) { GET_REGISTER_STATIC(SideClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0x10); // ini name. - static SideClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating SideClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = SideClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create SideClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create SideClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create SideClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * Stolen bytes here. */ @@ -88,15 +90,14 @@ DECLARE_PATCH(_SideClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - SideClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007B3470 } // Sides.vtble + JMP_REG(eax, 0x005F1AEE); } @@ -114,52 +115,14 @@ DECLARE_PATCH(_SideClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - SideClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_SideClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(SideClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static SideClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = SideClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } + _asm { mov edx, ds:0x007B3470 } // Sides.vtble + JMP_REG(eax, 0x005F1D9E); } @@ -169,7 +132,6 @@ DECLARE_PATCH(_SideClass_Compute_CRC_Patch) void SideClassExtension_Init() { Patch_Jump(0x005F1AC6, &_SideClass_Constructor_Patch); - //Patch_Jump(0x005F1B68, &_SideClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x005F1E28, &_SideClass_Scalar_Destructor_Patch); - Patch_Jump(0x005F1BC9, &_SideClass_Compute_CRC_Patch); + //Patch_Jump(0x005F1AE8, &_SideClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x005F1D98, &_SideClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/sidebar/sidebarext_hooks.cpp b/src/extensions/sidebar/sidebarext_hooks.cpp index b445b867..4e4b6eb4 100644 --- a/src/extensions/sidebar/sidebarext_hooks.cpp +++ b/src/extensions/sidebar/sidebarext_hooks.cpp @@ -35,6 +35,7 @@ #include "spritecollection.h" #include "bsurface.h" #include "drawshape.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" @@ -68,8 +69,8 @@ DECLARE_PATCH(_SidebarClass_StripClass_ObjectTypeClass_Custom_Cameo_Image_Patch) _SidebarClass_StripClass_obj = obj; _SidebarClass_StripClass_CustomImage = nullptr; - technotypeext = TechnoTypeClassExtensions.find(reinterpret_cast(obj)); - if (technotypeext && technotypeext->CameoImageSurface) { + technotypeext = Extension::Fetch(reinterpret_cast(obj)); + if (technotypeext->CameoImageSurface) { _SidebarClass_StripClass_CustomImage = technotypeext->CameoImageSurface; } @@ -89,8 +90,8 @@ DECLARE_PATCH(_SidebarClass_StripClass_SuperWeaponType_Custom_Cameo_Image_Patch) _SidebarClass_StripClass_spc = supertype; _SidebarClass_StripClass_CustomImage = nullptr; - supertypeext = SuperWeaponTypeClassExtensions.find(supertype); - if (supertypeext && supertypeext->CameoImageSurface) { + supertypeext = Extension::Fetch(supertype); + if (supertypeext->CameoImageSurface) { _SidebarClass_StripClass_CustomImage = supertypeext->CameoImageSurface; } diff --git a/src/extensions/smudgetype/smudgetypeext.cpp b/src/extensions/smudgetype/smudgetypeext.cpp index 954f4bdd..04ef15bd 100644 --- a/src/extensions/smudgetype/smudgetypeext.cpp +++ b/src/extensions/smudgetype/smudgetypeext.cpp @@ -28,29 +28,22 @@ #include "smudgetypeext.h" #include "smudgetype.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all SmudgeTypeClass extension instances. - */ -ExtensionMap SmudgeTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -SmudgeTypeClassExtension::SmudgeTypeClassExtension(SmudgeTypeClass *this_ptr) : - Extension(this_ptr) +SmudgeTypeClassExtension::SmudgeTypeClassExtension(const SmudgeTypeClass *this_ptr) : + ObjectTypeClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SmudgeTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("SmudgeTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("SmudgeTypeClassExtension::SmudgeTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + SmudgeTypeExtensions.Add(this); } @@ -60,9 +53,9 @@ SmudgeTypeClassExtension::SmudgeTypeClassExtension(SmudgeTypeClass *this_ptr) : * @author: CCHyper */ SmudgeTypeClassExtension::SmudgeTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::SmudgeTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ SmudgeTypeClassExtension::SmudgeTypeClassExtension(const NoInitClass &noinit) : */ SmudgeTypeClassExtension::~SmudgeTypeClassExtension() { - //EXT_DEBUG_TRACE("SmudgeTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("SmudgeTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::~SmudgeTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + SmudgeTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT SmudgeTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -87,10 +98,9 @@ SmudgeTypeClassExtension::~SmudgeTypeClassExtension() */ HRESULT SmudgeTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT SmudgeTypeClassExtension::Load(IStream *pStm) */ HRESULT SmudgeTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT SmudgeTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int SmudgeTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int SmudgeTypeClassExtension::Size_Of() const */ void SmudgeTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,8 +160,7 @@ void SmudgeTypeClassExtension::Detach(TARGET target, bool all) */ void SmudgeTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -165,11 +171,13 @@ void SmudgeTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool SmudgeTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("SmudgeTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SmudgeTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (!ObjectTypeClassExtension::Read_INI(ini)) { + return false; + } - const char *ini_name = ThisPtr->Name(); + const char *ini_name = Name(); if (!ini.Is_Present(ini_name)) { return false; diff --git a/src/extensions/smudgetype/smudgetypeext.h b/src/extensions/smudgetype/smudgetypeext.h index 73a6a008..f0c1c818 100644 --- a/src/extensions/smudgetype/smudgetypeext.h +++ b/src/extensions/smudgetype/smudgetypeext.h @@ -27,33 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "objecttypeext.h" +#include "smudgetype.h" -class SmudgeTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_SMUDGETYPE_EXTENSION) +SmudgeTypeClassExtension final : public ObjectTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class SmudgeTypeClassExtension final : public Extension -{ public: - SmudgeTypeClassExtension(SmudgeTypeClass *this_ptr); + SmudgeTypeClassExtension(const SmudgeTypeClass *this_ptr = nullptr); SmudgeTypeClassExtension(const NoInitClass &noinit); - ~SmudgeTypeClassExtension(); + virtual ~SmudgeTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual SmudgeTypeClass *This() const override { return reinterpret_cast(ObjectTypeClassExtension::This()); } + virtual const SmudgeTypeClass *This_Const() const override { return reinterpret_cast(ObjectTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_SMUDGETYPE; } - public: + virtual bool Read_INI(CCINIClass &ini) override; + public: }; - - -extern ExtensionMap SmudgeTypeClassExtensions; diff --git a/src/extensions/smudgetype/smudgetypeext_init.cpp b/src/extensions/smudgetype/smudgetypeext_init.cpp index 9f4184ff..ebaee73c 100644 --- a/src/extensions/smudgetype/smudgetypeext_init.cpp +++ b/src/extensions/smudgetype/smudgetypeext_init.cpp @@ -30,10 +30,15 @@ #include "smudgetype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,45 +51,19 @@ DECLARE_PATCH(_SmudgeTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(SmudgeTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0xC); // ini name. - static SmudgeTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating SmudgeTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = SmudgeTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create SmudgeTypeClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create SmudgeTypeClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create SmudgeTypeClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_SmudgeTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(SmudgeTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. @@ -92,6 +71,7 @@ DECLARE_PATCH(_SmudgeTypeClass_NoInit_Constructor_Patch) original_code: _asm { mov eax, this_ptr } _asm { pop esi } + _asm { pop ebx } _asm { ret 4 } } @@ -110,15 +90,14 @@ DECLARE_PATCH(_SmudgeTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - SmudgeTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007B3470 } // SmudgeTypes.vtble + JMP_REG(eax, 0x005FB31E); } @@ -136,90 +115,14 @@ DECLARE_PATCH(_SmudgeTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - SmudgeTypeClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_SmudgeTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(SmudgeTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static SmudgeTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = SmudgeTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_SmudgeTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(SmudgeTypeClass *, this_ptr, esi); - GET_REGISTER_STATIC(CCINIClass *, ini, ebx); - static SmudgeTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = SmudgeTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov al, 1 } - _asm { pop esi } - _asm { pop ebx } - _asm { add esp, 0x200 } - _asm { ret 4 } + _asm { mov edx, ds:0x007B3470 } // SmudgeTypes.vtble + JMP_REG(eax, 0x005FC02E); } @@ -230,9 +133,6 @@ void SmudgeTypeClassExtension_Init() { Patch_Jump(0x005FB2CC, &_SmudgeTypeClass_Constructor_Patch); Patch_Jump(0x005FB2D9, &_SmudgeTypeClass_Constructor_Patch); - Patch_Jump(0x005FB2FA, &_SmudgeTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x005FB368, &_SmudgeTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x005FC088, &_SmudgeTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x005FB724, &_SmudgeTypeClass_Compute_CRC_Patch); - Patch_Jump(0x005FB6A7, &_SmudgeTypeClass_Read_INI_Patch); + //Patch_Jump(0x005FB318, &_SmudgeTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x005FC028, &_SmudgeTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/super/superext.cpp b/src/extensions/super/superext.cpp index c48e0970..65d576c5 100644 --- a/src/extensions/super/superext.cpp +++ b/src/extensions/super/superext.cpp @@ -28,31 +28,24 @@ #include "superext.h" #include "super.h" #include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all SuperClass extension instances. - */ -ExtensionMap SuperClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -SuperClassExtension::SuperClassExtension(SuperClass *this_ptr) : - Extension(this_ptr), +SuperClassExtension::SuperClassExtension(const SuperClass *this_ptr) : + AbstractClassExtension(this_ptr), FlashTimeEnd(0), TimerFlashState(false) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SuperClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("SuperClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("SuperClassExtension::SuperClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + SuperExtensions.Add(this); } @@ -62,9 +55,9 @@ SuperClassExtension::SuperClassExtension(SuperClass *this_ptr) : * @author: CCHyper */ SuperClassExtension::SuperClassExtension(const NoInitClass &noinit) : - Extension(noinit) + AbstractClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("SuperClassExtension::SuperClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -75,10 +68,28 @@ SuperClassExtension::SuperClassExtension(const NoInitClass &noinit) : */ SuperClassExtension::~SuperClassExtension() { - //EXT_DEBUG_TRACE("SuperClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("SuperClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SuperClassExtension::~SuperClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + SuperExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT SuperClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("SuperClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); - IsInitialized = false; + return S_OK; } @@ -89,10 +100,9 @@ SuperClassExtension::~SuperClassExtension() */ HRESULT SuperClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SuperClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SuperClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = AbstractClassExtension::Internal_Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -110,10 +120,9 @@ HRESULT SuperClassExtension::Load(IStream *pStm) */ HRESULT SuperClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SuperClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SuperClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = AbstractClassExtension::Internal_Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -129,8 +138,7 @@ HRESULT SuperClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int SuperClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SuperClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SuperClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -143,8 +151,7 @@ int SuperClassExtension::Size_Of() const */ void SuperClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SuperClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SuperClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -155,6 +162,5 @@ void SuperClassExtension::Detach(TARGET target, bool all) */ void SuperClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SuperClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SuperClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } diff --git a/src/extensions/super/superext.h b/src/extensions/super/superext.h index 32e7e7cf..73b0e5b0 100644 --- a/src/extensions/super/superext.h +++ b/src/extensions/super/superext.h @@ -27,28 +27,45 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "abstracttypeext.h" +#include "super.h" +#include "supertype.h" -class SuperClass; class HouseClass; -class SuperClassExtension final : public Extension +class DECLSPEC_UUID(UUID_SUPERWEAPON_EXTENSION) +SuperClassExtension final : public AbstractClassExtension { public: - SuperClassExtension(SuperClass *this_ptr); + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + SuperClassExtension(const SuperClass *this_ptr = nullptr); SuperClassExtension(const NoInitClass &noinit); - ~SuperClassExtension(); + virtual ~SuperClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + virtual const char *Name() const override { return reinterpret_cast(This())->Class->Name(); } + virtual const char *Full_Name() const override { return reinterpret_cast(This())->Class->Full_Name(); } + + virtual SuperClass *This() const override { return reinterpret_cast(AbstractClassExtension::This()); } + virtual const SuperClass *This_Const() const override { return reinterpret_cast(AbstractClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_SUPERWEAPON; } + public: /** * The time at which the flash mode should return to normal. @@ -60,6 +77,3 @@ class SuperClassExtension final : public Extension */ bool TimerFlashState; }; - - -extern ExtensionMap SuperClassExtensions; diff --git a/src/extensions/super/superext_init.cpp b/src/extensions/super/superext_init.cpp index 7d5ae0a3..57ad7856 100644 --- a/src/extensions/super/superext_init.cpp +++ b/src/extensions/super/superext_init.cpp @@ -27,10 +27,16 @@ ******************************************************************************/ #include "superext.h" #include "super.h" +#include "tibsun_globals.h" +#include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" -#include "vinifera_util.h" + +#include "hooker.h" +#include "hooker_macros.h" /** @@ -43,21 +49,20 @@ DECLARE_PATCH(_SuperClass_Default_Constructor_Patch) { GET_REGISTER_STATIC(SuperClass *, this_ptr, esi); // Current "this" pointer. - static SuperClassExtension *exttype_ptr; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = SuperClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create SuperClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create SuperClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create SuperClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * Stolen bytes here. */ @@ -78,21 +83,20 @@ DECLARE_PATCH(_SuperClass_Default_Constructor_Patch) DECLARE_PATCH(_SuperClass_Constructor_Patch) { GET_REGISTER_STATIC(SuperClass *, this_ptr, esi); // Current "this" pointer. - static SuperClassExtension *exttype_ptr; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = SuperClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create SuperClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create SuperClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create SuperClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * Stolen bytes here. */ @@ -118,15 +122,14 @@ DECLARE_PATCH(_SuperClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - SuperClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x0080F588 } // Neuron vector.vtble + JMP_REG(eax, 0x0060B520); } @@ -144,81 +147,35 @@ DECLARE_PATCH(_SuperClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - SuperClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } + _asm { mov edx, ds:0x0080F588 } // Neuron vector.vtble + JMP_REG(eax, 0x0060CC30); } /** - * Patch for including the extended class members to the base class detach process. + * This patch fixes the incorrect constructor being used in SuperClass::Load, so + * this is technically a bug fix, while also allowing the extended class to operate + * correctly. * * @warning: Do not touch this unless you know what you are doing! * * @author: CCHyper */ -DECLARE_PATCH(_SuperClass_Detach_Patch) +DECLARE_PATCH(_SuperClass_Load_Patch) { - GET_REGISTER_STATIC(SuperClass *, this_ptr, ecx); - GET_STACK_STATIC(TARGET, target, esp, 0x10); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static SuperClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = SuperClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Detach(target, all); + _asm { lea ecx, [esp+0x0C] } + _asm { push ecx } + _asm { mov ecx, esi } + _asm { mov eax, 0x00405B70 } // AbstractClass::AbstractClass(const NoInitClass &) + _asm { call eax } - /** - * Stolen bytes here. - */ -original_code: - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members to the base class crc calculation. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_SuperClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(SuperClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static SuperClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = SuperClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } + JMP(0x0060C7AF); } @@ -229,8 +186,7 @@ void SuperClassExtension_Init() { Patch_Jump(0x0060B352, &_SuperClass_Default_Constructor_Patch); Patch_Jump(0x0060B4AB, &_SuperClass_Constructor_Patch); - Patch_Jump(0x0060B5B3, &_SuperClass_Destructor_Patch); - Patch_Jump(0x0060CCD3, &_SuperClass_Scalar_Destructor_Patch); - Patch_Jump(0x0060C81C, &_SuperClass_Detach_Patch); - Patch_Jump(0x0060C870, &_SuperClass_Compute_CRC_Patch); + Patch_Jump(0x0060B51A, &_SuperClass_Destructor_Patch); + Patch_Jump(0x0060CC2A, &_SuperClass_Scalar_Destructor_Patch); + Patch_Jump(0x0060C7A8, &_SuperClass_Load_Patch); } diff --git a/src/extensions/supertype/supertypeext.cpp b/src/extensions/supertype/supertypeext.cpp index b251cad4..18f9aa54 100644 --- a/src/extensions/supertype/supertypeext.cpp +++ b/src/extensions/supertype/supertypeext.cpp @@ -30,31 +30,25 @@ #include "vinifera_util.h" #include "bsurface.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all SuperWeaponTypeClass extension instances. - */ -ExtensionMap SuperWeaponTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -SuperWeaponTypeClassExtension::SuperWeaponTypeClassExtension(SuperWeaponTypeClass *this_ptr) : - Extension(this_ptr), +SuperWeaponTypeClassExtension::SuperWeaponTypeClassExtension(const SuperWeaponTypeClass *this_ptr) : + AbstractTypeClassExtension(this_ptr), + SidebarImage(), IsShowTimer(false), CameoImageSurface(nullptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("SuperWeaponTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::SuperWeaponTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + SuperWeaponTypeExtensions.Add(this); } @@ -64,9 +58,9 @@ SuperWeaponTypeClassExtension::SuperWeaponTypeClassExtension(SuperWeaponTypeClas * @author: CCHyper */ SuperWeaponTypeClassExtension::SuperWeaponTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + AbstractTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::SuperWeaponTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -77,13 +71,31 @@ SuperWeaponTypeClassExtension::SuperWeaponTypeClassExtension(const NoInitClass & */ SuperWeaponTypeClassExtension::~SuperWeaponTypeClassExtension() { - //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("SuperWeaponTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::~SuperWeaponTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); delete CameoImageSurface; CameoImageSurface = nullptr; - IsInitialized = false; + SuperWeaponTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT SuperWeaponTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -94,10 +106,9 @@ SuperWeaponTypeClassExtension::~SuperWeaponTypeClassExtension() */ HRESULT SuperWeaponTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = AbstractTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -107,7 +118,7 @@ HRESULT SuperWeaponTypeClassExtension::Load(IStream *pStm) /** * Fetch the cameo image surface if it exists. */ - BSurface *imagesurface = Vinifera_Get_Image_Surface(ThisPtr->SidebarImage); + BSurface *imagesurface = Vinifera_Get_Image_Surface(SidebarImage); if (imagesurface) { CameoImageSurface = imagesurface; } @@ -123,10 +134,14 @@ HRESULT SuperWeaponTypeClassExtension::Load(IStream *pStm) */ HRESULT SuperWeaponTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + /** + * Store the graphic name strings as raw data, these are used by the load operation. + */ + std::strncpy(SidebarImage, This()->SidebarImage, sizeof(SidebarImage)); + + HRESULT hr = AbstractTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -142,8 +157,7 @@ HRESULT SuperWeaponTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int SuperWeaponTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -156,8 +170,7 @@ int SuperWeaponTypeClassExtension::Size_Of() const */ void SuperWeaponTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -168,8 +181,7 @@ void SuperWeaponTypeClassExtension::Detach(TARGET target, bool all) */ void SuperWeaponTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -180,22 +192,20 @@ void SuperWeaponTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool SuperWeaponTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("SuperWeaponTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("SuperWeaponTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - const char *ini_name = ThisPtr->Name(); - - if (!ini.Is_Present(ini_name)) { + if (!AbstractTypeClassExtension::Read_INI(ini)) { return false; } + const char *ini_name = Name(); + IsShowTimer = ini.Get_Bool(ini_name, "ShowTimer", IsShowTimer); /** * Fetch the cameo image surface if it exists. */ - BSurface *imagesurface = Vinifera_Get_Image_Surface(ThisPtr->SidebarImage); + BSurface *imagesurface = Vinifera_Get_Image_Surface(This()->SidebarImage); if (imagesurface) { CameoImageSurface = imagesurface; } diff --git a/src/extensions/supertype/supertypeext.h b/src/extensions/supertype/supertypeext.h index 518e92b3..a106defa 100644 --- a/src/extensions/supertype/supertypeext.h +++ b/src/extensions/supertype/supertypeext.h @@ -27,30 +27,48 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "abstracttypeext.h" +#include "supertype.h" -class SuperWeaponTypeClass; -class CCINIClass; class BSurface; -class SuperWeaponTypeClassExtension final : public Extension +class DECLSPEC_UUID(UUID_SUPERWEAPONTYPE_EXTENSION) +SuperWeaponTypeClassExtension final : public AbstractTypeClassExtension { public: - SuperWeaponTypeClassExtension(SuperWeaponTypeClass *this_ptr); + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + SuperWeaponTypeClassExtension(const SuperWeaponTypeClass *this_ptr = nullptr); SuperWeaponTypeClassExtension(const NoInitClass &noinit); - ~SuperWeaponTypeClassExtension(); + virtual ~SuperWeaponTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual bool Read_INI(CCINIClass &ini) override; + + virtual SuperWeaponTypeClass *This() const override { return reinterpret_cast(AbstractTypeClassExtension::This()); } + virtual const SuperWeaponTypeClass *This_Const() const override { return reinterpret_cast(AbstractTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_SUPERWEAPONTYPE; } + + protected: + /** + * These are only to be accessed for save and load operations! + */ + char SidebarImage[24 + 1]; public: /** @@ -64,6 +82,3 @@ class SuperWeaponTypeClassExtension final : public Extension SuperWeaponTypeClassExtensions; diff --git a/src/extensions/supertype/supertypeext_init.cpp b/src/extensions/supertype/supertypeext_init.cpp index cf000d27..1d43b431 100644 --- a/src/extensions/supertype/supertypeext_init.cpp +++ b/src/extensions/supertype/supertypeext_init.cpp @@ -30,10 +30,15 @@ #include "supertype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,54 +51,29 @@ DECLARE_PATCH(_SuperWeaponTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(SuperWeaponTypeClass *, this_ptr, ebp); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0x14); // ini name. - static SuperWeaponTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating SuperWeaponTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = SuperWeaponTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create SuperWeaponTypeClassExtension instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create SuperWeaponTypeClassExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create SuperWeaponTypeClassExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { pop edi } - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_SuperWeaponTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(SuperWeaponTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. */ original_code: + _asm { pop edi } _asm { mov eax, this_ptr } _asm { pop esi } + _asm { pop ebp } + _asm { pop ebx } _asm { ret 4 } } @@ -112,15 +92,14 @@ DECLARE_PATCH(_SuperWeaponTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - SuperWeaponTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + this_ptr->AbstractTypeClass::~AbstractTypeClass(); + JMP_REG(ecx, 0x0060D0F1); } @@ -138,90 +117,14 @@ DECLARE_PATCH(_SuperWeaponTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - SuperWeaponTypeClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_SuperWeaponTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(SuperWeaponTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static SuperWeaponTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = SuperWeaponTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_SuperWeaponTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(SuperWeaponTypeClass *, this_ptr, ebp); - GET_REGISTER_STATIC(CCINIClass *, ini, ebx); - static SuperWeaponTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = SuperWeaponTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov al, 1 } - _asm { pop ebp } - _asm { pop ebx } - _asm { add esp, 0x3C8 } - _asm { ret 4 } + this_ptr->AbstractTypeClass::~AbstractTypeClass(); + JMP_REG(ecx, 0x0060D881); } @@ -231,9 +134,6 @@ DECLARE_PATCH(_SuperWeaponTypeClass_Read_INI_Patch) void SuperWeaponTypeClassExtension_Init() { Patch_Jump(0x0060D04A, &_SuperWeaponTypeClass_Constructor_Patch); - Patch_Jump(0x0060D084, &_SuperWeaponTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x0060D0F1, &_SuperWeaponTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x0060D891, &_SuperWeaponTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x0060D2D3, &_SuperWeaponTypeClass_Compute_CRC_Patch); - Patch_Jump(0x0060D57A, &_SuperWeaponTypeClass_Read_INI_Patch); + //Patch_Jump(0x0060D0EA, &_SuperWeaponTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x0060D87A, &_SuperWeaponTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/tactical/tacticalext.cpp b/src/extensions/tactical/tacticalext.cpp index 9337722d..a43d76bf 100644 --- a/src/extensions/tactical/tacticalext.cpp +++ b/src/extensions/tactical/tacticalext.cpp @@ -33,6 +33,7 @@ #include "colorscheme.h" #include "rgb.h" #include "wwfont.h" +#include "wwcrc.h" #include "foot.h" #include "unit.h" #include "unittype.h" @@ -47,21 +48,20 @@ #include "supertypeext.h" #include "rules.h" #include "rulesext.h" +#include "swizzle.h" +#include "vinifera_saveload.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -TacticalMapExtension *TacticalExtension = nullptr; - - /** * Class constructor. * * @author: CCHyper */ -TacticalMapExtension::TacticalMapExtension(Tactical *this_ptr) : - Extension(this_ptr), - +TacticalExtension::TacticalExtension(const Tactical *this_ptr) : + GlobalExtensionClass(this_ptr), IsInfoTextSet(false), InfoTextBuffer(), InfoTextPosition(BOTTOM_LEFT), @@ -70,11 +70,7 @@ TacticalMapExtension::TacticalMapExtension(Tactical *this_ptr) : InfoTextStyle(TPF_6PT_GRAD|TPF_DROPSHADOW), InfoTextTimer(0) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TacticalMapExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("TacticalMapExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - - IsInitialized = true; + //if (this_ptr) EXT_DEBUG_TRACE("TacticalExtension::TacticalExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -83,13 +79,11 @@ TacticalMapExtension::TacticalMapExtension(Tactical *this_ptr) : * * @author: CCHyper */ -TacticalMapExtension::TacticalMapExtension(const NoInitClass &noinit) : - Extension(noinit), - - IsInfoTextSet(false), +TacticalExtension::TacticalExtension(const NoInitClass &noinit) : + GlobalExtensionClass(noinit), InfoTextTimer(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("TacticalExtension::TacticalExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -98,54 +92,29 @@ TacticalMapExtension::TacticalMapExtension(const NoInitClass &noinit) : * * @author: CCHyper */ -TacticalMapExtension::~TacticalMapExtension() +TacticalExtension::~TacticalExtension() { - //EXT_DEBUG_TRACE("TacticalMapExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("TacticalMapExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - - IsInitialized = false; + //EXT_DEBUG_TRACE("TacticalExtension::~TacticalExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } /** * Initializes an object from the stream where it was saved previously. - * - * As TacticalMapExtension is static data, we do not need to request - * pointer remap of "ThisPtr" after loading has finished. * * @author: CCHyper */ -HRESULT TacticalMapExtension::Load(IStream *pStm) +HRESULT TacticalExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TacticalMapExtension::Load - 0x%08X\n", (uintptr_t)(ThisPtr)); - - HRESULT hr = ExtensionBase::Load(pStm); - if (FAILED(hr)) { - return E_FAIL; - } - - LONG id; - hr = pStm->Read(&id, sizeof(id), nullptr); - if (FAILED(hr)) { - return E_FAIL; - } + //EXT_DEBUG_TRACE("TacticalExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - ULONG size = Size_Of(); - hr = pStm->Read(this, size, nullptr); + HRESULT hr = GlobalExtensionClass::Load(pStm); if (FAILED(hr)) { return E_FAIL; } - new (this) TacticalMapExtension(NoInitClass()); - - SWIZZLE_REGISTER_POINTER(id, this); - -#ifndef NDEBUG - EXT_DEBUG_INFO("TacticalExt Load: ID 0x%08X Ptr 0x%08X\n", id, this); -#endif - - return S_OK; + new (this) TacticalExtension(NoInitClass()); + + return hr; } @@ -154,12 +123,11 @@ HRESULT TacticalMapExtension::Load(IStream *pStm) * * @author: CCHyper */ -HRESULT TacticalMapExtension::Save(IStream *pStm, BOOL fClearDirty) +HRESULT TacticalExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TacticalMapExtension::Save - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TacticalExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = GlobalExtensionClass::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -173,10 +141,9 @@ HRESULT TacticalMapExtension::Save(IStream *pStm, BOOL fClearDirty) * * @author: CCHyper */ -int TacticalMapExtension::Size_Of() const +int TacticalExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TacticalMapExtension::Size_Of - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TacticalExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -187,10 +154,9 @@ int TacticalMapExtension::Size_Of() const * * @author: CCHyper */ -void TacticalMapExtension::Detach(TARGET target, bool all) +void TacticalExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TacticalMapExtension::Detach - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TacticalExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -199,22 +165,32 @@ void TacticalMapExtension::Detach(TARGET target, bool all) * * @author: CCHyper */ -void TacticalMapExtension::Compute_CRC(WWCRCEngine &crc) const +void TacticalExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TacticalMapExtension::Compute_CRC - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TacticalExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } /** - * Draws the developer mode overlay. + * Set the information text to be displayed. * * @authors: CCHyper */ -void TacticalMapExtension::Draw_Debug_Overlay() +void TacticalExtension::Set_Info_Text(const char *text) { - ASSERT(ThisPtr != nullptr); + std::memset(TacticalMapExtension->InfoTextBuffer, 0, sizeof(TacticalMapExtension->InfoTextBuffer)); + std::strncpy(TacticalMapExtension->InfoTextBuffer, text, sizeof(TacticalMapExtension->InfoTextBuffer)); + TacticalMapExtension->InfoTextBuffer[std::strlen(text)-1] = '\0'; +} + +/** + * Draws the developer mode overlay. + * + * @authors: CCHyper + */ +void TacticalExtension::Draw_Debug_Overlay() +{ RGBClass rgb_black(0,0,0); unsigned color_black = DSurface::RGB_To_Pixel(0, 0, 0); ColorScheme *text_color = ColorScheme::As_Pointer("White"); @@ -288,10 +264,8 @@ void TacticalMapExtension::Draw_Debug_Overlay() * * @author: CCHyper */ -bool TacticalMapExtension::Debug_Draw_Facings() +bool TacticalExtension::Debug_Draw_Facings() { - ASSERT(ThisPtr != nullptr); - if (CurrentObjects.Count() != 1) { return false; } @@ -347,10 +321,8 @@ bool TacticalMapExtension::Debug_Draw_Facings() * * @authors: CCHyper */ -void TacticalMapExtension::Draw_FrameStep_Overlay() +void TacticalExtension::Draw_FrameStep_Overlay() { - ASSERT(ThisPtr != nullptr); - RGBClass rgb_black(0,0,0); unsigned color_black = DSurface::RGB_To_Pixel(0, 0, 0); ColorScheme *text_color = ColorScheme::As_Pointer("White"); @@ -396,9 +368,11 @@ void TacticalMapExtension::Draw_FrameStep_Overlay() * * @author: CCHyper */ -void TacticalMapExtension::Draw_Information_Text() +void TacticalExtension::Draw_Information_Text() { - ASSERT(ThisPtr != nullptr); + if (!IsInfoTextSet) { + return; + } RGBClass rgb_black(0,0,0); unsigned color_black = DSurface::RGB_To_Pixel(0, 0, 0); @@ -406,14 +380,7 @@ void TacticalMapExtension::Draw_Information_Text() int padding = 2; - if (!TacticalExtension) { - return; - } - - const char *text = TacticalExtension->InfoTextBuffer.Peek_Buffer(); - if (!text) { - return; - } + const char *text = InfoTextBuffer; /** * Fetch the text occupy area. @@ -423,11 +390,11 @@ void TacticalMapExtension::Draw_Information_Text() Rect fill_rect; - TextPrintType style = TacticalExtension->InfoTextStyle; + TextPrintType style = InfoTextStyle; int pos_x = 0; int pos_y = 0; - switch (TacticalExtension->InfoTextPosition) { + switch (InfoTextPosition) { default: case InfoTextPosType::TOP_LEFT: @@ -529,10 +496,9 @@ void TacticalMapExtension::Draw_Information_Text() * * @authors: CCHyper */ -void TacticalMapExtension::Render_Post() +void TacticalExtension::Render_Post() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TacticalMapExtension::Render_Post - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TacticalExtension::Render_Post - 0x%08X\n", (uintptr_t)(This())); /** * Draw any new post effects here. @@ -553,7 +519,7 @@ void TacticalMapExtension::Render_Post() * * @authors: CCHyper */ -void TacticalMapExtension::Super_Draw_Timer(int row_index, ColorScheme *color, int time, const char *name, unsigned long *flash_time, bool *flash_state) +void TacticalExtension::Super_Draw_Timer(int row_index, ColorScheme *color, int time, const char *name, unsigned long *flash_time, bool *flash_state) { static WWFontClass *_font = nullptr; @@ -644,10 +610,9 @@ void TacticalMapExtension::Super_Draw_Timer(int row_index, ColorScheme *color, i * * @authors: CCHyper */ -void TacticalMapExtension::Draw_Super_Timers() +void TacticalExtension::Draw_Super_Timers() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TacticalMapExtension::Draw_Super_Timers - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TacticalExtension::Draw_Super_Timers - 0x%08X\n", (uintptr_t)(This())); /** * Super weapon timers are for multiplayer only. @@ -661,7 +626,7 @@ void TacticalMapExtension::Draw_Super_Timers() /** * Does the game rules state that the super weapon timers should be shown? */ - if (!RulesExtension->IsShowSuperWeaponTimers) { + if (!RuleExtension->IsShowSuperWeaponTimers) { return; } @@ -672,13 +637,6 @@ void TacticalMapExtension::Draw_Super_Timers() return; } - /** - * If no SuperClass extensions are found, then this feature is unavailable. - */ - if (!SuperClassExtensions.size() || !SuperWeaponTypeClassExtensions.size()) { - return; - } - /** * Non-release builds print the version information to the tactical view * so we need to adjust the timers to print above this text. @@ -695,11 +653,8 @@ void TacticalMapExtension::Draw_Super_Timers() for (int i = 0; i < Supers.Count(); ++i) { SuperClass *super = Supers[i]; - SuperClassExtension *superext = SuperClassExtensions.find(super); - SuperWeaponTypeClassExtension *supertypeext = SuperWeaponTypeClassExtensions.find(super->Class); - if (!superext || !supertypeext) { - continue; - } + SuperClassExtension *superext = Extension::Fetch(super); + SuperWeaponTypeClassExtension *supertypeext = Extension::Fetch(super->Class); /** * Should we show the recharge timer for this super? diff --git a/src/extensions/tactical/tacticalext.h b/src/extensions/tactical/tacticalext.h index 08dd6214..50b9874f 100644 --- a/src/extensions/tactical/tacticalext.h +++ b/src/extensions/tactical/tacticalext.h @@ -27,16 +27,19 @@ ******************************************************************************/ #pragma once +#include "abstractext.h" #include "extension.h" +#include "tactical.h" #include "ttimer.h" #include "stimer.h" #include "wstring.h" #include "point.h" #include "textprint.h" +#include -class Tactical; class HouseClass; +class WWCRCEngine; enum InfoTextPosType { @@ -47,23 +50,26 @@ enum InfoTextPosType { }; -/** - * Extension to Tactical. - */ -class TacticalMapExtension final : public Extension +class TacticalExtension final : public GlobalExtensionClass { public: - TacticalMapExtension(Tactical *this_ptr); - TacticalMapExtension(const NoInitClass &noinit); - ~TacticalMapExtension(); + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; - virtual int Size_Of() const override; + public: + TacticalExtension(const Tactical *this_ptr = nullptr); + TacticalExtension(const NoInitClass &noinit); + virtual ~TacticalExtension(); + virtual int Size_Of() const override; virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + virtual const char *Name() const override { return "TacticalMap"; } + virtual const char *Full_Name() const override { return "TacticalMap"; } + + void Set_Info_Text(const char *text); + void Draw_Debug_Overlay(); void Draw_FrameStep_Overlay(); @@ -88,7 +94,7 @@ class TacticalMapExtension final : public Extension /** * The information text to print on the screen. */ - Wstring InfoTextBuffer; + char InfoTextBuffer[512]; /** * Where on the screen shall the text be printed? @@ -115,9 +121,3 @@ class TacticalMapExtension final : public Extension */ CDTimerClass InfoTextTimer; }; - - -/** - * Global instance of the extended class. - */ -extern TacticalMapExtension *TacticalExtension; diff --git a/src/extensions/tactical/tacticalext_hooks.cpp b/src/extensions/tactical/tacticalext_hooks.cpp index 17db1120..54619a8b 100644 --- a/src/extensions/tactical/tacticalext_hooks.cpp +++ b/src/extensions/tactical/tacticalext_hooks.cpp @@ -32,13 +32,17 @@ #include "voc.h" #include "laserdraw.h" #include "ebolt.h" -#include "fatal.h" #include "vinifera_globals.h" #include "vinifera_util.h" +#include "extension_globals.h" +#include "fatal.h" #include "debughandler.h" #include "asserthandler.h" #include +#include "hooker.h" +#include "hooker_macros.h" + /** * #issue-315 @@ -258,9 +262,7 @@ DECLARE_PATCH(_Tactical_Render_Post_Effects_Patch) /** * Draw any new post effects here. */ - if (TacticalExtension) { - TacticalExtension->Render_Post(); - } + TacticalMapExtension->Render_Post(); JMP(0x00611AFE); } @@ -281,14 +283,10 @@ DECLARE_PATCH(_Tactical_Render_Overlay_Patch) */ if (Vinifera_DeveloperMode) { - if (TacticalExtension) { - - TacticalExtension->Draw_Debug_Overlay(); - - if (Vinifera_Developer_FrameStep) { - TacticalExtension->Draw_FrameStep_Overlay(); - } + TacticalMapExtension->Draw_Debug_Overlay(); + if (Vinifera_Developer_FrameStep) { + TacticalMapExtension->Draw_FrameStep_Overlay(); } } @@ -308,36 +306,34 @@ DECLARE_PATCH(_Tactical_Render_Overlay_Patch) Vinifera_Draw_Version_Text(CompositeSurface); #endif - if (TacticalExtension) { + /** + * Has custom screen text been set? + */ + if (TacticalMapExtension->IsInfoTextSet) { /** - * Has custom screen text been set? + * Draw it to the screen. + */ + TacticalMapExtension->Draw_Information_Text(); + + /** + * Play the one time notification sound if defined. */ - if (TacticalExtension->IsInfoTextSet) { - - /** - * Draw it to the screen. - */ - TacticalExtension->Draw_Information_Text(); - - /** - * Play the one time notification sound if defined. - */ - if (TacticalExtension->InfoTextNotifySound != VOC_NONE) { - Sound_Effect(TacticalExtension->InfoTextNotifySound, TacticalExtension->InfoTextNotifySoundVolume); - TacticalExtension->InfoTextNotifySound = VOC_NONE; - } - - /** - * If the screen timer has expired, disable drawing. - */ - if (TacticalExtension->InfoTextTimer.Expired()) { - TacticalExtension->InfoTextTimer.Stop(); - TacticalExtension->IsInfoTextSet = false; - TacticalExtension->InfoTextNotifySound = VOC_NONE; - TacticalExtension->InfoTextPosition = TOP_LEFT; - } + if (TacticalMapExtension->InfoTextNotifySound != VOC_NONE) { + Sound_Effect(TacticalMapExtension->InfoTextNotifySound, TacticalMapExtension->InfoTextNotifySoundVolume); + TacticalMapExtension->InfoTextNotifySound = VOC_NONE; } + + /** + * If the screen timer has expired, disable drawing. + */ + if (TacticalMapExtension->InfoTextTimer.Expired()) { + TacticalMapExtension->InfoTextTimer.Stop(); + TacticalMapExtension->IsInfoTextSet = false; + std::memset(TacticalMapExtension->InfoTextBuffer, 0, sizeof(TacticalMapExtension->InfoTextBuffer)); + TacticalMapExtension->InfoTextNotifySound = VOC_NONE; + TacticalMapExtension->InfoTextPosition = TOP_LEFT; + } } /** diff --git a/src/extensions/tactical/tacticalext_init.cpp b/src/extensions/tactical/tacticalext_init.cpp index d81e94fe..7ff4d490 100644 --- a/src/extensions/tactical/tacticalext_init.cpp +++ b/src/extensions/tactical/tacticalext_init.cpp @@ -28,41 +28,18 @@ #include "tacticalext_hooks.h" #include "tacticalext.h" #include "tactical.h" -#include "fatal.h" +#include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" +#include "fatal.h" #include "debughandler.h" #include "asserthandler.h" + #include "hooker.h" #include "hooker_macros.h" -/** - * "new" operations must be done within a new function for patched code. - * - * @author: CCHyper - */ -static void New_Tactical_Extension(Tactical *this_ptr) -{ - /** - * Delete existing instance (should never be the case). - */ - delete TacticalExtension; - - TacticalExtension = new TacticalMapExtension(this_ptr); -} - - -/** - * "delete" operations must be done within a new function for patched code. - * - * @author: CCHyper - */ -static void Delete_Tactical_Extension() -{ - delete TacticalExtension; -} - - /** * Patch for including the extended class members in the creation process. * @@ -77,15 +54,7 @@ DECLARE_PATCH(_Tactical_Constructor_Patch) /** * Create the extended class instance. */ - New_Tactical_Extension(this_ptr); - if (!TacticalExtension) { - DEBUG_ERROR("Failed to create TacticalExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create TacticalExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create TacticalExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. - } + TacticalMapExtension = Extension::Singleton::Make(this_ptr); /** * Stolen bytes here. @@ -100,113 +69,52 @@ DECLARE_PATCH(_Tactical_Constructor_Patch) /** - * Patch for including the extended class members in the noinit creation process. + * Patch for including the extended class members in the destruction process. * * @warning: Do not touch this unless you know what you are doing! * * @author: CCHyper */ -DECLARE_PATCH(_Tactical_NoInit_Constructor_Patch) +DECLARE_PATCH(_Tactical_Destructor_Patch) { GET_REGISTER_STATIC(Tactical *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit, esp, 0x4); /** - * Create the extended class instance. + * Remove the extended class instance. */ - New_Tactical_Extension(this_ptr); - if (!TacticalExtension) { - DEBUG_ERROR("Failed to create TacticalExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create TacticalExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create TacticalExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. - } + Extension::Singleton::Destroy(TacticalMapExtension); /** * Stolen bytes here. */ original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { ret 4 } + this_ptr->AbstractClass::~AbstractClass(); + _asm { ret } } /** - * Patch for including the extended class members in the destruction process. + * Patch for including the extended class members in the virtual destruction process. * * @warning: Do not touch this unless you know what you are doing! * * @author: CCHyper */ -DECLARE_PATCH(_Tactical_Destructor_Patch) +DECLARE_PATCH(_Tactical_Scalar_Destructor_Patch) { GET_REGISTER_STATIC(Tactical *, this_ptr, esi); /** * Remove the extended class instance. */ - Delete_Tactical_Extension(); + Extension::Singleton::Destroy(TacticalMapExtension); /** * Stolen bytes here. */ original_code: this_ptr->AbstractClass::~AbstractClass(); - _asm { ret } -} - - -/** - * A fake class for implementing new member functions which allow - * access to the "this" pointer of the intended class. - * - * @note: This must not contain a constructor or destructor. - * - * @note: All functions must not be virtual and must also be prefixed - * with "_" to prevent accidental virtualization. - */ -static class FakeTacticalClass final : public Tactical -{ - public: - void _Detach(TARGET target, bool all); - void _Compute_CRC(WWCRCEngine &crc); -}; - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -void FakeTacticalClass::_Detach(TARGET target, bool all) -{ - Tactical::Detach(target, all); - - if (TacticalExtension) { - TacticalExtension->Detach(target, all); - } -} - - -/** - * Patch for including the extended class members to the base class crc calculation. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -void FakeTacticalClass::_Compute_CRC(WWCRCEngine &crc) -{ - AbstractClass::Compute_CRC(crc); - - if (TacticalExtension) { - TacticalExtension->Compute_CRC(crc); - } + JMP(0x0061802F); } @@ -216,8 +124,6 @@ void FakeTacticalClass::_Compute_CRC(WWCRCEngine &crc) void TacticalExtension_Init() { Patch_Jump(0x0060F08A, &_Tactical_Constructor_Patch); - Patch_Jump(0x0060F0C5, &_Tactical_NoInit_Constructor_Patch); Patch_Jump(0x0060F0E7, &_Tactical_Destructor_Patch); - Change_Virtual_Address(0x006D7720, Get_Func_Address(&FakeTacticalClass::_Detach)); - Change_Virtual_Address(0x006D7730, Get_Func_Address(&FakeTacticalClass::_Compute_CRC)); + Patch_Jump(0x0061802A, &_Tactical_Scalar_Destructor_Patch); } diff --git a/src/extensions/techno/technoext.cpp b/src/extensions/techno/technoext.cpp index 3fbd906c..2fc373dd 100644 --- a/src/extensions/techno/technoext.cpp +++ b/src/extensions/techno/technoext.cpp @@ -34,30 +34,21 @@ #include "ebolt.h" #include "tibsun_inline.h" #include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all TechnoClass extension instances. - */ -ExtensionMap TechnoClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -TechnoClassExtension::TechnoClassExtension(TechnoClass *this_ptr) : - Extension(this_ptr), +TechnoClassExtension::TechnoClassExtension(const TechnoClass *this_ptr) : + ObjectClassExtension(this_ptr), ElectricBolt(nullptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("TechnoClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - - IsInitialized = true; + //if (this_ptr) EXT_DEBUG_TRACE("TechnoClassExtension::TechnoClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -67,9 +58,9 @@ TechnoClassExtension::TechnoClassExtension(TechnoClass *this_ptr) : * @author: CCHyper */ TechnoClassExtension::TechnoClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("TechnoClassExtension::TechnoClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -80,10 +71,9 @@ TechnoClassExtension::TechnoClassExtension(const NoInitClass &noinit) : */ TechnoClassExtension::~TechnoClassExtension() { - //EXT_DEBUG_TRACE("TechnoClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("TechnoClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoClassExtension::~TechnoClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + ElectricBolt = nullptr; } @@ -94,16 +84,13 @@ TechnoClassExtension::~TechnoClassExtension() */ HRESULT TechnoClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } - new (this) TechnoClassExtension(NoInitClass()); - ElectricBolt = nullptr; return hr; @@ -117,10 +104,9 @@ HRESULT TechnoClassExtension::Load(IStream *pStm) */ HRESULT TechnoClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -132,20 +118,6 @@ HRESULT TechnoClassExtension::Save(IStream *pStm, BOOL fClearDirty) } -/** - * Return the raw size of class data for save/load purposes. - * - * @author: CCHyper - */ -int TechnoClassExtension::Size_Of() const -{ - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - - return sizeof(*this); -} - - /** * Removes the specified target from any targeting and reference trackers. * @@ -153,8 +125,9 @@ int TechnoClassExtension::Size_Of() const */ void TechnoClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + ObjectClassExtension::Detach(target, all); } @@ -165,8 +138,9 @@ void TechnoClassExtension::Detach(TARGET target, bool all) */ void TechnoClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + ObjectClassExtension::Compute_CRC(crc); } @@ -177,22 +151,21 @@ void TechnoClassExtension::Compute_CRC(WWCRCEngine &crc) const */ void TechnoClassExtension::Response_Capture() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoClassExtension::Response_Capture - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoClassExtension::Response_Capture - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); if (!AllowVoice) { return; } - //if (!ThisPtr->House->Is_Player_Control()) { + //if (!This()->House->Is_Player_Control()) { // return; //} VocType response = VOC_NONE; - TechnoTypeClass *technotype = ThisPtr->Techno_Type_Class(); - TechnoTypeClassExtension *technotypeext = TechnoTypeClassExtensions.find(technotype); - if (technotypeext && technotypeext->VoiceCapture.Count() > 0) { + const TechnoTypeClass *technotype = Techno_Type_Class(); + const TechnoTypeClassExtension *technotypeext = Extension::Fetch(technotype); + if (technotypeext->VoiceCapture.Count() > 0) { response = technotypeext->VoiceCapture[Sim_Random_Pick(0, technotypeext->VoiceCapture.Count()-1)]; @@ -213,22 +186,21 @@ void TechnoClassExtension::Response_Capture() */ void TechnoClassExtension::Response_Enter() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoClassExtension::Response_Enter - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoClassExtension::Response_Enter - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); if (!AllowVoice) { return; } - //if (!ThisPtr->House->Is_Player_Control()) { + //if (!This()->House->Is_Player_Control()) { // return; //} VocType response = VOC_NONE; - TechnoTypeClass *technotype = ThisPtr->Techno_Type_Class(); - TechnoTypeClassExtension *technotypeext = TechnoTypeClassExtensions.find(technotype); - if (technotypeext && technotypeext->VoiceEnter.Count() > 0) { + const TechnoTypeClass *technotype = Techno_Type_Class(); + const TechnoTypeClassExtension *technotypeext = Extension::Fetch(technotype); + if (technotypeext->VoiceEnter.Count() > 0) { response = technotypeext->VoiceEnter[Sim_Random_Pick(0, technotypeext->VoiceEnter.Count()-1)]; @@ -249,22 +221,21 @@ void TechnoClassExtension::Response_Enter() */ void TechnoClassExtension::Response_Deploy() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoClassExtension::Response_Deploy - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoClassExtension::Response_Deploy - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); if (!AllowVoice) { return; } - //if (!ThisPtr->House->Is_Player_Control()) { + //if (!This()->House->Is_Player_Control()) { // return; //} VocType response = VOC_NONE; - TechnoTypeClass *technotype = ThisPtr->Techno_Type_Class(); - TechnoTypeClassExtension *technotypeext = TechnoTypeClassExtensions.find(technotype); - if (technotypeext && technotypeext->VoiceDeploy.Count() > 0) { + const TechnoTypeClass *technotype = Techno_Type_Class(); + const TechnoTypeClassExtension *technotypeext = Extension::Fetch(technotype); + if (technotypeext->VoiceDeploy.Count() > 0) { response = technotypeext->VoiceDeploy[Sim_Random_Pick(0, technotypeext->VoiceDeploy.Count()-1)]; @@ -285,22 +256,21 @@ void TechnoClassExtension::Response_Deploy() */ void TechnoClassExtension::Response_Harvest() { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoClassExtension::Response_Harvest - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoClassExtension::Response_Harvest - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); if (!AllowVoice) { return; } - //if (!ThisPtr->House->Is_Player_Control()) { + //if (!This()->House->Is_Player_Control()) { // return; //} VocType response = VOC_NONE; - TechnoTypeClass *technotype = ThisPtr->Techno_Type_Class(); - TechnoTypeClassExtension *technotypeext = TechnoTypeClassExtensions.find(technotype); - if (technotypeext && technotypeext->VoiceHarvest.Count() > 0) { + const TechnoTypeClass *technotype = Techno_Type_Class(); + const TechnoTypeClassExtension *technotypeext = Extension::Fetch(technotype); + if (technotypeext->VoiceHarvest.Count() > 0) { response = technotypeext->VoiceHarvest[Sim_Random_Pick(0, technotypeext->VoiceHarvest.Count()-1)]; @@ -321,18 +291,24 @@ void TechnoClassExtension::Response_Harvest() */ bool TechnoClassExtension::Can_Passive_Acquire() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoClassExtension::Can_Passive_Acquire - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoClassExtension::Can_Passive_Acquire - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - TechnoTypeClass *technotype = ThisPtr->Techno_Type_Class(); - TechnoTypeClassExtension *technotypeext = TechnoTypeClassExtensions.find(technotype); - - if (technotypeext) { - return technotypeext->IsCanPassiveAcquire; - } + const TechnoTypeClass *technotype = Techno_Type_Class(); + const TechnoTypeClassExtension *technotypeext = Extension::Fetch(technotype); /** - * Original behaviour, all units can passive acquire. + * IsCanPassiveAcquire defaults to true to copy original behaviour, so all units can passive acquire unless told otherwise. */ - return true; + return technotypeext->IsCanPassiveAcquire; +} + + +/** + * Provides access to the TechnoTypeClass instance for this extension. + * + * @author: CCHyper + */ +const TechnoTypeClass *TechnoClassExtension::Techno_Type_Class() const +{ + return reinterpret_cast(This())->Techno_Type_Class(); } diff --git a/src/extensions/techno/technoext.h b/src/extensions/techno/technoext.h index 68cca83c..4d09c1d1 100644 --- a/src/extensions/techno/technoext.h +++ b/src/extensions/techno/technoext.h @@ -27,24 +27,25 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" -#include "techno.h" +#include "objectext.h" class EBoltClass; -class TechnoClassExtension final : public Extension +class TechnoClassExtension : public ObjectClassExtension { public: - TechnoClassExtension(TechnoClass *this_ptr); - TechnoClassExtension(const NoInitClass &noinit); - ~TechnoClassExtension(); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; - virtual int Size_Of() const override; + public: + TechnoClassExtension(const TechnoClass *this_ptr); + TechnoClassExtension(const NoInitClass &noinit); + virtual ~TechnoClassExtension(); virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; @@ -58,12 +59,12 @@ class TechnoClassExtension final : public Extension void Response_Harvest(); bool Can_Passive_Acquire() const; + private: + const TechnoTypeClass *Techno_Type_Class() const; + public: /** * The current electric bolt instance fired by this object. */ EBoltClass *ElectricBolt; }; - - -extern ExtensionMap TechnoClassExtensions; diff --git a/src/extensions/techno/technoext_functions.cpp b/src/extensions/techno/technoext_functions.cpp index f950fefb..09bc28d3 100644 --- a/src/extensions/techno/technoext_functions.cpp +++ b/src/extensions/techno/technoext_functions.cpp @@ -29,9 +29,11 @@ #include "technoext.h" #include "technotypeext.h" #include "techno.h" +#include "tibsun_globals.h" #include "ebolt.h" #include "target.h" #include "tactical.h" +#include "extension.h" #include "debughandler.h" #include "asserthandler.h" @@ -95,22 +97,19 @@ EBoltClass *TechnoClassExtension_Electric_Bolt(TechnoClass *this_ptr, TARGET tar if (ebolt) { if (this_ptr->IsActive) { - TechnoClassExtension *technoext; - technoext = TechnoClassExtensions.find(this_ptr); - if (technoext) { - - /** - * Remove existing electric bolt from the object. - */ - if (technoext->ElectricBolt) { - technoext->ElectricBolt->Flag_To_Delete(); - technoext->ElectricBolt = nullptr; - } - - if (!technoext->ElectricBolt) { - technoext->ElectricBolt = ebolt; - technoext->ElectricBolt->Set_Properties(this_ptr, weapontype, which); - } + TechnoClassExtension *technoext = Extension::Fetch(this_ptr); + + /** + * Remove existing electric bolt from the object. + */ + if (technoext->ElectricBolt) { + technoext->ElectricBolt->Flag_To_Delete(); + technoext->ElectricBolt = nullptr; + } + + if (!technoext->ElectricBolt) { + technoext->ElectricBolt = ebolt; + technoext->ElectricBolt->Set_Properties(this_ptr, weapontype, which); } } } diff --git a/src/extensions/techno/technoext_hooks.cpp b/src/extensions/techno/technoext_hooks.cpp index 56ebec06..cf4afa7f 100644 --- a/src/extensions/techno/technoext_hooks.cpp +++ b/src/extensions/techno/technoext_hooks.cpp @@ -26,7 +26,6 @@ * ******************************************************************************/ #include "technoext_hooks.h" -#include "technoext_init.h" #include "technoext_functions.h" #include "technoext.h" #include "techno.h" @@ -46,8 +45,9 @@ #include "infantrytype.h" #include "infantrytypeext.h" #include "voc.h" -#include "fatal.h" #include "vinifera_util.h" +#include "extension.h" +#include "fatal.h" #include "asserthandler.h" #include "debughandler.h" @@ -67,12 +67,12 @@ DECLARE_PATCH(_TechnoClass_Is_Allowed_To_Retaliate_Can_Retaliate_Patch) GET_REGISTER_STATIC(TechnoClass *, this_ptr, esi); static TechnoTypeClassExtension *technotypeext; - technotypeext = TechnoTypeClassExtensions.find(this_ptr->Techno_Type_Class()); + technotypeext = Extension::Fetch(this_ptr->Techno_Type_Class()); /** * If this unit is flagged as no being allowed to retaliate to attacks, return false. */ - if (technotypeext && !technotypeext->IsCanRetaliate) { + if (!technotypeext->IsCanRetaliate) { goto return_FALSE; } @@ -106,21 +106,23 @@ DECLARE_PATCH(_TechnoClass_Fire_At_Electric_Bolt_Patch) static WeaponTypeClassExtension *weapontypeext; /** - * Stolen bytes/code. + * Spawn the electric bolt. */ - this_ptr->Reduce_Ammunition(); + weapontypeext = Extension::Fetch(weapon); + if (weapontypeext->IsElectricBolt) { + TechnoClassExtension_Electric_Bolt(this_ptr, target); /** - * Spawn the electric bolt. + * Spawn the laser. */ - weapontypeext = WeaponTypeClassExtensions.find(weapon); - if (weapontypeext) { - if (weapontypeext->IsElectricBolt) { - TechnoClassExtension_Electric_Bolt(this_ptr, target); - } + } else if (weapon->IsLaser) { + goto is_laser; } - JMP_REG(edx, 0x006312D7); + JMP(0x006312CD); + +is_laser: + JMP_REG(edi, 0x00631231); } @@ -148,46 +150,44 @@ DECLARE_PATCH(_TechnoClass_Fire_At_Suicide_Patch) } /** - * Fetch the extended data for the firing weapon. + * Fetch the extension instance for the firing weapon. + */ + weapontypeext = Extension::Fetch(weap); + + /** + * Firing unit must be active in the game world when performing suicide. */ - weapontypeext = WeaponTypeClassExtensions.find(weap); - if (weapontypeext) { + if (this_ptr->IsActive && !this_ptr->IsInLimbo) { /** - * Firing unit must be active in the game world when performing suicide. + * Explicitly delete the unit from the game world at this very moment. + * This is legacy behavior similar to that of Red Alert. */ - if (this_ptr->IsActive && !this_ptr->IsInLimbo) { + if (weapontypeext->IsSuicide && weapontypeext->IsDeleteOnSuicide) { + DEV_DEBUG_INFO("Deleted: %s\n", this_ptr->Name()); + this_ptr->entry_E4(); - /** - * Explicitly delete the unit from the game world at this very moment. - * This is legacy behavior similar to that of Red Alert. - */ - if (weapontypeext->IsSuicide && weapontypeext->IsDeleteOnSuicide) { - DEV_DEBUG_INFO("Deleted: %s\n", this_ptr->Name()); - this_ptr->entry_E4(); + /** + * Deal full damage to the firing unit. The removal of the unit will + * go though the normal damage handling code. + */ + } else if (weapontypeext->IsSuicide) { /** - * Deal full damage to the firing unit. The removal of the unit will - * go though the normal damage handling code. + * #TODO: + * We have to skip aircraft as they crash the game because + * they do not get removed correctly after taking full damage. + * + * This same crash happens in Red Alert 2 also, possible engine bug. */ - } else if (weapontypeext->IsSuicide) { - - /** - * #TODO: - * We have to skip aircraft as they crash the game because - * they do not get removed correctly after taking full damage. - * - * This same crash happens in Red Alert 2 also, possible engine bug. - */ - if (this_ptr->What_Am_I() == RTTI_AIRCRAFT) { - goto limpet_check; - } - - damage = this_ptr->Techno_Type_Class()->MaxStrength; - this_ptr->Take_Damage(damage, 0, Rule->C4Warhead, nullptr, true, false); + if (this_ptr->What_Am_I() == RTTI_AIRCRAFT) { + goto limpet_check; } + damage = this_ptr->Techno_Type_Class()->MaxStrength; + this_ptr->Take_Damage(damage, 0, Rule->C4Warhead, nullptr, true, false); } + } /** @@ -221,8 +221,7 @@ static void Techno_Player_Assign_Mission_Response_Switch(TechnoClass *this_ptr, return; } - TechnoClassExtension *technoext; - technoext = TechnoClassExtensions.find(this_ptr); + TechnoClassExtension *technoext = Extension::Fetch(this_ptr); switch (mission) { @@ -241,35 +240,19 @@ static void Techno_Player_Assign_Mission_Response_Switch(TechnoClass *this_ptr, * Implements VoiceCapture, VoiceEnter, VoiceDeploy and VoiceHarvest. */ case MISSION_CAPTURE: - if (technoext) { - technoext->Response_Capture(); - } else { - this_ptr->Response_Move(); - } + technoext->Response_Capture(); break; case MISSION_ENTER: - if (technoext) { - technoext->Response_Enter(); - } else { - this_ptr->Response_Move(); - } + technoext->Response_Enter(); break; case MISSION_UNLOAD: - if (technoext) { - technoext->Response_Deploy(); - } else { - this_ptr->Response_Move(); - } + technoext->Response_Deploy(); break; case MISSION_HARVEST: - if (technoext) { - technoext->Response_Harvest(); - } else { - this_ptr->Response_Move(); - } + technoext->Response_Harvest(); break; } } @@ -313,14 +296,14 @@ DECLARE_PATCH(_TechnoClass_Refund_Amount_Soylent_Patch) technotype = this_ptr->Techno_Type_Class(); /** - * Fetch the techno type extension. + * Fetch the extension instance. */ - technotypext = TechnoTypeClassExtensions.find(technotype); + technotypext = Extension::Fetch(technotype); /** * If the object has a soylent value defined, return this. */ - if (technotypext && technotypext->SoylentValue > 0) { + if (technotypext->SoylentValue > 0) { cost = technotypext->SoylentValue; goto return_amount; } @@ -364,10 +347,10 @@ DECLARE_PATCH(_TechnoClass_Greatest_Threat_Infantry_Mechanic_Patch) * #NOTE: Removed THREAT_AIR for IsMechanic and IsOmniHealer infantry and it causes * them to chase down damaged friendly aircraft in the air. */ - infantrytypeext = InfantryTypeClassExtensions.find(infantry_this_ptr->Class); - if (infantrytypeext && infantrytypeext->IsOmniHealer) { + infantrytypeext = Extension::Fetch(infantry_this_ptr->Class); + if (infantrytypeext->IsOmniHealer) { method = method|(THREAT_INFANTRY|THREAT_VEHICLES/*|THREAT_AIR*/|THREAT_4000); - } else if (infantrytypeext && infantrytypeext->IsMechanic) { + } else if (infantrytypeext->IsMechanic) { method = method|(THREAT_VEHICLES/*|THREAT_AIR*/|THREAT_4000); } else { method = method|(THREAT_INFANTRY|THREAT_4000); @@ -452,8 +435,8 @@ DECLARE_PATCH(_TechnoClass_Take_Damage_IsAffectsAllies_Patch) /** * Is the warhead that hit us one that affects units allied with its firing owner? */ - warheadtypeext = WarheadTypeClassExtensions.find(warhead); - if (warheadtypeext && !warheadtypeext->IsAffectsAllies) { + warheadtypeext = Extension::Fetch(warhead); + if (!warheadtypeext->IsAffectsAllies) { /** * If the source of the damage is an ally of ours, then reset @@ -609,17 +592,15 @@ DECLARE_PATCH(_TechnoClass_Do_Cloak_Cloak_Sound_Patch) voc = Rule->CloakSound; /** - * Fetch the class extension if it exists. + * Fetch the extension instance. */ - technotypeext = TechnoTypeClassExtensions.find(technotype); - if (technotypeext) { + technotypeext = Extension::Fetch(technotype); - /** - * Does this object have a custom cloaking sound? If so, use it. - */ - if (technotypeext->CloakSound != VOC_NONE) { - voc = technotypeext->CloakSound; - } + /** + * Does this object have a custom cloaking sound? If so, use it. + */ + if (technotypeext->CloakSound != VOC_NONE) { + voc = technotypeext->CloakSound; } /** @@ -654,17 +635,15 @@ DECLARE_PATCH(_TechnoClass_Do_Uncloak_Uncloak_Sound_Patch) voc = Rule->CloakSound; /** - * Fetch the class extension if it exists. + * Fetch the extension instance. */ - technotypeext = TechnoTypeClassExtensions.find(technotype); - if (technotypeext) { + technotypeext = Extension::Fetch(technotype); - /** - * Does this object have a custom decloaking sound? If so, use it. - */ - if (technotypeext->UncloakSound != VOC_NONE) { - voc = technotypeext->UncloakSound; - } + /** + * Does this object have a custom decloaking sound? If so, use it. + */ + if (technotypeext->UncloakSound != VOC_NONE) { + voc = technotypeext->UncloakSound; } /** @@ -710,11 +689,6 @@ DECLARE_PATCH(_TechnoClass_Null_House_Warning_Patch) */ void TechnoClassExtension_Hooks() { - /** - * Initialises the extended class. - */ - TechnoClassExtension_Init(); - Patch_Jump(0x00633C78, &_TechnoClass_Do_Cloak_Cloak_Sound_Patch); Patch_Jump(0x00633BD4, &_TechnoClass_Do_Uncloak_Uncloak_Sound_Patch); Patch_Jump(0x0063105C, &_TechnoClass_Fire_At_Weapon_Anim_Patch); @@ -727,6 +701,6 @@ void TechnoClassExtension_Hooks() Patch_Jump(0x00638095, &_TechnoClass_Refund_Amount_Soylent_Patch); Patch_Jump(0x00631661, &_TechnoClass_Player_Assign_Mission_Response_Patch); Patch_Jump(0x00630390, &_TechnoClass_Fire_At_Suicide_Patch); - Patch_Jump(0x006312CD, &_TechnoClass_Fire_At_Electric_Bolt_Patch); + Patch_Jump(0x00631223, &_TechnoClass_Fire_At_Electric_Bolt_Patch); Patch_Jump(0x00636F09, &_TechnoClass_Is_Allowed_To_Retaliate_Can_Retaliate_Patch); } diff --git a/src/extensions/techno/technoext_init.cpp b/src/extensions/techno/technoext_init.cpp deleted file mode 100644 index e7f70b47..00000000 --- a/src/extensions/techno/technoext_init.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/******************************************************************************* -/* O P E N S O U R C E -- V I N I F E R A ** -/******************************************************************************* - * - * @project Vinifera - * - * @file TECHNOEXT_INIT.CPP - * - * @author CCHyper - * - * @brief Contains the hooks for initialising the extended TechnoClass. - * - * @license Vinifera is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version - * 3 of the License, or (at your option) any later version. - * - * Vinifera is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. - * If not, see . - * - ******************************************************************************/ -#include "technoext.h" -#include "technotypeext.h" -#include "techno.h" -#include "fatal.h" -#include "asserthandler.h" -#include "debughandler.h" -#include "vinifera_util.h" - - -/** - * Patch for including the extended class members in the creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TechnoClass_Constructor_Patch) -{ - GET_REGISTER_STATIC(TechnoClass *, this_ptr, esi); // Current "this" pointer. - static TechnoClassExtension *exttype_ptr; - - /** - * Find existing or create an extended class instance. - */ - exttype_ptr = TechnoClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create TechnoClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create TechnoClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create TechnoClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. - } - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TechnoClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(TechnoClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit, esp, 0x4); - static TechnoClassExtension *ext_ptr; - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the destruction process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TechnoClass_Destructor_Patch) -{ - GET_REGISTER_STATIC(TechnoClass *, this_ptr, esi); - - /** - * Remove the extended class from the global index. - */ - TechnoClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TechnoClass_Detach_Patch) -{ - GET_REGISTER_STATIC(TechnoClass *, this_ptr, esi); - GET_STACK_STATIC(TARGET, target, esp, 0x10); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static TechnoClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = TechnoClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Detach(target, all); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { add esp, 0x0C } - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members to the base class crc calculation. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TechnoClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(TechnoClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static TechnoClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = TechnoClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Main function for patching the hooks. - */ -void TechnoClassExtension_Init() -{ - Patch_Jump(0x0062A004, _TechnoClass_Constructor_Patch); - Patch_Jump(0x0062A8CC, _TechnoClass_NoInit_Constructor_Patch); - Patch_Jump(0x0062A968, _TechnoClass_Destructor_Patch); - Patch_Jump(0x0063641C, _TechnoClass_Detach_Patch); - Patch_Jump(0x0063910C, _TechnoClass_Compute_CRC_Patch); -} diff --git a/src/extensions/technotype/technotypeext.cpp b/src/extensions/technotype/technotypeext.cpp index 00a618e2..e2a309e3 100644 --- a/src/extensions/technotype/technotypeext.cpp +++ b/src/extensions/technotype/technotypeext.cpp @@ -34,23 +34,18 @@ #include "tibsun_globals.h" #include "vinifera_util.h" #include "spritecollection.h" +#include "vinifera_saveload.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all TechnoTypeClass extension instances. - */ -ExtensionMap TechnoTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -TechnoTypeClassExtension::TechnoTypeClassExtension(TechnoTypeClass *this_ptr) : - Extension(this_ptr), +TechnoTypeClassExtension::TechnoTypeClassExtension(const TechnoTypeClass *this_ptr) : + ObjectTypeClassExtension(this_ptr), CloakSound(VOC_NONE), UncloakSound(VOC_NONE), IsShakeScreen(false), @@ -72,11 +67,7 @@ TechnoTypeClassExtension::TechnoTypeClassExtension(TechnoTypeClass *this_ptr) : IdleRate(0), CameoImageSurface(nullptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("TechnoTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - - IsInitialized = true; + //if (this_ptr) EXT_DEBUG_TRACE("TechnoTypeClassExtension::TechnoTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -86,9 +77,9 @@ TechnoTypeClassExtension::TechnoTypeClassExtension(TechnoTypeClass *this_ptr) : * @author: CCHyper */ TechnoTypeClassExtension::TechnoTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("TechnoTypeClassExtension::TechnoTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -99,13 +90,10 @@ TechnoTypeClassExtension::TechnoTypeClassExtension(const NoInitClass &noinit) : */ TechnoTypeClassExtension::~TechnoTypeClassExtension() { - //EXT_DEBUG_TRACE("TechnoTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("TechnoTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoTypeClassExtension::~TechnoTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); delete CameoImageSurface; CameoImageSurface = nullptr; - - IsInitialized = false; } @@ -116,24 +104,21 @@ TechnoTypeClassExtension::~TechnoTypeClassExtension() */ HRESULT TechnoTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } - new (this) TechnoTypeClassExtension(NoInitClass()); - - SWIZZLE_REQUEST_POINTER_REMAP(UnloadingClass); + VINIFERA_SWIZZLE_REQUEST_POINTER_REMAP(UnloadingClass, "UnloadingClass"); /** * We need to reload the "Cameo" key because TechnoTypeClass does * not store the entry value. */ - const char *ini_name = ThisPtr->Name(); - const char *graphic_name = ThisPtr->Graphic_Name(); + const char *ini_name = IniName; + const char *graphic_name = GraphicName; char cameo_buffer[32]; @@ -163,10 +148,9 @@ HRESULT TechnoTypeClassExtension::Load(IStream *pStm) */ HRESULT TechnoTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -176,16 +160,24 @@ HRESULT TechnoTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) /** - * Return the raw size of class data for save/load purposes. - * - * @author: CCHyper + * Retrieves the size of the stream needed to save the object. + * + * @author: CCHyper, tomsons26 */ -int TechnoTypeClassExtension::Size_Of() const +LONG TechnoTypeClassExtension::GetSizeMax(ULARGE_INTEGER *pcbSize) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("AbstractClassExtension::GetSizeMax - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (!pcbSize) { + return E_POINTER; + } - return sizeof(*this); + pcbSize->LowPart += VoiceCapture.Count() * sizeof(uint32_t); + pcbSize->LowPart += VoiceEnter.Count() * sizeof(uint32_t); + pcbSize->LowPart += VoiceDeploy.Count() * sizeof(uint32_t); + pcbSize->LowPart += VoiceHarvest.Count() * sizeof(uint32_t); + + return S_OK; } @@ -196,8 +188,7 @@ int TechnoTypeClassExtension::Size_Of() const */ void TechnoTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -208,8 +199,7 @@ void TechnoTypeClassExtension::Detach(TARGET target, bool all) */ void TechnoTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TechnoTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); crc(IsShakeScreen); crc(IsImmuneToEMP); @@ -228,17 +218,15 @@ void TechnoTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool TechnoTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TechnoTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("TechnoTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - - const char *ini_name = ThisPtr->Name(); - const char *graphic_name = ThisPtr->Graphic_Name(); + //EXT_DEBUG_TRACE("TechnoTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - if (!ini.Is_Present(ini_name)) { + if (!ObjectTypeClassExtension::Read_INI(ini)) { return false; } + const char *ini_name = Name(); + const char *graphic_name = Graphic_Name(); + //if (!ArtINI.Is_Present(graphic_name)) { // return false; //} @@ -251,7 +239,7 @@ bool TechnoTypeClassExtension::Read_INI(CCINIClass &ini) * * @author: CCHyper */ - ThisPtr->WalkRate = ArtINI.Get_Int(graphic_name, "WalkRate", ThisPtr->WalkRate); + This()->WalkRate = ArtINI.Get_Int(graphic_name, "WalkRate", This()->WalkRate); CloakSound = ini.Get_VocType(ini_name, "CloakSound", CloakSound); UncloakSound = ini.Get_VocType(ini_name, "UncloakSound", UncloakSound); @@ -278,7 +266,7 @@ bool TechnoTypeClassExtension::Read_INI(CCINIClass &ini) /** * Fetch the cameo image surface if it exists. */ - BSurface *imagesurface = Vinifera_Get_Image_Surface(ThisPtr->CameoFilename); + BSurface *imagesurface = Vinifera_Get_Image_Surface(This()->CameoFilename); if (imagesurface) { CameoImageSurface = imagesurface; } diff --git a/src/extensions/technotype/technotypeext.h b/src/extensions/technotype/technotypeext.h index 233791d8..2b3b6c48 100644 --- a/src/extensions/technotype/technotypeext.h +++ b/src/extensions/technotype/technotypeext.h @@ -27,32 +27,37 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "objecttypeext.h" +#include "technotype.h" #include "typelist.h" #include "tibsun_defines.h" -class TechnoTypeClass; -class CCINIClass; class BSurface; -class TechnoTypeClassExtension final : public Extension +class TechnoTypeClassExtension : public ObjectTypeClassExtension { public: - TechnoTypeClassExtension(TechnoTypeClass *this_ptr); - TechnoTypeClassExtension(const NoInitClass &noinit); - ~TechnoTypeClassExtension(); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + IFACEMETHOD_(LONG, GetSizeMax)(ULARGE_INTEGER *pcbSize); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; - virtual int Size_Of() const override; + public: + TechnoTypeClassExtension(const TechnoTypeClass *this_ptr); + TechnoTypeClassExtension(const NoInitClass &noinit); + virtual ~TechnoTypeClassExtension(); virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual TechnoTypeClass *This() const override { return reinterpret_cast(ObjectTypeClassExtension::This()); } + virtual const TechnoTypeClass *This_Const() const override { return reinterpret_cast(ObjectTypeClassExtension::This_Const()); } + + virtual bool Read_INI(CCINIClass &ini) override; public: /** @@ -147,6 +152,3 @@ class TechnoTypeClassExtension final : public Extension */ BSurface *CameoImageSurface; }; - - -extern ExtensionMap TechnoTypeClassExtensions; diff --git a/src/extensions/technotype/technotypeext_hooks.cpp b/src/extensions/technotype/technotypeext_hooks.cpp index ad987b5a..dfede5ae 100644 --- a/src/extensions/technotype/technotypeext_hooks.cpp +++ b/src/extensions/technotype/technotypeext_hooks.cpp @@ -26,7 +26,6 @@ * ******************************************************************************/ #include "technotypeext_hooks.h" -#include "technotypeext_init.h" #include "technotypeext.h" #include "technotype.h" #include "fatal.h" @@ -39,8 +38,4 @@ */ void TechnoTypeClassExtension_Hooks() { - /** - * Initialises the extended class. - */ - TechnoTypeClassExtension_Init(); } diff --git a/src/extensions/technotype/technotypeext_init.cpp b/src/extensions/technotype/technotypeext_init.cpp deleted file mode 100644 index 192ac24d..00000000 --- a/src/extensions/technotype/technotypeext_init.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/******************************************************************************* -/* O P E N S O U R C E -- V I N I F E R A ** -/******************************************************************************* - * - * @project Vinifera - * - * @file TECHNOTYPEEXT_INIT.CPP - * - * @author CCHyper - * - * @brief Contains the hooks for initialising the extended TechnoTypeClass. - * - * @license Vinifera is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version - * 3 of the License, or (at your option) any later version. - * - * Vinifera is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. - * If not, see . - * - ******************************************************************************/ -#include "technotypeext_hooks.h" -#include "technotypeext.h" -#include "technotype.h" -#include "tibsun_globals.h" -#include "vinifera_util.h" -#include "fatal.h" -#include "debughandler.h" -#include "asserthandler.h" - - -/** - * Patch for including the extended class members in the creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TechnoTypeClass_Constructor_Patch) -{ - GET_REGISTER_STATIC(TechnoTypeClass *, this_ptr, esi); // "this" pointer. - GET_STACK_STATIC(const char *, ini_name, esp, 0x10); // ini name. - GET_STACK_STATIC(SpeedType, speed, esp, 0x14); // SpeedType. - static TechnoTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating TechnoTypeClassExtension instance for \"%s\".\n", ini_name); - - /** - * Find existing or create an extended class instance. - */ - exttype_ptr = TechnoTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create TechnoTypeClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create TechnoTypeClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create TechnoTypeClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. - } - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TechnoTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(TechnoTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the destruction process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TechnoTypeClass_Destructor_Patch) -{ - GET_REGISTER_STATIC(TechnoTypeClass *, this_ptr, esi); - - /** - * Remove the extended class from the global index. - */ - TechnoTypeClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop esi } - _asm { pop ebx } - _asm { pop ecx } - _asm { ret } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TechnoTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(TechnoTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static TechnoTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = TechnoTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TechnoTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(TechnoTypeClass *, this_ptr, ebp); - GET_REGISTER_STATIC(CCINIClass *, ini, esi); - static TechnoTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = TechnoTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov al, 1 } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { add esp, 0x2EC } - _asm { ret 4 } -} - - -/** - * Main function for patching the hooks. - */ -void TechnoTypeClassExtension_Init() -{ - Patch_Jump(0x0063B46C, &_TechnoTypeClass_Constructor_Patch); - Patch_Jump(0x0063B5E2, &_TechnoTypeClass_NoInit_Constructor_Patch); - Patch_Jump(0x0063B87B, &_TechnoTypeClass_Destructor_Patch); - Patch_Jump(0x0063E6A3, &_TechnoTypeClass_Compute_CRC_Patch); - Patch_Jump(0x0063D2F3, &_TechnoTypeClass_Read_INI_Patch); -} diff --git a/src/extensions/terrain/terrainext.cpp b/src/extensions/terrain/terrainext.cpp index 5e2a3188..6401cec1 100644 --- a/src/extensions/terrain/terrainext.cpp +++ b/src/extensions/terrain/terrainext.cpp @@ -27,33 +27,25 @@ ******************************************************************************/ #include "terrainext.h" #include "terrain.h" -#include "wwcrc.h" #include "lightsource.h" +#include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all TerrainClass extension instances. - */ -ExtensionMap TerrainClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -TerrainClassExtension::TerrainClassExtension(TerrainClass *this_ptr) : - Extension(this_ptr), - +TerrainClassExtension::TerrainClassExtension(const TerrainClass *this_ptr) : + ObjectClassExtension(this_ptr), LightSource(nullptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TerrainClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("TerrainClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("TerrainClassExtension::TerrainClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + TerrainExtensions.Add(this); } @@ -63,9 +55,9 @@ TerrainClassExtension::TerrainClassExtension(TerrainClass *this_ptr) : * @author: CCHyper */ TerrainClassExtension::TerrainClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("TerrainClassExtension::TerrainClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -76,8 +68,7 @@ TerrainClassExtension::TerrainClassExtension(const NoInitClass &noinit) : */ TerrainClassExtension::~TerrainClassExtension() { - //EXT_DEBUG_TRACE("TerrainClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("TerrainClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TerrainClassExtension::~TerrainClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); if (LightSource) { LightSource->Disable(); @@ -85,7 +76,26 @@ TerrainClassExtension::~TerrainClassExtension() LightSource = nullptr; } - IsInitialized = false; + TerrainExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT TerrainClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("TerrainClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -96,10 +106,9 @@ TerrainClassExtension::~TerrainClassExtension() */ HRESULT TerrainClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TerrainClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TerrainClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -119,10 +128,9 @@ HRESULT TerrainClassExtension::Load(IStream *pStm) */ HRESULT TerrainClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TerrainClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TerrainClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -138,8 +146,7 @@ HRESULT TerrainClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int TerrainClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TerrainClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TerrainClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -152,8 +159,7 @@ int TerrainClassExtension::Size_Of() const */ void TerrainClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TerrainClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TerrainClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -164,6 +170,5 @@ void TerrainClassExtension::Detach(TARGET target, bool all) */ void TerrainClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TerrainClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TerrainClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } diff --git a/src/extensions/terrain/terrainext.h b/src/extensions/terrain/terrainext.h index ea3202aa..313d9b44 100644 --- a/src/extensions/terrain/terrainext.h +++ b/src/extensions/terrain/terrainext.h @@ -27,34 +27,44 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "objectext.h" #include "terrain.h" class LightSourceClass; -class TerrainClassExtension final : public Extension +class DECLSPEC_UUID(UUID_TERRAIN_EXTENSION) +TerrainClassExtension final : public ObjectClassExtension { public: - TerrainClassExtension(TerrainClass *this_ptr); + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + TerrainClassExtension(const TerrainClass *this_ptr = nullptr); TerrainClassExtension(const NoInitClass &noinit); - ~TerrainClassExtension(); + virtual ~TerrainClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + virtual TerrainClass *This() const override { return reinterpret_cast(ObjectClassExtension::This()); } + virtual const TerrainClass *This_Const() const override { return reinterpret_cast(ObjectClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_TERRAIN; } + public: /** * The light source instance for this terrain object. */ LightSourceClass *LightSource; }; - - -extern ExtensionMap TerrainClassExtensions; diff --git a/src/extensions/terrain/terrainext_hooks.cpp b/src/extensions/terrain/terrainext_hooks.cpp index 3f32ef02..9af6dee9 100644 --- a/src/extensions/terrain/terrainext_hooks.cpp +++ b/src/extensions/terrain/terrainext_hooks.cpp @@ -32,10 +32,11 @@ #include "terrain.h" #include "terraintype.h" #include "lightsource.h" +#include "vinifera_util.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" -#include "vinifera_util.h" #include "hooker.h" #include "hooker_macros.h" @@ -57,10 +58,10 @@ static LightSourceClass *Terrain_New_LightSource(TerrainClass *this_ptr) LightSourceClass *light; /** - * Fetch the extended class instances if they exist. + * Fetch the extension instance. */ - terrainext = TerrainClassExtensions.find(this_ptr); - terraintypeext = TerrainTypeClassExtensions.find(this_ptr->Class); + terrainext = Extension::Fetch(this_ptr); + terraintypeext = Extension::Fetch(this_ptr->Class); /** * Create the light source object at the terrain coord. @@ -98,14 +99,14 @@ DECLARE_PATCH(_TerrainClass_Unlimbo_LightSource_Patch) terraintype = this_ptr->Class; /** - * Fetch the extended class instances if they exist. + * Fetch the extension instances. */ - terrainext = TerrainClassExtensions.find(this_ptr); - terraintypeext = TerrainTypeClassExtensions.find(terraintype); + terrainext = Extension::Fetch(this_ptr); + terraintypeext = Extension::Fetch(terraintype); - if (terraintypeext && terraintypeext->IsLightEnabled && terraintypeext->LightIntensity > 0) { + if (terraintypeext->IsLightEnabled && terraintypeext->LightIntensity > 0) { - if (terrainext && !terrainext->LightSource) { + if (!terrainext->LightSource) { /** * Create the light source object. @@ -153,10 +154,10 @@ DECLARE_PATCH(_TerrainClass_Take_Damage_LightSource_Patch) static TerrainClassExtension *terrainext; /** - * Fetch the extended class instance if it exists. + * Fetch the extension instance. */ - terrainext = TerrainClassExtensions.find(this_ptr); - if (terrainext && terrainext->LightSource) { + terrainext = Extension::Fetch(this_ptr); + if (terrainext->LightSource) { /** * This terrain object was destroyed, disable the attached lighting. diff --git a/src/extensions/terrain/terrainext_init.cpp b/src/extensions/terrain/terrainext_init.cpp index c25f39a0..9436d476 100644 --- a/src/extensions/terrain/terrainext_init.cpp +++ b/src/extensions/terrain/terrainext_init.cpp @@ -27,10 +27,16 @@ ******************************************************************************/ #include "terrainext.h" #include "terrain.h" +#include "tibsun_globals.h" +#include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" -#include "vinifera_util.h" + +#include "hooker.h" +#include "hooker_macros.h" /** @@ -45,21 +51,20 @@ DECLARE_PATCH(_TerrainClass_Default_Constructor_Patch) GET_REGISTER_STATIC(TerrainClass *, this_ptr, esi); // Current "this" pointer. GET_STACK_STATIC(const TerrainTypeClass *, classof, esp, 0x20); GET_STACK_STATIC(const Cell *, cell, esp, 0x24); - static TerrainClassExtension *ext_ptr; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - ext_ptr = TerrainClassExtensions.find_or_create(this_ptr); - if (!ext_ptr) { - DEBUG_ERROR("Failed to create TerrainClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create TerrainClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create TerrainClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * Stolen bytes here. */ @@ -84,20 +89,11 @@ DECLARE_PATCH(_TerrainClass_Default_Constructor_Patch) DECLARE_PATCH(_TerrainClass_Constructor_Patch) { GET_REGISTER_STATIC(TerrainClass *, this_ptr, esi); // Current "this" pointer. - static TerrainClassExtension *ext_ptr; /** - * Find existing or create an extended class instance. + * Create an extended class instance. */ - ext_ptr = TerrainClassExtensions.find_or_create(this_ptr); - if (!ext_ptr) { - DEBUG_ERROR("Failed to create TerrainClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create TerrainClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create TerrainClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. - } + Extension::Make(this_ptr); /** * Stolen bytes here. @@ -127,20 +123,11 @@ DECLARE_PATCH(_TerrainClass_Constructor_Before_Unlimbo_Patch) { GET_REGISTER_STATIC(TerrainClass *, this_ptr, esi); // Current "this" pointer. GET_STACK_STATIC(Cell *, cell, esp, 0x24); - static TerrainClassExtension *ext_ptr; /** - * Find existing or create an extended class instance. + * Create an extended class instance. */ - ext_ptr = TerrainClassExtensions.find_or_create(this_ptr); - if (!ext_ptr) { - DEBUG_ERROR("Failed to create TerrainClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create TerrainClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create TerrainClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. - } + Extension::Make(this_ptr); /** * Stolen bytes here. @@ -168,16 +155,14 @@ DECLARE_PATCH(_TerrainClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - TerrainClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { add esp, 0x8 } - _asm { ret } + _asm { mov edx, ds:0x007E4568 } // Terrains.vtble + JMP_REG(eax, 0x0063F193); } @@ -195,84 +180,14 @@ DECLARE_PATCH(_TerrainClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - TerrainClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { add esp, 0x8 } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TerrainClass_Detach_Patch) -{ - GET_REGISTER_STATIC(TerrainClass *, this_ptr, esi); - GET_STACK_STATIC(TARGET, target, esp, 0x10); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static TerrainClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = TerrainClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Detach(target, all); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members to the base class crc calculation. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TerrainClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(TerrainClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static TerrainClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = TerrainClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } + _asm { mov edx, ds:0x007E4568 } // Terrains.vtble + JMP_REG(eax, 0x00640C43); } @@ -284,8 +199,6 @@ void TerrainClassExtension_Init() Patch_Jump(0x0063F88C, _TerrainClass_Default_Constructor_Patch); //Patch_Jump(0x0063F701, _TerrainClass_Constructor_Patch); Patch_Jump(0x0063F556, _TerrainClass_Constructor_Before_Unlimbo_Patch); - Patch_Jump(0x0063F2BC, _TerrainClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x00640D7C, _TerrainClass_Scalar_Destructor_Patch); - Patch_Jump(0x0064089F, _TerrainClass_Detach_Patch); - Patch_Jump(0x0064086E, _TerrainClass_Compute_CRC_Patch); + Patch_Jump(0x0063F18D, _TerrainClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x00640C3D, _TerrainClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/terraintype/terraintypeext.cpp b/src/extensions/terraintype/terraintypeext.cpp index 39a032a0..7e253a4f 100644 --- a/src/extensions/terraintype/terraintypeext.cpp +++ b/src/extensions/terraintype/terraintypeext.cpp @@ -28,23 +28,19 @@ #include "terraintypeext.h" #include "terraintype.h" #include "ccini.h" +#include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all TerrainTypeClass extension instances. - */ -ExtensionMap TerrainTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -TerrainTypeClassExtension::TerrainTypeClassExtension(TerrainTypeClass *this_ptr) : - Extension(this_ptr), +TerrainTypeClassExtension::TerrainTypeClassExtension(const TerrainTypeClass *this_ptr) : + ObjectTypeClassExtension(this_ptr), IsLightEnabled(false), LightVisibility(5000), LightIntensity(0), @@ -52,11 +48,9 @@ TerrainTypeClassExtension::TerrainTypeClassExtension(TerrainTypeClass *this_ptr) LightGreenTint(1000000), LightBlueTint(1000000) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TerrainTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("TerrainTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("TerrainTypeClassExtension::TerrainTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + TerrainTypeExtensions.Add(this); } @@ -66,9 +60,9 @@ TerrainTypeClassExtension::TerrainTypeClassExtension(TerrainTypeClass *this_ptr) * @author: CCHyper */ TerrainTypeClassExtension::TerrainTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("TerrainTypeClassExtension::TerrainTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -79,10 +73,28 @@ TerrainTypeClassExtension::TerrainTypeClassExtension(const NoInitClass &noinit) */ TerrainTypeClassExtension::~TerrainTypeClassExtension() { - //EXT_DEBUG_TRACE("TerrainTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("TerrainTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TerrainTypeClassExtension::~TerrainTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + TerrainTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT TerrainTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("TerrainTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -93,10 +105,9 @@ TerrainTypeClassExtension::~TerrainTypeClassExtension() */ HRESULT TerrainTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TerrainTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TerrainTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -114,10 +125,9 @@ HRESULT TerrainTypeClassExtension::Load(IStream *pStm) */ HRESULT TerrainTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TerrainTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TerrainTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -133,8 +143,7 @@ HRESULT TerrainTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int TerrainTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TerrainTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TerrainTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -147,8 +156,7 @@ int TerrainTypeClassExtension::Size_Of() const */ void TerrainTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TerrainTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TerrainTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -159,8 +167,7 @@ void TerrainTypeClassExtension::Detach(TARGET target, bool all) */ void TerrainTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TerrainTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TerrainTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); crc(IsLightEnabled); } @@ -173,16 +180,14 @@ void TerrainTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool TerrainTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TerrainTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("TerrainTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TerrainTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - const char *ini_name = ThisPtr->Name(); - - if (!ini.Is_Present(ini_name)) { + if (!ObjectTypeClassExtension::Read_INI(ini)) { return false; } + const char *ini_name = Name(); + IsLightEnabled = ini.Get_Bool(ini_name, "IsLightEnabled", IsLightEnabled); LightVisibility = ini.Get_Int(ini_name, "LightVisibility", LightVisibility); LightIntensity = ini.Get_Double(ini_name, "LightIntensity", (LightIntensity / 1000)) * 1000.0 + 0.1; diff --git a/src/extensions/terraintype/terraintypeext.h b/src/extensions/terraintype/terraintypeext.h index b245da02..3b3e295e 100644 --- a/src/extensions/terraintype/terraintypeext.h +++ b/src/extensions/terraintype/terraintypeext.h @@ -27,29 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "objecttypeext.h" +#include "terraintype.h" -class TerrainTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_TERRAINTYPE_EXTENSION) +TerrainTypeClassExtension final : public ObjectTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class TerrainTypeClassExtension final : public Extension -{ public: - TerrainTypeClassExtension(TerrainTypeClass *this_ptr); + TerrainTypeClassExtension(const TerrainTypeClass *this_ptr = nullptr); TerrainTypeClassExtension(const NoInitClass &noinit); - ~TerrainTypeClassExtension(); + virtual ~TerrainTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual TerrainTypeClass *This() const override { return reinterpret_cast(ObjectTypeClassExtension::This()); } + virtual const TerrainTypeClass *This_Const() const override { return reinterpret_cast(ObjectTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_TERRAINTYPE; } + + virtual bool Read_INI(CCINIClass &ini) override; public: /** @@ -82,6 +92,3 @@ class TerrainTypeClassExtension final : public Extension */ int LightBlueTint; }; - - -extern ExtensionMap TerrainTypeClassExtensions; diff --git a/src/extensions/terraintype/terraintypeext_init.cpp b/src/extensions/terraintype/terraintypeext_init.cpp index 5fff8d20..9ca57dcf 100644 --- a/src/extensions/terraintype/terraintypeext_init.cpp +++ b/src/extensions/terraintype/terraintypeext_init.cpp @@ -30,10 +30,15 @@ #include "terraintype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,43 +51,19 @@ DECLARE_PATCH(_TerrainTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(TerrainTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0xC); // ini name. - static TerrainTypeClassExtension *exttype_ptr; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = TerrainTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create TerrainTypeClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create TerrainTypeClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create TerrainTypeClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TerrainTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(TerrainTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. @@ -90,6 +71,7 @@ DECLARE_PATCH(_TerrainTypeClass_NoInit_Constructor_Patch) original_code: _asm { mov eax, this_ptr } _asm { pop esi } + _asm { pop ebx } _asm { ret 4 } } @@ -108,15 +90,14 @@ DECLARE_PATCH(_TerrainTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - TerrainTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007E3FE0 } // TerrainTypes.vtble + JMP_REG(eax, 0x0064165E); } @@ -134,91 +115,14 @@ DECLARE_PATCH(_TerrainTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - TerrainTypeClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TerrainTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(TerrainTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static TerrainTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = TerrainTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TerrainTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(TerrainTypeClass *, this_ptr, esi); - GET_REGISTER_STATIC(CCINIClass *, ini, ebp); - static TerrainTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = TerrainTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { mov al, 1 } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { add esp, 0x204 } - _asm { ret 4 } + _asm { mov edx, ds:0x007E3FE0 } // TerrainTypes.vtble + JMP_REG(eax, 0x00641D8E); } @@ -228,9 +132,6 @@ DECLARE_PATCH(_TerrainTypeClass_Read_INI_Patch) void TerrainTypeClassExtension_Init() { Patch_Jump(0x00641619, &_TerrainTypeClass_Constructor_Patch); - Patch_Jump(0x0064163A, &_TerrainTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x006416A8, &_TerrainTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x00641DE8, &_TerrainTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x00641B6E, &_TerrainTypeClass_Compute_CRC_Patch); - Patch_Jump(0x00641A63, &_TerrainTypeClass_Read_INI_Patch); + //Patch_Jump(0x00641658, &_TerrainTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x00641D88, &_TerrainTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/textlabel/txtlabelext_hooks.cpp b/src/extensions/textlabel/txtlabelext_hooks.cpp index 8b37e6ad..4a6ac2bd 100644 --- a/src/extensions/textlabel/txtlabelext_hooks.cpp +++ b/src/extensions/textlabel/txtlabelext_hooks.cpp @@ -47,7 +47,7 @@ * @note: This must not contain a constructor or destructor! * @note: All functions must be prefixed with "_" to prevent accidental virtualization. */ -class TextLabelClassFake final : public TextLabelClass +class TextLabelClassExt final : public TextLabelClass { public: bool _Draw_Me(bool forced = false); @@ -59,7 +59,7 @@ class TextLabelClassFake final : public TextLabelClass * * @author: CCHyper */ -bool TextLabelClassFake::_Draw_Me(bool forced) +bool TextLabelClassExt::_Draw_Me(bool forced) { if (!GadgetClass::Draw_Me(forced)) { return false; @@ -146,5 +146,5 @@ bool TextLabelClassFake::_Draw_Me(bool forced) */ void TextLabelClassExtension_Hooks() { - Patch_Jump(0x0064D120, &TextLabelClassFake::_Draw_Me); + Patch_Jump(0x0064D120, &TextLabelClassExt::_Draw_Me); } diff --git a/src/extensions/theme/themeext.cpp b/src/extensions/theme/themeext.cpp index 35a1ec92..73a57d77 100644 --- a/src/extensions/theme/themeext.cpp +++ b/src/extensions/theme/themeext.cpp @@ -32,26 +32,16 @@ #include "debughandler.h" -/** - * Provides the map for all ThemeControlClass extension instances. - */ -ExtensionMap ThemeControlExtensions; - - /** * Class constructor. * * @author: CCHyper */ -ThemeControlExtension::ThemeControlExtension(ThemeClass::ThemeControl *this_ptr) : - Extension(this_ptr), +ThemeControlExtension::ThemeControlExtension(const ThemeClass::ThemeControl *this_ptr) : + GlobalExtensionClass(this_ptr), RequiredAddon(ADDON_NONE) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ThemeControlExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name, (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("ThemeControlExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name, (uintptr_t)(ThisPtr)); - - IsInitialized = true; + //EXT_DEBUG_TRACE("ThemeControlExtension::ThemeControlExtension - 0x%08X\n", (uintptr_t)(This())); } @@ -61,9 +51,9 @@ ThemeControlExtension::ThemeControlExtension(ThemeClass::ThemeControl *this_ptr) * @author: CCHyper */ ThemeControlExtension::ThemeControlExtension(const NoInitClass &noinit) : - Extension(noinit) + GlobalExtensionClass(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("ThemeControlExtension::ThemeControlExtension(NoInitClass) - 0x%08X\n", (uintptr_t)(This())); } @@ -74,10 +64,45 @@ ThemeControlExtension::ThemeControlExtension(const NoInitClass &noinit) : */ ThemeControlExtension::~ThemeControlExtension() { - //EXT_DEBUG_TRACE("ThemeControlExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name, (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("ThemeControlExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name, (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ThemeControlExtension::~ThemeControlExtension - 0x%08X\n", (uintptr_t)(This())); +} + + +/** + * Initializes an object from the stream where it was saved previously. + * + * @author: CCHyper + */ +HRESULT ThemeControlExtension::Load(IStream *pStm) +{ + //EXT_DEBUG_TRACE("ThemeControlExtension::Load - 0x%08X\n", (uintptr_t)(This())); + + HRESULT hr = GlobalExtensionClass::Load(pStm); + if (FAILED(hr)) { + return E_FAIL; + } - IsInitialized = false; + new (this) ThemeControlExtension(NoInitClass()); + + return hr; +} + + +/** + * Saves an object to the specified stream. + * + * @author: CCHyper + */ +HRESULT ThemeControlExtension::Save(IStream *pStm, BOOL fClearDirty) +{ + //EXT_DEBUG_TRACE("ThemeControlExtension::Save - 0x%08X\n", (uintptr_t)(This())); + + HRESULT hr = GlobalExtensionClass::Save(pStm, fClearDirty); + if (FAILED(hr)) { + return hr; + } + + return hr; } @@ -88,13 +113,34 @@ ThemeControlExtension::~ThemeControlExtension() */ int ThemeControlExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ThemeControlExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name, (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ThemeControlExtension::Size_Of - 0x%08X\n", (uintptr_t)(This())); return sizeof(*this); } +/** + * Removes the specified target from any targeting and reference trackers. + * + * @author: CCHyper + */ +void ThemeControlExtension::Detach(TARGET target, bool all) +{ + //EXT_DEBUG_TRACE("ThemeControlExtension::Detach - 0x%08X\n", (uintptr_t)(This())); +} + + +/** + * Compute a unique crc value for this instance. + * + * @author: CCHyper + */ +void ThemeControlExtension::Compute_CRC(WWCRCEngine &crc) const +{ + //EXT_DEBUG_TRACE("ThemeControlExtension::Compute_CRC - 0x%08X\n", (uintptr_t)(This())); +} + + /** * Fetches the extension data from the INI database. * @@ -102,11 +148,9 @@ int ThemeControlExtension::Size_Of() const */ bool ThemeControlExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("ThemeControlExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name, (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("ThemeControlExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name, (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("ThemeControlExtension::Read_INI - Name: %s (0x%08X)\n", This()->Name, (uintptr_t)(This())); - const char *ini_name = ThisPtr->Name; + const char *ini_name = This()->Name; if (!ini.Is_Present(ini_name)) { return false; diff --git a/src/extensions/theme/themeext.h b/src/extensions/theme/themeext.h index 40718118..0935d788 100644 --- a/src/extensions/theme/themeext.h +++ b/src/extensions/theme/themeext.h @@ -27,22 +27,35 @@ ******************************************************************************/ #pragma once +#include "always.h" #include "extension.h" -#include "container.h" #include "theme.h" class CCINIClass; -class ThemeControlExtension final : public Extension +class ThemeControlExtension final : public GlobalExtensionClass { public: - ThemeControlExtension(ThemeClass::ThemeControl *this_ptr); + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + ThemeControlExtension(const ThemeClass::ThemeControl *this_ptr); ThemeControlExtension(const NoInitClass &noinit); - ~ThemeControlExtension(); + virtual ~ThemeControlExtension(); + /** + * ThemeControl extension does not require these to be used, but we + * implement them for completeness. + */ virtual int Size_Of() const override; + virtual void Detach(TARGET target, bool all = true) override; + virtual void Compute_CRC(WWCRCEngine &crc) const override; + + virtual const char *Name() const override { return "ThemeControl"; } + virtual const char *Full_Name() const override { return "ThemeControl"; } bool Read_INI(CCINIClass &ini); @@ -52,6 +65,3 @@ class ThemeControlExtension final : public Extension */ AddonType RequiredAddon; }; - - -extern ExtensionMap ThemeControlExtensions; diff --git a/src/extensions/theme/themeext_hooks.cpp b/src/extensions/theme/themeext_hooks.cpp index f47a800b..3aa93b83 100644 --- a/src/extensions/theme/themeext_hooks.cpp +++ b/src/extensions/theme/themeext_hooks.cpp @@ -35,10 +35,14 @@ #include "session.h" #include "scenario.h" #include "addon.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * A fake class for implementing new member functions which allow @@ -47,7 +51,7 @@ * @note: This must not contain a constructor or deconstructor! * @note: All functions must be prefixed with "_" to prevent accidental virtualization. */ -static class ThemeClassFake final : public ThemeClass +static class ThemeClassExt final : public ThemeClass { public: bool _Is_Allowed(ThemeType index) const; @@ -60,7 +64,7 @@ static class ThemeClassFake final : public ThemeClass * @author: 07/04/1996 JLB - Red Alert source code. * CCHyper - Adjustments for Tiberian Sun. */ -bool ThemeClassFake::_Is_Allowed(ThemeType index) const +bool ThemeClassExt::_Is_Allowed(ThemeType index) const { if (index == THEME_QUIET || index == THEME_PICK_ANOTHER) { return true; @@ -91,8 +95,8 @@ bool ThemeClassFake::_Is_Allowed(ThemeType index) const * * @author: CCHyper */ - ThemeControlExtension *themectrlext = ThemeControlExtensions.find(Themes[index]); - if (themectrlext && themectrlext->RequiredAddon != ADDON_NONE) { + ThemeControlExtension *themectrlext = Extension::List::Fetch(Themes[index], ThemeControlExtensions); + if (themectrlext->RequiredAddon != ADDON_NONE) { if (!Addon_Enabled(themectrlext->RequiredAddon)) { return false; } @@ -133,5 +137,5 @@ void ThemeClassExtension_Hooks() */ ThemeClassExtension_Init(); - Patch_Jump(0x00644300, &ThemeClassFake::_Is_Allowed); + Patch_Jump(0x00644300, &ThemeClassExt::_Is_Allowed); } diff --git a/src/extensions/theme/themeext_init.cpp b/src/extensions/theme/themeext_init.cpp index c623bda7..84fab101 100644 --- a/src/extensions/theme/themeext_init.cpp +++ b/src/extensions/theme/themeext_init.cpp @@ -30,10 +30,15 @@ #include "theme.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -45,22 +50,12 @@ DECLARE_PATCH(_ThemeClass_ThemeControl_Constructor_Patch) { GET_REGISTER_STATIC(ThemeClass::ThemeControl *, this_ptr, eax); // "this" pointer. - static ThemeControlExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating ThemeClass_ThemeControlExtension.\n"); + static ThemeControlExtension *ext_ptr; /** - * Find existing or create an extended class instance. + * Create an extended class instance. */ - exttype_ptr = ThemeControlExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create ThemeControlExtension instance!\n"); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create ThemeControlExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create ThemeControlExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. - } + Extension::List::Make(this_ptr, ThemeControlExtensions); /** * Stolen bytes here. @@ -106,10 +101,7 @@ DECLARE_PATCH(_ThemeClass_ThemeControl_Read_INI_Patch) /** * Find the extension instance. */ - exttype_ptr = ThemeControlExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } + exttype_ptr = Extension::List::Fetch(this_ptr, ThemeControlExtensions); /** * Read type class ini. diff --git a/src/extensions/tiberium/tiberiumext.cpp b/src/extensions/tiberium/tiberiumext.cpp index 5a55c750..62a1c963 100644 --- a/src/extensions/tiberium/tiberiumext.cpp +++ b/src/extensions/tiberium/tiberiumext.cpp @@ -28,29 +28,22 @@ #include "tiberiumext.h" #include "tiberium.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all TiberiumClass extension instances. - */ -ExtensionMap TiberiumClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -TiberiumClassExtension::TiberiumClassExtension(TiberiumClass *this_ptr) : - Extension(this_ptr) +TiberiumClassExtension::TiberiumClassExtension(const TiberiumClass *this_ptr) : + AbstractTypeClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TiberiumClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("TiberiumClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("TiberiumClassExtension::TiberiumClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + TiberiumExtensions.Add(this); } @@ -60,9 +53,9 @@ TiberiumClassExtension::TiberiumClassExtension(TiberiumClass *this_ptr) : * @author: CCHyper */ TiberiumClassExtension::TiberiumClassExtension(const NoInitClass &noinit) : - Extension(noinit) + AbstractTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("TiberiumClassExtension::TiberiumClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ TiberiumClassExtension::TiberiumClassExtension(const NoInitClass &noinit) : */ TiberiumClassExtension::~TiberiumClassExtension() { - //EXT_DEBUG_TRACE("TiberiumClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("TiberiumClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TiberiumClassExtension::~TiberiumClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + TiberiumExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT TiberiumClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("TiberiumClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -87,10 +98,9 @@ TiberiumClassExtension::~TiberiumClassExtension() */ HRESULT TiberiumClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TiberiumClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TiberiumClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = AbstractTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT TiberiumClassExtension::Load(IStream *pStm) */ HRESULT TiberiumClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TiberiumClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TiberiumClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = AbstractTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT TiberiumClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int TiberiumClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TiberiumClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TiberiumClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int TiberiumClassExtension::Size_Of() const */ void TiberiumClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TiberiumClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TiberiumClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,8 +160,7 @@ void TiberiumClassExtension::Detach(TARGET target, bool all) */ void TiberiumClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TiberiumClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TiberiumClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -165,11 +171,13 @@ void TiberiumClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool TiberiumClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("TiberiumClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("TiberiumClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("TiberiumClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (!AbstractTypeClassExtension::Read_INI(ini)) { + return false; + } - const char *ini_name = ThisPtr->Name(); + const char *ini_name = Name(); if (!ini.Is_Present(ini_name)) { return false; diff --git a/src/extensions/tiberium/tiberiumext.h b/src/extensions/tiberium/tiberiumext.h index b5450d91..f851cc4d 100644 --- a/src/extensions/tiberium/tiberiumext.h +++ b/src/extensions/tiberium/tiberiumext.h @@ -27,33 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "abstracttypeext.h" +#include "tiberium.h" -class TiberiumClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_TIBERIUM_EXTENSION) +TiberiumClassExtension final : public AbstractTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class TiberiumClassExtension final : public Extension -{ public: - TiberiumClassExtension(TiberiumClass *this_ptr); + TiberiumClassExtension(const TiberiumClass *this_ptr = nullptr); TiberiumClassExtension(const NoInitClass &noinit); - ~TiberiumClassExtension(); + virtual ~TiberiumClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual TiberiumClass *This() const override { return reinterpret_cast(AbstractTypeClassExtension::This()); } + virtual const TiberiumClass *This_Const() const override { return reinterpret_cast(AbstractTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_TIBERIUM; } - public: + virtual bool Read_INI(CCINIClass &ini) override; + public: }; - - -extern ExtensionMap TiberiumClassExtensions; diff --git a/src/extensions/tiberium/tiberiumext_init.cpp b/src/extensions/tiberium/tiberiumext_init.cpp index 3a22ffd5..8e8c85f4 100644 --- a/src/extensions/tiberium/tiberiumext_init.cpp +++ b/src/extensions/tiberium/tiberiumext_init.cpp @@ -30,10 +30,15 @@ #include "tiberium.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,23 +51,20 @@ DECLARE_PATCH(_TiberiumClass_Constructor_Patch) { GET_REGISTER_STATIC(TiberiumClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0x10); // ini name. - static TiberiumClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating TiberiumClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = TiberiumClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create TiberiumClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create TiberiumClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create TiberiumClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * Stolen bytes here. */ @@ -89,88 +91,14 @@ DECLARE_PATCH(_TiberiumClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - TiberiumClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { pop ecx } - _asm { ret } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TiberiumClass_Detach_Patch) -{ - GET_REGISTER_STATIC(TiberiumClass *, this_ptr, esi); - GET_STACK_STATIC(TARGET, target, esp, 0x4); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static TiberiumClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = TiberiumClassExtensions.find(this_ptr, false); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class detach. - */ - exttype_ptr->Detach(target, all); - - /** - * Stolen bytes here. - */ -original_code: - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_TiberiumClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(TiberiumClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static TiberiumClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = TiberiumClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } + _asm { mov edx, ds:0x0080F408 } // Tiberiums.vtble + JMP_REG(eax, 0x00644A99); } @@ -188,12 +116,9 @@ DECLARE_PATCH(_TiberiumClass_Read_INI_Patch) static TiberiumClassExtension *exttype_ptr; /** - * Find the extension instance. + * Fetch the extension instance. */ - exttype_ptr = TiberiumClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } + exttype_ptr = Extension::Fetch(this_ptr); /** * Read type class ini. @@ -218,8 +143,6 @@ DECLARE_PATCH(_TiberiumClass_Read_INI_Patch) void TiberiumClassExtension_Init() { Patch_Jump(0x00644A20, &_TiberiumClass_Constructor_Patch); - Patch_Jump(0x00644BE1, &_TiberiumClass_Destructor_Patch); - Patch_Jump(0x00645326, &_TiberiumClass_Detach_Patch); - Patch_Jump(0x00644FCA, &_TiberiumClass_Compute_CRC_Patch); + Patch_Jump(0x00644A93, &_TiberiumClass_Destructor_Patch); Patch_Jump(0x00644E74, &_TiberiumClass_Read_INI_Patch); } diff --git a/src/extensions/unit/unitext.cpp b/src/extensions/unit/unitext.cpp index 61b98d54..7e1621bd 100644 --- a/src/extensions/unit/unitext.cpp +++ b/src/extensions/unit/unitext.cpp @@ -28,29 +28,22 @@ #include "unitext.h" #include "unit.h" #include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all UnitClass extension instances. - */ -ExtensionMap UnitClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -UnitClassExtension::UnitClassExtension(UnitClass *this_ptr) : - Extension(this_ptr) +UnitClassExtension::UnitClassExtension(const UnitClass *this_ptr) : + FootClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("UnitClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("UnitClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("UnitClassExtension::UnitClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + UnitExtensions.Add(this); } @@ -60,9 +53,9 @@ UnitClassExtension::UnitClassExtension(UnitClass *this_ptr) : * @author: CCHyper */ UnitClassExtension::UnitClassExtension(const NoInitClass &noinit) : - Extension(noinit) + FootClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("UnitClassExtension::UnitClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ UnitClassExtension::UnitClassExtension(const NoInitClass &noinit) : */ UnitClassExtension::~UnitClassExtension() { - //EXT_DEBUG_TRACE("UnitClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("UnitClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("UnitClassExtension::~UnitClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + UnitExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT UnitClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("UnitClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); - IsInitialized = false; + return S_OK; } @@ -87,10 +98,9 @@ UnitClassExtension::~UnitClassExtension() */ HRESULT UnitClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("UnitClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("UnitClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = FootClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT UnitClassExtension::Load(IStream *pStm) */ HRESULT UnitClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("UnitClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("UnitClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = FootClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT UnitClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int UnitClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("UnitClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("UnitClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int UnitClassExtension::Size_Of() const */ void UnitClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("UnitClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("UnitClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,6 +160,5 @@ void UnitClassExtension::Detach(TARGET target, bool all) */ void UnitClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("UnitClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("UnitClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } diff --git a/src/extensions/unit/unitext.h b/src/extensions/unit/unitext.h index 3aee1086..4142ec10 100644 --- a/src/extensions/unit/unitext.h +++ b/src/extensions/unit/unitext.h @@ -27,30 +27,37 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "footext.h" +#include "unit.h" -class UnitClass; -class HouseClass; +class DECLSPEC_UUID(UUID_UNIT_EXTENSION) +UnitClassExtension final : public FootClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class UnitClassExtension final : public Extension -{ public: - UnitClassExtension(UnitClass *this_ptr); + UnitClassExtension(const UnitClass *this_ptr = nullptr); UnitClassExtension(const NoInitClass &noinit); - ~UnitClassExtension(); + virtual ~UnitClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + virtual UnitClass *This() const override { return reinterpret_cast(FootClassExtension::This()); } + virtual const UnitClass *This_Const() const override { return reinterpret_cast(FootClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_UNIT; } + public: }; - - -extern ExtensionMap UnitClassExtensions; diff --git a/src/extensions/unit/unitext_hooks.cpp b/src/extensions/unit/unitext_hooks.cpp index adc9c059..0e54d509 100644 --- a/src/extensions/unit/unitext_hooks.cpp +++ b/src/extensions/unit/unitext_hooks.cpp @@ -40,6 +40,7 @@ #include "rules.h" #include "iomap.h" #include "voc.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" @@ -183,14 +184,12 @@ DECLARE_PATCH(_UnitClass_Draw_Shape_IdleRate_Patch) GET_REGISTER_STATIC(UnitClass *, this_ptr, esi); GET_REGISTER_STATIC(int, facing, ebx); GET_REGISTER_STATIC(ShapeFileStruct *, shape, edi); - static TechnoTypeClassExtension *technotypeext; static UnitTypeClassExtension *unittypeext; - static UnitTypeClass *unittype; + static const UnitTypeClass *unittype; static int frame; - unittype = this_ptr->Class; - technotypeext = TechnoTypeClassExtensions.find(this_ptr->Techno_Type_Class()); - unittypeext = UnitTypeClassExtensions.find(unittype); + unittype = reinterpret_cast(this_ptr->Techno_Type_Class()); + unittypeext = Extension::Fetch(unittype); if (!Locomotion_Is_Moving(this_ptr)) { if (this_ptr->FiringSyncDelay >= 0) { @@ -229,7 +228,7 @@ DECLARE_PATCH(_UnitClass_Draw_Shape_IdleRate_Patch) /** * Unit is not moving, so if the unit has a idle animation rate, use this. */ - if (!Locomotion_Is_Moving(this_ptr) && (technotypeext && technotypeext->IdleRate > 0) && unittypeext) { + if (!Locomotion_Is_Moving(this_ptr) && unittypeext->IdleRate > 0) { frame = unittypeext->StartIdleFrame + (this_ptr->TotalFramesWalked % unittypeext->IdleFrames) + (unittypeext->IdleFrames * facing); @@ -274,8 +273,8 @@ DECLARE_PATCH(_UnitClass_Mission_Unload_Transport_Detach_Sound_Patch) /** * Do we have a sound to play when passengers leave us? If so, play it now. */ - radio_technotypeext = TechnoTypeClassExtensions.find(this_ptr->Techno_Type_Class()); - if (radio_technotypeext && radio_technotypeext->LeaveTransportSound != VOC_NONE) { + radio_technotypeext = Extension::Fetch(this_ptr->Techno_Type_Class()); + if (radio_technotypeext->LeaveTransportSound != VOC_NONE) { Sound_Effect(radio_technotypeext->LeaveTransportSound, this_ptr->Coord); } @@ -314,8 +313,8 @@ DECLARE_PATCH(_UnitClass_Draw_It_Unloading_Harvester_Patch) { GET_REGISTER_STATIC(UnitClass *, this_ptr, esi); GET_REGISTER_STATIC(UnitTypeClass *, unittype, eax); - static const TechnoTypeClassExtension *technotypext; static const UnitTypeClass *unloading_class; + static const UnitTypeClassExtension *unittypeext; /** * The code just before this backs up the current Class, so we @@ -351,12 +350,10 @@ DECLARE_PATCH(_UnitClass_Draw_It_Unloading_Harvester_Patch) /** * Fetch the unloading class from the extended class instance if it exists. */ - technotypext = TechnoTypeClassExtensions.find(unittype); - if (technotypext) { - if (technotypext->UnloadingClass) { - if (technotypext->UnloadingClass->Kind_Of() == RTTI_UNITTYPE) { - unloading_class = reinterpret_cast(technotypext->UnloadingClass); - } + unittypeext = Extension::Fetch(unittype); + if (unittypeext->UnloadingClass) { + if (unittypeext->UnloadingClass->Kind_Of() == RTTI_UNITTYPE) { + unloading_class = reinterpret_cast(unittypeext->UnloadingClass); } } @@ -433,7 +430,7 @@ DECLARE_PATCH(_UnitClass_Draw_Shape_Primary_Facing_Patch) * Using either of these causes a memory leak for some reason... * So we now just fetch EAX which is a UnitTypeClass instance already. */ - //unittype = reinterpret_cast(this_ptr->Class_Of()); + //unittype = reinterpret_cast(this_ptr->Techno_Type_Class()); //unittype = this_ptr->Class; /** @@ -472,7 +469,7 @@ DECLARE_PATCH(_UnitClass_Draw_Shape_Turret_Facing_Patch) frame_number = 0; - unittype = reinterpret_cast(this_ptr->Class_Of()); + unittype = reinterpret_cast(this_ptr->Techno_Type_Class()); /** * All turrets have 32 facings in Tiberian Sun. @@ -484,18 +481,16 @@ DECLARE_PATCH(_UnitClass_Draw_Shape_Turret_Facing_Patch) */ start_turret_frame = unittype->Facings * unittype->WalkFrames; - unittypeext = UnitTypeClassExtensions.find(unittype); - if (unittypeext) { + unittypeext = Extension::Fetch(unittype); - /** - * #issue-393 - * - * Allow the custom turret facings. - * - * @author: CCHyper - */ - turret_facings = unittypeext->TurretFacings; - } + /** + * #issue-393 + * + * Allow the custom turret facings. + * + * @author: CCHyper + */ + turret_facings = unittypeext->TurretFacings; /** * Fetch the frame index for current turret facing. @@ -546,14 +541,12 @@ DECLARE_PATCH(_UnitClass_Draw_Shape_Turret_Facing_Patch) */ static void UnitClass_Shake_Screen(UnitClass *unit) { - TechnoTypeClass *technotype; - TechnoTypeClassExtension *technotypeext; + UnitTypeClassExtension *unittypeext; /** - * Fetch the extended techno type instance if it exists. + * Fetch the extension instance. */ - technotype = unit->Techno_Type_Class(); - technotypeext = TechnoTypeClassExtensions.find(technotype); + unittypeext = Extension::Fetch(unit->Techno_Type_Class()); /** * #issue-414 @@ -562,20 +555,20 @@ static void UnitClass_Shake_Screen(UnitClass *unit) * * @author: CCHyper */ - if (technotypeext && technotypeext->IsShakeScreen) { + if (unittypeext->IsShakeScreen) { /** * If this unit has screen shake values defined, then set the blitter * offset values. GScreenClass::Blit will handle the rest for us. */ - if ((technotypeext->ShakePixelXLo > 0 || technotypeext->ShakePixelXHi > 0) - || (technotypeext->ShakePixelYLo > 0 || technotypeext->ShakePixelYHi > 0)) { + if ((unittypeext->ShakePixelXLo > 0 || unittypeext->ShakePixelXHi > 0) + || (unittypeext->ShakePixelYLo > 0 || unittypeext->ShakePixelYHi > 0)) { - if (technotypeext->ShakePixelXLo > 0 || technotypeext->ShakePixelXHi > 0) { - Map.ScreenX = Sim_Random_Pick(technotypeext->ShakePixelXLo, technotypeext->ShakePixelXHi); + if (unittypeext->ShakePixelXLo > 0 || unittypeext->ShakePixelXHi > 0) { + Map.ScreenX = Sim_Random_Pick(unittypeext->ShakePixelXLo, unittypeext->ShakePixelXHi); } - if (technotypeext->ShakePixelYLo > 0 || technotypeext->ShakePixelYHi > 0) { - Map.ScreenY = Sim_Random_Pick(technotypeext->ShakePixelYLo, technotypeext->ShakePixelYHi); + if (unittypeext->ShakePixelYLo > 0 || unittypeext->ShakePixelYHi > 0) { + Map.ScreenY = Sim_Random_Pick(unittypeext->ShakePixelYLo, unittypeext->ShakePixelYHi); } } else { diff --git a/src/extensions/unit/unitext_init.cpp b/src/extensions/unit/unitext_init.cpp index c0af3db5..901c496f 100644 --- a/src/extensions/unit/unitext_init.cpp +++ b/src/extensions/unit/unitext_init.cpp @@ -29,10 +29,16 @@ #include "unittypeext.h" #include "unit.h" #include "unittype.h" +#include "tibsun_globals.h" +#include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" -#include "vinifera_util.h" + +#include "hooker.h" +#include "hooker_macros.h" /** @@ -45,21 +51,20 @@ DECLARE_PATCH(_UnitClass_Constructor_Patch) { GET_REGISTER_STATIC(UnitClass *, this_ptr, esi); // Current "this" pointer. - static UnitClassExtension *exttype_ptr; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = UnitClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create UnitClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create UnitClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create UnitClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * Stolen bytes here. */ @@ -74,28 +79,6 @@ DECLARE_PATCH(_UnitClass_Constructor_Patch) } -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_UnitClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(UnitClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit, esp, 0x18); - static UnitClassExtension *ext_ptr; - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov dword ptr [esi], 0x006D8B6C } // this->vftable = const UnitClass::`vftable'; - JMP(0x00659680); -} - - /** * Patch for including the extended class members in the destruction process. * @@ -110,85 +93,14 @@ DECLARE_PATCH(_UnitClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - UnitClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { add esp, 0x8 } - _asm { ret } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_UnitClass_Detach_Patch) -{ - GET_REGISTER_STATIC(UnitClass *, this_ptr, esi); - GET_STACK_STATIC(TARGET, target, esp, 0x10); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static UnitClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = UnitClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Detach(target, all); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members to the base class crc calculation. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_UnitClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(UnitClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static UnitClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = UnitClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Compute_CRC(*crc); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } + _asm { mov edx, ds:0x007B3458 } // Units.vtble + JMP_REG(ecx, 0x0064D8B4); } @@ -198,8 +110,5 @@ DECLARE_PATCH(_UnitClass_Compute_CRC_Patch) void UnitClassExtension_Init() { Patch_Jump(0x0064D7B4, &_UnitClass_Constructor_Patch); - Patch_Jump(0x0065967A, &_UnitClass_NoInit_Constructor_Patch); - Patch_Jump(0x0064D9C0, &_UnitClass_Destructor_Patch); - Patch_Jump(0x00659863, &_UnitClass_Detach_Patch); - Patch_Jump(0x00659825, &_UnitClass_Compute_CRC_Patch); + Patch_Jump(0x0064D8AE, &_UnitClass_Destructor_Patch); } diff --git a/src/extensions/unittype/unittypeext.cpp b/src/extensions/unittype/unittypeext.cpp index 148378c1..65ada901 100644 --- a/src/extensions/unittype/unittypeext.cpp +++ b/src/extensions/unittype/unittypeext.cpp @@ -28,34 +28,28 @@ #include "unittypeext.h" #include "unittype.h" #include "ccini.h" +#include "tibsun_globals.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all UnitTypeClass extension instances. - */ -ExtensionMap UnitTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -UnitTypeClassExtension::UnitTypeClassExtension(UnitTypeClass *this_ptr) : - Extension(this_ptr), +UnitTypeClassExtension::UnitTypeClassExtension(const UnitTypeClass *this_ptr) : + TechnoTypeClassExtension(this_ptr), IsTotable(true), StartTurretFrame(-1), TurretFacings(32), // Must default to 32 as all Tiberian Sun units have 32 facings for turrets., StartIdleFrame(0), IdleFrames(0) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("UnitTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("UnitTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("UnitTypeClassExtension::UnitTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + UnitTypeExtensions.Add(this); } @@ -65,9 +59,9 @@ UnitTypeClassExtension::UnitTypeClassExtension(UnitTypeClass *this_ptr) : * @author: CCHyper */ UnitTypeClassExtension::UnitTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + TechnoTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("UnitTypeClassExtension::UnitTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -78,10 +72,28 @@ UnitTypeClassExtension::UnitTypeClassExtension(const NoInitClass &noinit) : */ UnitTypeClassExtension::~UnitTypeClassExtension() { - //EXT_DEBUG_TRACE("UnitTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("UnitTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("UnitTypeClassExtension::~UnitTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + UnitTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT UnitTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("UnitTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -92,10 +104,9 @@ UnitTypeClassExtension::~UnitTypeClassExtension() */ HRESULT UnitTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("UnitTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("UnitTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = TechnoTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -113,10 +124,9 @@ HRESULT UnitTypeClassExtension::Load(IStream *pStm) */ HRESULT UnitTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("UnitTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("UnitTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = TechnoTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -132,8 +142,7 @@ HRESULT UnitTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int UnitTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("UnitTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("UnitTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -146,8 +155,7 @@ int UnitTypeClassExtension::Size_Of() const */ void UnitTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("UnitTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("UnitTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -158,8 +166,7 @@ void UnitTypeClassExtension::Detach(TARGET target, bool all) */ void UnitTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("UnitTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("UnitTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -170,17 +177,14 @@ void UnitTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool UnitTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("UnitTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("UnitTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - - const char *ini_name = ThisPtr->Name(); + //EXT_DEBUG_TRACE("UnitTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - if (!ini.Is_Present(ini_name)) { + if (!TechnoTypeClassExtension::Read_INI(ini)) { return false; } - const char *graphic_name = ThisPtr->Graphic_Name(); + const char *ini_name = Name(); + const char *graphic_name = This()->Graphic_Name(); //if (!ArtINI.Is_Present(graphic_name)) { // return false; @@ -194,8 +198,8 @@ bool UnitTypeClassExtension::Read_INI(CCINIClass &ini) /** * Set the defaults to walk frames (this ensures IdleRate by itself works as expected). */ - StartIdleFrame = ThisPtr->StartWalkFrame; - IdleFrames = ThisPtr->WalkFrames; + StartIdleFrame = This()->StartWalkFrame; + IdleFrames = This()->WalkFrames; StartIdleFrame = ArtINI.Get_Int(graphic_name, "StartIdleFrame", StartIdleFrame); IdleFrames = ArtINI.Get_Int(graphic_name, "IdleFrames", IdleFrames); diff --git a/src/extensions/unittype/unittypeext.h b/src/extensions/unittype/unittypeext.h index 022ae5f4..9fcf9391 100644 --- a/src/extensions/unittype/unittypeext.h +++ b/src/extensions/unittype/unittypeext.h @@ -27,29 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "technotypeext.h" +#include "unittype.h" -class UnitTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_UNITTYPE_EXTENSION) +UnitTypeClassExtension final : public TechnoTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class UnitTypeClassExtension final : public Extension -{ public: - UnitTypeClassExtension(UnitTypeClass *this_ptr); + UnitTypeClassExtension(const UnitTypeClass *this_ptr = nullptr); UnitTypeClassExtension(const NoInitClass &noinit); - ~UnitTypeClassExtension(); + virtual ~UnitTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual UnitTypeClass *This() const override { return reinterpret_cast(TechnoTypeClassExtension::This()); } + virtual const UnitTypeClass *This_Const() const override { return reinterpret_cast(TechnoTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_UNITTYPE; } + + virtual bool Read_INI(CCINIClass &ini) override; public: /** @@ -77,6 +87,3 @@ class UnitTypeClassExtension final : public Extension */ unsigned IdleFrames; }; - - -extern ExtensionMap UnitTypeClassExtensions; diff --git a/src/extensions/unittype/unittypeext_init.cpp b/src/extensions/unittype/unittypeext_init.cpp index 8dbeaa1d..ba96dabb 100644 --- a/src/extensions/unittype/unittypeext_init.cpp +++ b/src/extensions/unittype/unittypeext_init.cpp @@ -30,10 +30,15 @@ #include "unittype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,53 +51,28 @@ DECLARE_PATCH(_UnitTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(UnitTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0x10); // ini name. - static UnitTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating UnitTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = UnitTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create UnitTypeClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create UnitTypeClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create UnitTypeClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_UnitTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(UnitTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. */ original_code: _asm { mov eax, this_ptr } + _asm { pop edi } _asm { pop esi } + _asm { pop ebx } _asm { ret 4 } } @@ -111,15 +91,14 @@ DECLARE_PATCH(_UnitTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - UnitTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007E2218 } // UnitTypes.vtble + JMP_REG(eax, 0x0065BADE); } @@ -137,95 +116,14 @@ DECLARE_PATCH(_UnitTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - UnitTypeClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_UnitTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(UnitTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static UnitTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = UnitTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_UnitTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(void *, alt_image_ptr, eax); // Return from MixFileClass::Retrieve() - GET_REGISTER_STATIC(UnitTypeClass *, this_ptr, ebp); - GET_STACK_STATIC(CCINIClass *, ini, esp, 0x144); // Can't use ESI as its reused by this point. - static UnitTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = UnitTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); - - /** - * Stolen bytes here. - */ -original_code: - this_ptr->AltImage = (ShapeFileStruct *)alt_image_ptr; - - _asm { mov al, 1 } - _asm { pop esi } - _asm { pop ebx } - _asm { pop edi } - _asm { pop ebp } - _asm { add esp, 0x130 } - _asm { ret 4 } + _asm { mov edx, ds:0x007E2218 } // UnitTypes.vtble + JMP_REG(eax, 0x0065C79E); } @@ -235,9 +133,6 @@ DECLARE_PATCH(_UnitTypeClass_Read_INI_Patch) void UnitTypeClassExtension_Init() { Patch_Jump(0x0065BA96, &_UnitTypeClass_Constructor_Patch); - Patch_Jump(0x0065BABA, &_UnitTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x0065BB28, &_UnitTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x0065C7F8, &_UnitTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x0065C50A, &_UnitTypeClass_Compute_CRC_Patch); - Patch_Jump(0x0065C38D, &_UnitTypeClass_Read_INI_Patch); + //Patch_Jump(0x0065BAD8, &_UnitTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x0065C798, &_UnitTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/voxelanimtype/voxelanimtypeext.cpp b/src/extensions/voxelanimtype/voxelanimtypeext.cpp index fb1a6517..89067576 100644 --- a/src/extensions/voxelanimtype/voxelanimtypeext.cpp +++ b/src/extensions/voxelanimtype/voxelanimtypeext.cpp @@ -28,29 +28,22 @@ #include "voxelanimtypeext.h" #include "voxelanimtype.h" #include "ccini.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all VoxelAnimTypeClass extension instances. - */ -ExtensionMap VoxelAnimTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -VoxelAnimTypeClassExtension::VoxelAnimTypeClassExtension(VoxelAnimTypeClass *this_ptr) : - Extension(this_ptr) +VoxelAnimTypeClassExtension::VoxelAnimTypeClassExtension(const VoxelAnimTypeClass *this_ptr) : + ObjectTypeClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("VoxelAnimTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::VoxelAnimTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + VoxelAnimTypeExtensions.Add(this); } @@ -60,9 +53,9 @@ VoxelAnimTypeClassExtension::VoxelAnimTypeClassExtension(VoxelAnimTypeClass *thi * @author: CCHyper */ VoxelAnimTypeClassExtension::VoxelAnimTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::VoxelAnimTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ VoxelAnimTypeClassExtension::VoxelAnimTypeClassExtension(const NoInitClass &noin */ VoxelAnimTypeClassExtension::~VoxelAnimTypeClassExtension() { - //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("VoxelAnimTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::~VoxelAnimTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + VoxelAnimTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT VoxelAnimTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -87,10 +98,9 @@ VoxelAnimTypeClassExtension::~VoxelAnimTypeClassExtension() */ HRESULT VoxelAnimTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT VoxelAnimTypeClassExtension::Load(IStream *pStm) */ HRESULT VoxelAnimTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT VoxelAnimTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int VoxelAnimTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int VoxelAnimTypeClassExtension::Size_Of() const */ void VoxelAnimTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -153,8 +160,7 @@ void VoxelAnimTypeClassExtension::Detach(TARGET target, bool all) */ void VoxelAnimTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -165,11 +171,13 @@ void VoxelAnimTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool VoxelAnimTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("VoxelAnimTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("VoxelAnimTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (!ObjectTypeClassExtension::Read_INI(ini)) { + return false; + } - const char *ini_name = ThisPtr->Name(); + const char *ini_name = Name(); if (!ini.Is_Present(ini_name)) { return false; diff --git a/src/extensions/voxelanimtype/voxelanimtypeext.h b/src/extensions/voxelanimtype/voxelanimtypeext.h index 35c4d414..5c087aaa 100644 --- a/src/extensions/voxelanimtype/voxelanimtypeext.h +++ b/src/extensions/voxelanimtype/voxelanimtypeext.h @@ -27,33 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "objecttypeext.h" +#include "voxelanimtype.h" -class VoxelAnimTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_VOXELANIMTYPE_EXTENSION) +VoxelAnimTypeClassExtension final : public ObjectTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class VoxelAnimTypeClassExtension final : public Extension -{ public: - VoxelAnimTypeClassExtension(VoxelAnimTypeClass *this_ptr); + VoxelAnimTypeClassExtension(const VoxelAnimTypeClass *this_ptr = nullptr); VoxelAnimTypeClassExtension(const NoInitClass &noinit); - ~VoxelAnimTypeClassExtension(); + virtual ~VoxelAnimTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual VoxelAnimTypeClass *This() const override { return reinterpret_cast(ObjectTypeClassExtension::This()); } + virtual const VoxelAnimTypeClass *This_Const() const override { return reinterpret_cast(ObjectTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_VOXELANIMTYPE; } - public: + virtual bool Read_INI(CCINIClass &ini) override; + public: }; - - -extern ExtensionMap VoxelAnimTypeClassExtensions; diff --git a/src/extensions/voxelanimtype/voxelanimtypeext_init.cpp b/src/extensions/voxelanimtype/voxelanimtypeext_init.cpp index fa6995ec..e9b67aa8 100644 --- a/src/extensions/voxelanimtype/voxelanimtypeext_init.cpp +++ b/src/extensions/voxelanimtype/voxelanimtypeext_init.cpp @@ -30,10 +30,15 @@ #include "voxelanimtype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,45 +51,19 @@ DECLARE_PATCH(_VoxelAnimTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(VoxelAnimTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0xC); // ini name. - static VoxelAnimTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating VoxelAnimTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = VoxelAnimTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create VoxelAnimTypeClassExtension instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create VoxelAnimTypeClassExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create VoxelAnimTypeClassExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_VoxelAnimTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(VoxelAnimTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. @@ -92,6 +71,7 @@ DECLARE_PATCH(_VoxelAnimTypeClass_NoInit_Constructor_Patch) original_code: _asm { mov eax, this_ptr } _asm { pop esi } + _asm { pop ebx } _asm { ret 4 } } @@ -110,15 +90,14 @@ DECLARE_PATCH(_VoxelAnimTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - VoxelAnimTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007E46F0 } // VoxelAnimTypes.vtble + JMP_REG(eax, 0x0065F5F7); } @@ -136,127 +115,14 @@ DECLARE_PATCH(_VoxelAnimTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - VoxelAnimTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_VoxelAnimTypeClass_Detach_Patch) -{ - GET_REGISTER_STATIC(VoxelAnimTypeClass *, this_ptr, ecx); - GET_STACK_STATIC(TARGET, target, esp, 0x4); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static VoxelAnimTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = VoxelAnimTypeClassExtensions.find(this_ptr, false); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class detach. - */ - exttype_ptr->Detach(target, all); - - /** - * Stolen bytes here. - */ -original_code: - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_VoxelAnimTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(VoxelAnimTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static VoxelAnimTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = VoxelAnimTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_VoxelAnimTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(VoxelAnimTypeClass *, this_ptr, esi); - GET_REGISTER_STATIC(CCINIClass *, ini, ebx); - static VoxelAnimTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = VoxelAnimTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov al, 1 } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { mov esp, ebp } - _asm { pop ebp } - _asm { ret 4 } + _asm { mov edx, ds:0x007E46F0 } // VoxelAnimTypes.vtble + JMP_REG(eax, 0x006600E7); } @@ -266,14 +132,6 @@ DECLARE_PATCH(_VoxelAnimTypeClass_Read_INI_Patch) void VoxelAnimTypeClassExtension_Init() { Patch_Jump(0x0065F584, &_VoxelAnimTypeClass_Constructor_Patch); - //Patch_Jump(0x, &_VoxelAnimTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x0065F653, &_VoxelAnimTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x00660153, &_VoxelAnimTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x0065FFA0, &_VoxelAnimTypeClass_Detach_Patch); - Patch_Jump(0x0065FE22, &_VoxelAnimTypeClass_Compute_CRC_Patch); - Patch_Jump(0x0065FB54, &_VoxelAnimTypeClass_Read_INI_Patch); - Patch_Jump(0x0065FB76, &_VoxelAnimTypeClass_Read_INI_Patch); - Patch_Jump(0x0065FB9F, &_VoxelAnimTypeClass_Read_INI_Patch); - Patch_Jump(0x0065FBB0, &_VoxelAnimTypeClass_Read_INI_Patch); - Patch_Jump(0x0065FC53, &_VoxelAnimTypeClass_Read_INI_Patch); + //Patch_Jump(0x0065F5F1, &_VoxelAnimTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x006600E1, &_VoxelAnimTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/warheadtype/warheadtypeext.cpp b/src/extensions/warheadtype/warheadtypeext.cpp index 66b59cc3..6a44bdf0 100644 --- a/src/extensions/warheadtype/warheadtypeext.cpp +++ b/src/extensions/warheadtype/warheadtypeext.cpp @@ -28,24 +28,19 @@ #include "warheadtypeext.h" #include "warheadtype.h" #include "ccini.h" +#include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all WarheadTypeClass extension instances. - */ -ExtensionMap WarheadTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -WarheadTypeClassExtension::WarheadTypeClassExtension(WarheadTypeClass *this_ptr) : - Extension(this_ptr), - +WarheadTypeClassExtension::WarheadTypeClassExtension(const WarheadTypeClass *this_ptr) : + AbstractTypeClassExtension(this_ptr), IsWallAbsoluteDestroyer(false), IsAffectsAllies(true), CombatLightSize(0.0f), @@ -54,11 +49,9 @@ WarheadTypeClassExtension::WarheadTypeClassExtension(WarheadTypeClass *this_ptr) ShakePixelXHi(0), ShakePixelXLo(0) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WarheadTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("WarheadTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("WarheadTypeClassExtension::WarheadTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + WarheadTypeExtensions.Add(this); } @@ -68,9 +61,9 @@ WarheadTypeClassExtension::WarheadTypeClassExtension(WarheadTypeClass *this_ptr) * @author: CCHyper */ WarheadTypeClassExtension::WarheadTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + AbstractTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("WarheadTypeClassExtension::WarheadTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -81,10 +74,28 @@ WarheadTypeClassExtension::WarheadTypeClassExtension(const NoInitClass &noinit) */ WarheadTypeClassExtension::~WarheadTypeClassExtension() { - //EXT_DEBUG_TRACE("WarheadTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("WarheadTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WarheadTypeClassExtension::~WarheadTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + WarheadTypeExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT WarheadTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("WarheadTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); - IsInitialized = false; + return S_OK; } @@ -95,12 +106,11 @@ WarheadTypeClassExtension::~WarheadTypeClassExtension() */ HRESULT WarheadTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WarheadTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WarheadTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = AbstractTypeClassExtension::Load(pStm); if (FAILED(hr)) { - return E_FAIL; + return hr; } new (this) WarheadTypeClassExtension(NoInitClass()); @@ -116,10 +126,9 @@ HRESULT WarheadTypeClassExtension::Load(IStream *pStm) */ HRESULT WarheadTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WarheadTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WarheadTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = AbstractTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -135,8 +144,7 @@ HRESULT WarheadTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int WarheadTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WarheadTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WarheadTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -149,8 +157,7 @@ int WarheadTypeClassExtension::Size_Of() const */ void WarheadTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WarheadTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WarheadTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -161,8 +168,7 @@ void WarheadTypeClassExtension::Detach(TARGET target, bool all) */ void WarheadTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WarheadTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WarheadTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); crc(IsWallAbsoluteDestroyer); crc(IsAffectsAllies); @@ -181,16 +187,14 @@ void WarheadTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool WarheadTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WarheadTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("WarheadTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WarheadTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - const char *ini_name = ThisPtr->Name(); - - if (!ini.Is_Present(ini_name)) { + if (!AbstractTypeClassExtension::Read_INI(ini)) { return false; } + const char *ini_name = Name(); + IsWallAbsoluteDestroyer = ini.Get_Bool(ini_name, "WallAbsoluteDestroyer", IsWallAbsoluteDestroyer); IsAffectsAllies = ini.Get_Bool(ini_name, "AffectsAllies", IsAffectsAllies); CombatLightSize = ini.Get_Float_Clamp(ini_name, "CombatLightSize", 0.0f, 1.0f, CombatLightSize); diff --git a/src/extensions/warheadtype/warheadtypeext.h b/src/extensions/warheadtype/warheadtypeext.h index 054d8a80..bb658fb0 100644 --- a/src/extensions/warheadtype/warheadtypeext.h +++ b/src/extensions/warheadtype/warheadtypeext.h @@ -27,29 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "abstracttypeext.h" +#include "warheadtype.h" -class WarheadTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_WARHEADTYPE_EXTENSION) +WarheadTypeClassExtension final : public AbstractTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class WarheadTypeClassExtension final : public Extension -{ public: - WarheadTypeClassExtension(WarheadTypeClass *this_ptr); + WarheadTypeClassExtension(const WarheadTypeClass *this_ptr = nullptr); WarheadTypeClassExtension(const NoInitClass &noinit); - ~WarheadTypeClassExtension(); + virtual ~WarheadTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual WarheadTypeClass *This() const override { return reinterpret_cast(AbstractTypeClassExtension::This()); } + virtual const WarheadTypeClass *This_Const() const override { return reinterpret_cast(AbstractTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_WARHEADTYPE; } + + virtual bool Read_INI(CCINIClass &ini) override; public: /** @@ -75,6 +85,3 @@ class WarheadTypeClassExtension final : public Extension unsigned int ShakePixelXHi; unsigned int ShakePixelXLo; }; - - -extern ExtensionMap WarheadTypeClassExtensions; diff --git a/src/extensions/warheadtype/warheadtypeext_init.cpp b/src/extensions/warheadtype/warheadtypeext_init.cpp index 003c38cf..19cce945 100644 --- a/src/extensions/warheadtype/warheadtypeext_init.cpp +++ b/src/extensions/warheadtype/warheadtypeext_init.cpp @@ -30,10 +30,15 @@ #include "warheadtype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,54 +51,29 @@ DECLARE_PATCH(_WarheadTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(WarheadTypeClass *, this_ptr, ebp); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0x14); // ini name. - static WarheadTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating WarheadTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = WarheadTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create WarheadTypeClassExtensions instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create WarheadTypeClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create WarheadTypeClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_WarheadTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(WarheadTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. */ original_code: _asm { mov eax, this_ptr } + _asm { pop edi } _asm { pop esi } + _asm { pop ebp } + _asm { pop ebx } _asm { ret 4 } } @@ -112,15 +92,14 @@ DECLARE_PATCH(_WarheadTypeClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - WarheadTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x0074C798 } // WarheadTypes.vtble + JMP_REG(eax, 0x0066EF7E); } @@ -138,132 +117,14 @@ DECLARE_PATCH(_WarheadTypeClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - WarheadTypeClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_WarheadTypeClass_Detach_Patch) -{ - GET_REGISTER_STATIC(WarheadTypeClass *, this_ptr, esi); - GET_STACK_STATIC(TARGET, target, esp, 0x8); - GET_STACK_STATIC8(bool, all, esp, 0xC); - static WarheadTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. Flag that failures are Ok as the - * class may not have - */ - exttype_ptr = WarheadTypeClassExtensions.find(this_ptr, false); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class detach. - */ - exttype_ptr->Detach(target, all); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop esi } - _asm { ret 8 } -} - - -/** - * Patch for including the extended class members when computing a unique crc value for this instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_WarheadTypeClass_Compute_CRC_Patch) -{ - GET_REGISTER_STATIC(WarheadTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0x18); - static WarheadTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = WarheadTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); - - /** - * Stolen bytes here. - */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { mov esp, ebp } - _asm { pop ebp } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_WarheadTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(WarheadTypeClass *, this_ptr, esi); - GET_STACK_STATIC(CCINIClass *, ini, ebp, 0x8); // Can't use EDI as its reused by this point. - static WarheadTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = WarheadTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. - */ - exttype_ptr->Read_INI(*ini); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { mov al, 1 } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { mov esp, ebp } - _asm { pop ebp } - _asm { ret 4 } + _asm { mov edx, ds:0x0074C798 } // WarheadTypes.vtble + JMP_REG(eax, 0x0066FA9E); } @@ -273,10 +134,6 @@ DECLARE_PATCH(_WarheadTypeClass_Read_INI_Patch) void WarheadTypeClassExtension_Init() { Patch_Jump(0x0066EEF4, &_WarheadTypeClass_Constructor_Patch); - Patch_Jump(0x0066EF4F, &_WarheadTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x0066F053, &_WarheadTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x0066FB83, &_WarheadTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x0066F9F5, &_WarheadTypeClass_Detach_Patch); - Patch_Jump(0x0066F6A4, &_WarheadTypeClass_Compute_CRC_Patch); - Patch_Jump(0x0066F566, &_WarheadTypeClass_Read_INI_Patch); + //Patch_Jump(0x0066EF78, &_WarheadTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x0066FA98, &_WarheadTypeClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/wave/waveext.cpp b/src/extensions/wave/waveext.cpp index f2b03c98..e70dae26 100644 --- a/src/extensions/wave/waveext.cpp +++ b/src/extensions/wave/waveext.cpp @@ -28,29 +28,22 @@ #include "waveext.h" #include "wave.h" #include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all WaveClass extension instances. - */ -ExtensionMap WaveClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -WaveClassExtension::WaveClassExtension(WaveClass *this_ptr) : - Extension(this_ptr) +WaveClassExtension::WaveClassExtension(const WaveClass *this_ptr) : + ObjectClassExtension(this_ptr) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WaveClassExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("WaveClassExtension constructor - 0x%08X\n", (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("WaveClassExtension::WaveClassExtension - 0x%08X\n", (uintptr_t)(This())); - IsInitialized = true; + WaveExtensions.Add(this); } @@ -60,9 +53,9 @@ WaveClassExtension::WaveClassExtension(WaveClass *this_ptr) : * @author: CCHyper */ WaveClassExtension::WaveClassExtension(const NoInitClass &noinit) : - Extension(noinit) + ObjectClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("WaveClassExtension::WaveClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -73,10 +66,28 @@ WaveClassExtension::WaveClassExtension(const NoInitClass &noinit) : */ WaveClassExtension::~WaveClassExtension() { - //EXT_DEBUG_TRACE("WaveClassExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("WaveClassExtension destructor - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WaveClassExtension::~WaveClassExtension - 0x%08X\n", (uintptr_t)(This())); + + WaveExtensions.Delete(this); +} + + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT WaveClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("WaveClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); - IsInitialized = false; + return S_OK; } @@ -87,10 +98,9 @@ WaveClassExtension::~WaveClassExtension() */ HRESULT WaveClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WaveClassExtension::Load - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WaveClassExtension::Load - 0x%08X\n", (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = ObjectClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -108,10 +118,9 @@ HRESULT WaveClassExtension::Load(IStream *pStm) */ HRESULT WaveClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WaveClassExtension::Save - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WaveClassExtension::Save - 0x%08X\n", (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = ObjectClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -127,8 +136,7 @@ HRESULT WaveClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int WaveClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WaveClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WaveClassExtension::Size_Of - 0x%08X\n", (uintptr_t)(This())); return sizeof(*this); } @@ -141,8 +149,7 @@ int WaveClassExtension::Size_Of() const */ void WaveClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WaveClassExtension::Detach - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WaveClassExtension::Detach - 0x%08X\n", (uintptr_t)(This())); } @@ -153,6 +160,5 @@ void WaveClassExtension::Detach(TARGET target, bool all) */ void WaveClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WaveClassExtension::Compute_CRC - 0x%08X\n", (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WaveClassExtension::Compute_CRC - 0x%08X\n", (uintptr_t)(This())); } diff --git a/src/extensions/wave/waveext.h b/src/extensions/wave/waveext.h index 01989292..a61683e6 100644 --- a/src/extensions/wave/waveext.h +++ b/src/extensions/wave/waveext.h @@ -27,27 +27,37 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "objectext.h" #include "wave.h" -class WaveClassExtension final : public Extension +class DECLSPEC_UUID(UUID_WAVE_EXTENSION) +WaveClassExtension final : public ObjectClassExtension { public: - WaveClassExtension(WaveClass *this_ptr); + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); + + public: + WaveClassExtension(const WaveClass *this_ptr = nullptr); WaveClassExtension(const NoInitClass &noinit); - ~WaveClassExtension(); + virtual ~WaveClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; + virtual WaveClass *This() const override { return reinterpret_cast(ObjectClassExtension::This()); } + virtual const WaveClass *This_Const() const override { return reinterpret_cast(ObjectClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_WAVE; } + public: }; - - -extern ExtensionMap WaveClassExtensions; diff --git a/src/extensions/wave/waveext_init.cpp b/src/extensions/wave/waveext_init.cpp index 33e1f732..543153c0 100644 --- a/src/extensions/wave/waveext_init.cpp +++ b/src/extensions/wave/waveext_init.cpp @@ -28,10 +28,16 @@ #include "waveext.h" #include "wave.h" #include "techno.h" +#include "tibsun_globals.h" +#include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "asserthandler.h" #include "debughandler.h" -#include "vinifera_util.h" + +#include "hooker.h" +#include "hooker_macros.h" #if 0 @@ -45,21 +51,20 @@ DECLARE_PATCH(_WaveClass_Default_Constructor_Patch) { GET_REGISTER_STATIC(WaveClass *, this_ptr, esi); // Current "this" pointer. - static WaveClassExtension *ext_ptr; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - ext_ptr = WaveClassExtensions.find_or_create(this_ptr); - if (!ext_ptr) { - DEBUG_ERROR("Failed to create WaveClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create WaveClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create WaveClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * Stolen bytes here. */ @@ -89,21 +94,20 @@ DECLARE_PATCH(_WaveClass_Default_Constructor_Patch) DECLARE_PATCH(_WaveClass_Default_Constructor_Before_Init_Patch) { GET_REGISTER_STATIC(WaveClass *, this_ptr, esi); // Current "this" pointer. - static WaveClassExtension *ext_ptr; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - ext_ptr = WaveClassExtensions.find_or_create(this_ptr); - if (!ext_ptr) { - DEBUG_ERROR("Failed to create WaveClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create WaveClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create WaveClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * Stolen bytes here. */ @@ -126,21 +130,20 @@ DECLARE_PATCH(_WaveClass_Default_Constructor_Before_Init_Patch) DECLARE_PATCH(_WaveClass_Constructor_Patch) { GET_REGISTER_STATIC(WaveClass *, this_ptr, esi); // Current "this" pointer. - static WaveClassExtension *ext_ptr; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - ext_ptr = WaveClassExtensions.find_or_create(this_ptr); - if (!ext_ptr) { - DEBUG_ERROR("Failed to create WaveClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create WaveClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create WaveClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * Stolen bytes here. */ @@ -169,21 +172,20 @@ DECLARE_PATCH(_WaveClass_Constructor_Patch) DECLARE_PATCH(_WaveClass_Constructor_Before_Init_Patch) { GET_REGISTER_STATIC(WaveClass *, this_ptr, esi); // Current "this" pointer. - static WaveClassExtension *ext_ptr; /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - ext_ptr = WaveClassExtensions.find_or_create(this_ptr); - if (!ext_ptr) { - DEBUG_ERROR("Failed to create WaveClassExtension instance for 0x%08X!\n", (uintptr_t)this_ptr); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create WaveClassExtensions instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create WaveClassExtensions instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } + /** + * Create an extended class instance. + */ + Extension::Make(this_ptr); + /** * Stolen bytes here. */ @@ -209,16 +211,14 @@ DECLARE_PATCH(_WaveClass_Destructor_Patch) /** * Remove the extended class from the global index. */ - WaveClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { pop ecx } - _asm { ret } + _asm { mov edx, ds:0x007E47E8 } // Waves.vtble + JMP_REG(eax, 0x006702DF); } @@ -236,50 +236,14 @@ DECLARE_PATCH(_WaveClass_Scalar_Destructor_Patch) /** * Remove the extended class from the global index. */ - WaveClassExtensions.remove(this_ptr); - - /** - * Stolen bytes here. - */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop ecx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members to the base class detach process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_WaveClass_Detach_Patch) -{ - GET_REGISTER_STATIC(WaveClass *, this_ptr, esi); - GET_STACK_STATIC(TARGET, target, esp, 0x10); - GET_STACK_STATIC8(bool, all, esp, 0x8); - static WaveClassExtension *ext_ptr; - - /** - * Find the extension instance. - */ - ext_ptr = WaveClassExtensions.find(this_ptr); - if (!ext_ptr) { - goto original_code; - } - - ext_ptr->Detach(target, all); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 8 } + _asm { mov edx, ds:0x007E47E8 } // Waves.vtble + JMP_REG(eax, 0x00672E7E); } @@ -292,7 +256,6 @@ void WaveClassExtension_Init() Patch_Jump(0x00670189, &_WaveClass_Default_Constructor_Before_Init_Patch); //Patch_Jump(0x006700A2, &_WaveClass_Constructor_Patch); Patch_Jump(0x0066FECF, &_WaveClass_Constructor_Before_Init_Patch); - Patch_Jump(0x00670369, &_WaveClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x00672F1B, &_WaveClass_Scalar_Destructor_Patch); - Patch_Jump(0x00670B3D, &_WaveClass_Detach_Patch); + Patch_Jump(0x006702D9, &_WaveClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x00672E78, &_WaveClass_Scalar_Destructor_Patch); } diff --git a/src/extensions/weapontype/weapontypeext.cpp b/src/extensions/weapontype/weapontypeext.cpp index 85febd80..3a4a8418 100644 --- a/src/extensions/weapontype/weapontypeext.cpp +++ b/src/extensions/weapontype/weapontypeext.cpp @@ -29,23 +29,19 @@ #include "weapontype.h" #include "ebolt.h" #include "ccini.h" +#include "wwcrc.h" +#include "extension.h" #include "asserthandler.h" #include "debughandler.h" -/** - * Provides the map for all WeaponTypeClass extension instances. - */ -ExtensionMap WeaponTypeClassExtensions; - - /** * Class constructor. * * @author: CCHyper */ -WeaponTypeClassExtension::WeaponTypeClassExtension(WeaponTypeClass *this_ptr) : - Extension(this_ptr), +WeaponTypeClassExtension::WeaponTypeClassExtension(const WeaponTypeClass *this_ptr) : + AbstractTypeClassExtension(this_ptr), IsSuicide(false), IsDeleteOnSuicide(false), IsElectricBolt(false), @@ -57,11 +53,9 @@ WeaponTypeClassExtension::WeaponTypeClassExtension(WeaponTypeClass *this_ptr) : ElectricBoltIterationCount(EBOLT_DEFAULT_INTERATIONS), ElectricBoltDeviation(EBOLT_DEFAULT_DEVIATION) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WeaponTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("WeaponTypeClassExtension constructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //if (this_ptr) EXT_DEBUG_TRACE("WeaponTypeClassExtension::WeaponTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = true; + WeaponTypeExtensions.Add(this); } @@ -71,9 +65,9 @@ WeaponTypeClassExtension::WeaponTypeClassExtension(WeaponTypeClass *this_ptr) : * @author: CCHyper */ WeaponTypeClassExtension::WeaponTypeClassExtension(const NoInitClass &noinit) : - Extension(noinit) + AbstractTypeClassExtension(noinit) { - IsInitialized = false; + //EXT_DEBUG_TRACE("WeaponTypeClassExtension::WeaponTypeClassExtension(NoInitClass) - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -84,10 +78,27 @@ WeaponTypeClassExtension::WeaponTypeClassExtension(const NoInitClass &noinit) : */ WeaponTypeClassExtension::~WeaponTypeClassExtension() { - //EXT_DEBUG_TRACE("WeaponTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - //EXT_DEBUG_WARNING("WeaponTypeClassExtension destructor - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WeaponTypeClassExtension::~WeaponTypeClassExtension - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - IsInitialized = false; + WeaponTypeExtensions.Delete(this); +} + +/** + * Retrieves the class identifier (CLSID) of the object. + * + * @author: CCHyper + */ +HRESULT WeaponTypeClassExtension::GetClassID(CLSID *lpClassID) +{ + //EXT_DEBUG_TRACE("WeaponTypeClassExtension::GetClassID - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); + + if (lpClassID == nullptr) { + return E_POINTER; + } + + *lpClassID = __uuidof(this); + + return S_OK; } @@ -98,10 +109,9 @@ WeaponTypeClassExtension::~WeaponTypeClassExtension() */ HRESULT WeaponTypeClassExtension::Load(IStream *pStm) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WeaponTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WeaponTypeClassExtension::Load - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Load(pStm); + HRESULT hr = AbstractTypeClassExtension::Load(pStm); if (FAILED(hr)) { return E_FAIL; } @@ -119,10 +129,9 @@ HRESULT WeaponTypeClassExtension::Load(IStream *pStm) */ HRESULT WeaponTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WeaponTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WeaponTypeClassExtension::Save - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - HRESULT hr = Extension::Save(pStm, fClearDirty); + HRESULT hr = AbstractTypeClassExtension::Save(pStm, fClearDirty); if (FAILED(hr)) { return hr; } @@ -138,8 +147,7 @@ HRESULT WeaponTypeClassExtension::Save(IStream *pStm, BOOL fClearDirty) */ int WeaponTypeClassExtension::Size_Of() const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WeaponTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WeaponTypeClassExtension::Size_Of - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); return sizeof(*this); } @@ -152,8 +160,7 @@ int WeaponTypeClassExtension::Size_Of() const */ void WeaponTypeClassExtension::Detach(TARGET target, bool all) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WeaponTypeClassExtension::Detach - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WeaponTypeClassExtension::Detach - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); } @@ -164,8 +171,7 @@ void WeaponTypeClassExtension::Detach(TARGET target, bool all) */ void WeaponTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WeaponTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WeaponTypeClassExtension::Compute_CRC - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); crc(IsElectricBolt); } @@ -178,15 +184,13 @@ void WeaponTypeClassExtension::Compute_CRC(WWCRCEngine &crc) const */ bool WeaponTypeClassExtension::Read_INI(CCINIClass &ini) { - ASSERT(ThisPtr != nullptr); - //EXT_DEBUG_TRACE("WeaponTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); - EXT_DEBUG_WARNING("WeaponTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", ThisPtr->Name(), (uintptr_t)(ThisPtr)); + //EXT_DEBUG_TRACE("WeaponTypeClassExtension::Read_INI - Name: %s (0x%08X)\n", Name(), (uintptr_t)(This())); - const char *ini_name = ThisPtr->Name(); - - if (!ini.Is_Present(ini_name)) { + if (!AbstractTypeClassExtension::Read_INI(ini)) { return false; } + + const char *ini_name = Name(); IsSuicide = ini.Get_Bool(ini_name, "Suicide", IsSuicide); IsDeleteOnSuicide = ini.Get_Bool(ini_name, "DeleteOnSuicide", IsDeleteOnSuicide); diff --git a/src/extensions/weapontype/weapontypeext.h b/src/extensions/weapontype/weapontypeext.h index 86e1f0a1..4d662c3e 100644 --- a/src/extensions/weapontype/weapontypeext.h +++ b/src/extensions/weapontype/weapontypeext.h @@ -27,29 +27,39 @@ ******************************************************************************/ #pragma once -#include "extension.h" -#include "container.h" +#include "abstracttypeext.h" +#include "weapontype.h" -class WeaponTypeClass; -class CCINIClass; +class DECLSPEC_UUID(UUID_WEAPONTYPE_EXTENSION) +WeaponTypeClassExtension final : public AbstractTypeClassExtension +{ + public: + /** + * IPersist + */ + IFACEMETHOD(GetClassID)(CLSID *pClassID); + /** + * IPersistStream + */ + IFACEMETHOD(Load)(IStream *pStm); + IFACEMETHOD(Save)(IStream *pStm, BOOL fClearDirty); -class WeaponTypeClassExtension final : public Extension -{ public: - WeaponTypeClassExtension(WeaponTypeClass *this_ptr); + WeaponTypeClassExtension(const WeaponTypeClass *this_ptr = nullptr); WeaponTypeClassExtension(const NoInitClass &noinit); - ~WeaponTypeClassExtension(); + virtual ~WeaponTypeClassExtension(); - virtual HRESULT Load(IStream *pStm) override; - virtual HRESULT Save(IStream *pStm, BOOL fClearDirty) override; virtual int Size_Of() const override; - virtual void Detach(TARGET target, bool all = true) override; virtual void Compute_CRC(WWCRCEngine &crc) const override; - bool Read_INI(CCINIClass &ini); + virtual WeaponTypeClass *This() const override { return reinterpret_cast(AbstractTypeClassExtension::This()); } + virtual const WeaponTypeClass *This_Const() const override { return reinterpret_cast(AbstractTypeClassExtension::This_Const()); } + virtual RTTIType What_Am_I() const override { return RTTI_WEAPONTYPE; } + + virtual bool Read_INI(CCINIClass &ini) override; public: /** @@ -100,6 +110,3 @@ class WeaponTypeClassExtension final : public Extension //ParticleSystemClass *ElectricBoltSourceBoltParticleSys; //ParticleSystemClass *ElectricBoltTargetBoltParticleSys; }; - - -extern ExtensionMap WeaponTypeClassExtensions; diff --git a/src/extensions/weapontype/weapontypeext_init.cpp b/src/extensions/weapontype/weapontypeext_init.cpp index 36401a3c..e028c714 100644 --- a/src/extensions/weapontype/weapontypeext_init.cpp +++ b/src/extensions/weapontype/weapontypeext_init.cpp @@ -30,10 +30,15 @@ #include "weapontype.h" #include "tibsun_globals.h" #include "vinifera_util.h" +#include "vinifera_globals.h" +#include "extension.h" #include "fatal.h" #include "debughandler.h" #include "asserthandler.h" +#include "hooker.h" +#include "hooker_macros.h" + /** * Patch for including the extended class members in the creation process. @@ -46,53 +51,28 @@ DECLARE_PATCH(_WeaponTypeClass_Constructor_Patch) { GET_REGISTER_STATIC(WeaponTypeClass *, this_ptr, esi); // "this" pointer. GET_STACK_STATIC(const char *, ini_name, esp, 0x10); // ini name. - static WeaponTypeClassExtension *exttype_ptr; - - //EXT_DEBUG_WARNING("Creating WeaponTypeClassExtension instance for \"%s\".\n", ini_name); /** - * Find existing or create an extended class instance. + * If we are performing a load operation, the Windows API will invoke the + * constructors for us as part of the operation, so we can skip our hook here. */ - exttype_ptr = WeaponTypeClassExtensions.find_or_create(this_ptr); - if (!exttype_ptr) { - DEBUG_ERROR("Failed to create WeaponTypeClassExtension instance for \"%s\"!\n", ini_name); - ShowCursor(TRUE); - MessageBoxA(MainWindow, "Failed to create WeaponTypeClassExtension instance!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); - Vinifera_Generate_Mini_Dump(); - Fatal("Failed to create WeaponTypeClassExtension instance!\n"); - goto original_code; // Keep this for clean code analysis. + if (Vinifera_PerformingLoad) { + goto original_code; } /** - * Stolen bytes here. + * Create an extended class instance. */ -original_code: - _asm { mov eax, this_ptr } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebx } - _asm { ret 4 } -} - - -/** - * Patch for including the extended class members in the noinit creation process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_WeaponTypeClass_NoInit_Constructor_Patch) -{ - GET_REGISTER_STATIC(WeaponTypeClass *, this_ptr, esi); - GET_STACK_STATIC(const NoInitClass *, noinit_ptr, esp, 0x4); + Extension::Make(this_ptr); /** * Stolen bytes here. */ original_code: _asm { mov eax, this_ptr } + _asm { pop edi } _asm { pop esi } + _asm { pop ebx } _asm { ret 4 } } @@ -108,123 +88,54 @@ DECLARE_PATCH(_WeaponTypeClass_Destructor_Patch) { GET_REGISTER_STATIC(WeaponTypeClass *, this_ptr, esi); - /** - * Remove the extended class from the global index. - */ - WeaponTypeClassExtensions.remove(this_ptr); - /** * Stolen bytes here. */ -original_code: - _asm { pop esi } - _asm { pop ebx } - _asm { pop ecx } - _asm { ret } -} - - -/** - * Patch for including the extended class members in the virtual destruction process. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_WeaponTypeClass_Scalar_Destructor_Patch) -{ - GET_REGISTER_STATIC(WeaponTypeClass *, this_ptr, esi); + _asm { mov [esi+0x0A5], bl } + _asm { mov [esi+0x0A0], ebx } /** * Remove the extended class from the global index. */ - WeaponTypeClassExtensions.remove(this_ptr); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { mov eax, this_ptr } - _asm { pop esi } - _asm { pop ebx } - _asm { pop ecx } - _asm { ret 4 } + this_ptr->AbstractTypeClass::~AbstractTypeClass(); + JMP_REG(ecx, 0x00680D1F); } /** - * Patch for including the extended class members when computing a unique crc value for this instance. + * Patch for including the extended class members in the virtual destruction process. * * @warning: Do not touch this unless you know what you are doing! * * @author: CCHyper */ -DECLARE_PATCH(_WeaponTypeClass_Compute_CRC_Patch) +DECLARE_PATCH(_WeaponTypeClass_Scalar_Destructor_Patch) { GET_REGISTER_STATIC(WeaponTypeClass *, this_ptr, esi); - GET_STACK_STATIC(WWCRCEngine *, crc, esp, 0xC); - static WeaponTypeClassExtension *exttype_ptr; - - /** - * Find the extension instance. - */ - exttype_ptr = WeaponTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class compute crc. - */ - exttype_ptr->Compute_CRC(*crc); /** * Stolen bytes here. */ -original_code: - _asm { pop edi } - _asm { pop esi } - _asm { ret 4 } -} - - -/** - * Patch for reading the extended class members from the ini instance. - * - * @warning: Do not touch this unless you know what you are doing! - * - * @author: CCHyper - */ -DECLARE_PATCH(_WeaponTypeClass_Read_INI_Patch) -{ - GET_REGISTER_STATIC(WeaponTypeClass *, this_ptr, esi); - GET_STACK_STATIC(CCINIClass *, ini, esp, 0x0E4); // Can't use EBX as its reused by this point. - static WeaponTypeClassExtension *exttype_ptr; + _asm { mov [esi+0x0A5], bl } + _asm { mov [esi+0x0A0], ebx } /** - * Find the extension instance. - */ - exttype_ptr = WeaponTypeClassExtensions.find(this_ptr); - if (!exttype_ptr) { - goto original_code; - } - - /** - * Read type class ini. + * Remove the extended class from the global index. */ - exttype_ptr->Read_INI(*ini); + Extension::Destroy(this_ptr); /** * Stolen bytes here. */ original_code: - _asm { mov al, 1 } - _asm { pop edi } - _asm { pop esi } - _asm { pop ebp } - _asm { pop ebx } - _asm { add esp, 0x0D0 } - _asm { ret 4 } + this_ptr->AbstractTypeClass::~AbstractTypeClass(); + JMP_REG(ecx, 0x006819BF); } @@ -234,9 +145,6 @@ DECLARE_PATCH(_WeaponTypeClass_Read_INI_Patch) void WeaponTypeClassExtension_Init() { Patch_Jump(0x00680BEF, &_WeaponTypeClass_Constructor_Patch); - Patch_Jump(0x00680C2E, &_WeaponTypeClass_NoInit_Constructor_Patch); - //Patch_Jump(0x00680D1F, &_WeaponTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! - Patch_Jump(0x006819CF, &_WeaponTypeClass_Scalar_Destructor_Patch); - Patch_Jump(0x00681514, &_WeaponTypeClass_Compute_CRC_Patch); - Patch_Jump(0x0068129D, &_WeaponTypeClass_Read_INI_Patch); + //Patch_Jump(0x00680D0C, &_WeaponTypeClass_Destructor_Patch); // Destructor is actually inlined in scalar destructor! + Patch_Jump(0x006819AC, &_WeaponTypeClass_Scalar_Destructor_Patch); } diff --git a/src/hooker/hooker_macros.h b/src/hooker/hooker_macros.h index a909c264..99a19cd9 100644 --- a/src/hooker/hooker_macros.h +++ b/src/hooker/hooker_macros.h @@ -117,6 +117,15 @@ #define SET_REGISTER(reg, src) _asm { mov reg, src } +/** + * Get value of an offset relative to a register (eg, [this + member_offset]) + */ +#define GET_REGISTER_OFFSET_STATIC(type, dst, reg, off) static type dst; _asm { mov eax, [reg+off] } _asm { mov dst, eax } +#define LEA_REGISTER_OFFSET_STATIC(type, dst, reg, off) static type dst; _asm { lea eax, [reg+off] } _asm { mov dst, eax } +#define GET_REGISTER_OFFSET_STATIC8(type, dst, reg, off) static type dst; _asm { mov al, byte ptr [reg+off] } _asm { mov dst, al } +#define GET_REGISTER_OFFSET_STATIC16(type, dst, reg, off) static type dst; _asm { mov ax, word ptr [reg+off] } _asm { mov dst, ax } + + #define GET_ADDRESS_STATIC(type, dst, addr) static type dst; _asm { mov dst, addr } #define LEA_ADDRESS_STATIC(type, dst, addr) static type dst; _asm { lea eax, addr } diff --git a/src/hooker/setup_hooks.cpp b/src/hooker/setup_hooks.cpp index 4ebb1588..2fd7841c 100644 --- a/src/hooker/setup_hooks.cpp +++ b/src/hooker/setup_hooks.cpp @@ -40,9 +40,6 @@ #include "cncnet5_hooks.h" -extern bool Vinifera_ClassExtensionsDisabled; - - void Setup_Hooks() { Vinifera_Memory_Hooks(); @@ -51,23 +48,7 @@ void Setup_Hooks() Debug_Hooks(); Vinifera_Hooks(); NewSwizzle_Hooks(); - - /** - * Command line option to disable class extensions. - */ - const char *cmdline = GetCommandLineA(); - Vinifera_ClassExtensionsDisabled = (std::strstr(cmdline, "-NO_CLASS_EXTENSIONS") != nullptr); - - /** - * Command line option to disable all extensions and new gameplay code. - */ - bool no_extensions = (std::strstr(cmdline, "-NO_EXTENSIONS") != nullptr); - - if (!no_extensions) { - Extension_Hooks(); - } else { - Vinifera_ClassExtensionsDisabled = true; - } + Extension_Hooks(); CnCNet4_Hooks(); CnCNet5_Hooks(); diff --git a/src/new/ebolt.cpp b/src/new/ebolt.cpp index c3606ca1..d5e30cce 100644 --- a/src/new/ebolt.cpp +++ b/src/new/ebolt.cpp @@ -41,6 +41,7 @@ #include "random.h" #include "wwmath.h" #include "clipline.h" +#include "extension.h" #include "debughandler.h" #include "asserthandler.h" @@ -90,11 +91,8 @@ void EBoltClass::Clear() { if (Source) { - TechnoClassExtension *technoext; - technoext = TechnoClassExtensions.find(Source); - if (technoext) { - technoext->ElectricBolt = nullptr; - } + TechnoClassExtension *technoext = Extension::Fetch(Source); + technoext->ElectricBolt = nullptr; Source = nullptr; } @@ -214,17 +212,15 @@ void EBoltClass::Set_Properties(TechnoClass *techno, const WeaponTypeClass *weap /** * Copy the color overrides from the firing objects weapon. */ - WeaponTypeClassExtension *weapontypeext; - weapontypeext = WeaponTypeClassExtensions.find(weapon); - if (weapontypeext) { - LineColor1 = weapontypeext->ElectricBoltColor1; - LineColor2 = weapontypeext->ElectricBoltColor2; - LineColor3 = weapontypeext->ElectricBoltColor3; - IterationCount = weapontypeext->ElectricBoltIterationCount; - LineSegmentCount = weapontypeext->ElectricBoltSegmentCount; - Lifetime = std::clamp(weapontypeext->ElectricBoltLifetime, 0, EBOLT_MAX_LIFETIME); - Deviation = weapontypeext->ElectricBoltDeviation; - } + WeaponTypeClassExtension *weapontypeext = Extension::Fetch(weapon); + + LineColor1 = weapontypeext->ElectricBoltColor1; + LineColor2 = weapontypeext->ElectricBoltColor2; + LineColor3 = weapontypeext->ElectricBoltColor3; + IterationCount = weapontypeext->ElectricBoltIterationCount; + LineSegmentCount = weapontypeext->ElectricBoltSegmentCount; + Lifetime = std::clamp(weapontypeext->ElectricBoltLifetime, 0, EBOLT_MAX_LIFETIME); + Deviation = weapontypeext->ElectricBoltDeviation; } } } diff --git a/src/new/swizzle/newswizzle_hooks.cpp b/src/new/swizzle/newswizzle_hooks.cpp index c21c62ff..7b35544e 100644 --- a/src/new/swizzle/newswizzle_hooks.cpp +++ b/src/new/swizzle/newswizzle_hooks.cpp @@ -475,8 +475,6 @@ LONG STDAPICALLTYPE SwizzleManagerClassExt::_Here_I_Am(LONG id, void *pointer) { //DEV_DEBUG_INFO("SwizzleManager::Here_I_Am - retaddr 0x%08X id 0x%08X pointer 0x%08X\n", (uintptr_t)_ReturnAddress(), id, pointer); - bool added = false; - /** * Get the caller return address, we use this to identify a location in which the annoucement was made. */ @@ -518,12 +516,12 @@ LONG STDAPICALLTYPE SwizzleManagerClassExt::_Reset() { //DEV_DEBUG_INFO("SwizzleManager::Reset - retaddr 0x%08X id 0x%08X pointer 0x%08X\n", (uintptr_t)_ReturnAddress(), id, pointer); +#ifdef VINIFERA_ENABLE_SWIZZLE_DEBUG_PRINTING /** * Get the caller return address, we use this to identify a location in which the request was made. */ uintptr_t retaddr = (uintptr_t)_ReturnAddress(); -#ifdef VINIFERA_ENABLE_SWIZZLE_DEBUG_PRINTING switch (retaddr) { case 0x005D69C7: DEV_DEBUG_INFO("Reset() - From Load_Game\n"); @@ -547,8 +545,6 @@ LONG STDAPICALLTYPE SwizzleManagerClassExt::_Swizzle(void **pointer) { //DEV_DEBUG_INFO("SwizzleManager::Swizzle - retaddr 0x%08X id 0x%08X pointer 0x%08X\n", (uintptr_t)_ReturnAddress(), id, pointer); - bool added = false; - /** * Get the caller return address, we use this to identify a location in which the request was made. */ diff --git a/src/vinifera/vinifera_defines.h b/src/vinifera/vinifera_defines.h index c065fdc2..c3e7599a 100644 --- a/src/vinifera/vinifera_defines.h +++ b/src/vinifera/vinifera_defines.h @@ -45,14 +45,85 @@ //#define VINIFERA_ENABLE_SWIZZLE_DEBUG_PRINTING 1 #endif - /** - * This is the base CLSID for all COM objects. When defining a new COM CLSID, - * you must append the two digit hex number, incrementing from the previous. + * Enable debug printing of class extension creation and destruction process. + * + * WARNING: This will slow the game down when many instances are created at once. */ -#define VINIFERA_BASE_CLSID "EBE80B85-EED2-4DEF-92CA-BC0C99AF4A00" +#ifndef NDEBUG +//#define VINIFERA_ENABLE_EXTENSION_DEBUG_PRINTING 1 +#endif + /** * CLSID's for all new locomotors. */ -#define CLSID_TEST_LOCOMOTOR "EBE80B85-EED2-4DEF-92CA-BC0C99AF4A01" +#define CLSID_TEST_LOCOMOTOR "501DEF92-C7ED-448E-8FEB-7908DCE73377" + + +/** + * UUID's for all extension classes. + */ +#define UUID_UNIT_EXTENSION "17621513-3BDA-4FBD-A591-1A0B6DA0F4B9" +#define UUID_AIRCRAFT_EXTENSION "04B6C8D5-6D12-41C3-BF4B-B52F25928CF3" +#define UUID_AIRCRAFTTYPE_EXTENSION "2985D76F-00B8-4F6B-A89E-AE8149F31203" +#define UUID_ANIM_EXTENSION "4099F805-F5BC-40C2-A465-BB9C66DFE130" +#define UUID_ANIMTYPE_EXTENSION "00F9418E-171E-4B6E-83B1-D32840622DAC" +#define UUID_BUILDING_EXTENSION "B63BC5ED-23DF-4F98-8A87-E6CD79C19DB4" +#define UUID_BUILDINGTYPE_EXTENSION "F5DF6BE6-86F8-4DDB-9FF8-C353A40043A9" +#define UUID_BULLET_EXTENSION "866098FE-A846-4300-8F40-7AE058F80A9C" +#define UUID_BULLETTYPE_EXTENSION "B0A3AD67-07D3-4D40-8F06-41BF1202489E" +#define UUID_CAMPAIGN_EXTENSION "59BBAC71-C9F5-48DC-B624-D253F50B7A78" +#define UUID_CELL_EXTENSION "3D2CB3B7-8873-4055-A775-F44B24460F53" +#define UUID_FACTORY_EXTENSION "8565FEDD-1C81-4C5C-B026-F3CBAD0D00BC" +#define UUID_HOUSE_EXTENSION "7F10C6F0-F2C4-4DA4-A703-76F720E49212" +#define UUID_HOUSETYPE_EXTENSION "9146FAFE-9352-4E88-A660-AE720D80DF1C" +#define UUID_INFANTRY_EXTENSION "641151C0-8622-4453-9C2E-65110F31C147" +#define UUID_INFANTRYTYPE_EXTENSION "6A07DC7A-CCEC-4211-A194-06728659B0FF" +#define UUID_ISOTILE_EXTENSION "CFAD340B-63F1-45A0-BC52-32BEFC682201" +#define UUID_ISOTILETYPE_EXTENSION "A0E9C134-2FF9-429B-9E32-67C843A69969" +#define UUID_LIGHT_EXTENSION "B66943F4-02C8-472C-A641-247105DCFA26" +#define UUID_OVERLAY_EXTENSION "A728F930-574E-403A-8E0C-1FEDFAB3432F" +#define UUID_OVERLAYTYPE_EXTENSION "909D8654-24FF-4578-8DE4-EBBD4FB4400A" +#define UUID_PARTICLE_EXTENSION "5F6578B0-E093-4EB1-B2F6-18AC29FEAA5A" +#define UUID_PARTICLETYPE_EXTENSION "530B0567-0BAE-4EA6-A09C-491A62ED34DC" +#define UUID_PARTICLESYSTEM_EXTENSION "D6956628-11A0-46F7-B192-B10C88AE3AE7" +#define UUID_PARTICLESYSTEMTYPE_EXTENSION "D73A1DEE-D9E3-4695-90A9-26C4F1F62D59" +#define UUID_SCRIPT_EXTENSION "B5E5B269-7622-4424-B1EA-D74738D437CE" +#define UUID_SCRIPTTYPE_EXTENSION "AA9F56E7-1D25-4A0C-9381-A12FE3EECC06" +#define UUID_SIDE_EXTENSION "5B3BA576-710E-4895-A64E-8F0A26F7C4CC" +#define UUID_SMUDGE_EXTENSION "F611D411-1F93-43BD-91E3-8775451A5BD2" +#define UUID_SMUDGETYPE_EXTENSION "A5901451-8B24-49B4-A985-7B088E331633" +#define UUID_SPECIAL_EXTENSION "05844DB1-CF6A-4CC7-86BB-0D26D4CADB1C" +#define UUID_SUPERWEAPONTYPE_EXTENSION "DE57E079-BDC6-44C7-B543-50FB496E03F5" +#define UUID_TASKFORCE_EXTENSION "00F924D9-D9BA-4377-9003-EA87A4806852" +#define UUID_TEAM_EXTENSION "0EB26DF4-63C4-4F78-A31D-44092C029AF0" +#define UUID_TEAMTYPE_EXTENSION "3D99E462-372C-4839-8786-4A9B5B7DF5F7" +#define UUID_TERRAIN_EXTENSION "20894849-0FA8-4605-9932-33E0A6B6AD34" +#define UUID_TERRAINTYPE_EXTENSION "063C2121-A2B0-40BC-A99E-0980861AF5FF" +#define UUID_TRIGGER_EXTENSION "1C97F13C-6436-481E-80EE-2C561C54D520" +#define UUID_TRIGGERTYPE_EXTENSION "B315CE9A-3E3D-4D1A-AAE1-AEE337FFB449" +#define UUID_UNITTYPE_EXTENSION "6582C5FD-00D2-4FB3-AB4D-3AA4CB07BA33" +#define UUID_VOXELANIM_EXTENSION "35BADA82-EC34-48D1-A0C4-FA63D00050E0" +#define UUID_VOXELANIMTYPE_EXTENSION "EB378E30-D869-422C-9B4D-6B35B1843721" +#define UUID_WAVE_EXTENSION "1CAC2D6C-8427-46EF-B34E-9679A586FBC8" +#define UUID_TAG_EXTENSION "C792A1A6-0E33-45A4-9F06-EB65C320B0FE" +#define UUID_TAGTYPE_EXTENSION "829A522D-2E52-4AD0-A85A-AA5CBBC26B58" +#define UUID_TIBERIUM_EXTENSION "304CB21E-6D4F-4AFF-803A-795D050F5764" +#define UUID_ACTION_EXTENSION "84EC9941-BFE0-4E12-A2D8-511B92CAD3AE" +#define UUID_EVENT_EXTENSION "D65EB592-69B6-4EBA-A2FC-DADA0879DAE7" +#define UUID_WEAPONTYPE_EXTENSION "EDDB6074-03E4-4DF4-B883-DD48F583506A" +#define UUID_WARHEADTYPE_EXTENSION "DC9AD11A-AB41-42AC-A7FC-C7AF81D12017" +#define UUID_WAYPOINT_EXTENSION "C9838D5D-706C-4946-8511-EFC464C919CD" +#define UUID_ABSTRACT_EXTENSION "957275D3-8C3E-43C8-AB21-37FFA70D8E8B" +#define UUID_TUBE_EXTENSION "AFEF972F-A12F-4B8F-8C65-4EE55A079C04" +#define UUID_LIGHTSOURCE_EXTENSION "AAA984DB-720E-42F6-A9FF-C7A8C121C578" +#define UUID_EMPULSE_EXTENSION "9B06BCF6-0EAC-4D9A-9B13-1112EABFF0CC" +#define UUID_TACTICALMAP_EXTENSION "31EA713F-A141-4160-AB07-906674887839" +#define UUID_SUPERWEAPON_EXTENSION "661ED23D-FDB0-46BC-B435-CD8BC0DDE87F" +#define UUID_AITRIGGER_EXTENSION "08BE496C-282C-4E4F-9AA2-36950F7C5215" +#define UUID_AITRIGGERTYPE_EXTENSION "9C1B8527-6DC1-420B-A948-CAA81589E624" +#define UUID_NEURON_EXTENSION "4599C976-F74F-431C-A63D-E1FD6B36480F" +#define UUID_FOGGEDOBJECT_EXTENSION "7D9C5263-465F-42CE-AD81-5C057B52226F" +#define UUID_ALPHASHAPE_EXTENSION "4C8171D5-E7A7-43D1-80F3-0C285CF6B352" +#define UUID_VEINHOLEMONSTER_EXTENSION "4AD76F43-090A-44BF-BB1A-5BFDE52BC842" diff --git a/src/vinifera/vinifera_functions.cpp b/src/vinifera/vinifera_functions.cpp index ca8a85d2..ac1f411b 100644 --- a/src/vinifera/vinifera_functions.cpp +++ b/src/vinifera/vinifera_functions.cpp @@ -28,6 +28,7 @@ #include "vinifera_functions.h" #include "vinifera_globals.h" #include "vinifera_newdel.h" +#include "tibsun_globals.h" #include "cncnet4.h" #include "cncnet4_globals.h" #include "cncnet5_globals.h" @@ -45,9 +46,11 @@ #include "tacticalext.h" #include "tclassfactory.h" #include "testlocomotion.h" +#include "extension.h" #include "theatertype.h" #include "uicontrol.h" #include "debughandler.h" +#include "asserthandler.h" #include @@ -618,9 +621,20 @@ bool Vinifera_Shutdown() EBoltClass::Clear_All(); TheaterTypes.Clear(); + /** + * Cleanup global extension instances. + */ + delete OptionsExtension; + OptionsExtension = nullptr; + delete UIControls; UIControls = nullptr; + /** + * Cleanup additional extension instances. + */ + ThemeControlExtensions.Clear(); + DEV_DEBUG_INFO("Shutdown - New Count: %d, Delete Count: %d\n", Vinifera_New_Count, Vinifera_Delete_Count); return true; @@ -707,8 +721,11 @@ bool Vinifera_Register_Com_Objects() { DEBUG_INFO("Registering new com objects...\n"); - DEBUG_INFO(" TestLocomotionClass\n"); + //DEBUG_INFO(" TestLocomotionClass\n"); REGISTER_CLASS(TestLocomotionClass); + + //DEBUG_INFO(" Extension classes\n"); + Extension::Register_Class_Factories(); DEBUG_INFO(" ...OK!\n"); diff --git a/src/vinifera/vinifera_globals.cpp b/src/vinifera/vinifera_globals.cpp index 96292e8c..0dc2bc49 100644 --- a/src/vinifera/vinifera_globals.cpp +++ b/src/vinifera/vinifera_globals.cpp @@ -31,7 +31,8 @@ bool Vinifera_DeveloperMode = false; -bool Vinifera_ClassExtensionsDisabled = false; + +bool Vinifera_PerformingLoad = false; bool Vinifera_PrintFileErrors = true; bool Vinifera_FatalFileErrors = false; diff --git a/src/vinifera/vinifera_globals.h b/src/vinifera/vinifera_globals.h index af14c593..79abf62d 100644 --- a/src/vinifera/vinifera_globals.h +++ b/src/vinifera/vinifera_globals.h @@ -37,7 +37,8 @@ class TheaterTypeClass; extern bool Vinifera_DeveloperMode; -extern bool Vinifera_ClassExtensionsDisabled; + +extern bool Vinifera_PerformingLoad; extern bool Vinifera_PrintFileErrors; extern bool Vinifera_FatalFileErrors; diff --git a/src/vinifera/vinifera_hooks.cpp b/src/vinifera/vinifera_hooks.cpp index 96f3708c..4eb5d17a 100644 --- a/src/vinifera/vinifera_hooks.cpp +++ b/src/vinifera/vinifera_hooks.cpp @@ -31,6 +31,8 @@ #include "vinifera_globals.h" #include "vinifera_util.h" #include "vinifera_functions.h" +#include "vinifera_saveload.h" +#include "vinifera_gitinfo.h" #include "dsurface.h" #include "wwmouse.h" #include "blowfish.h" @@ -38,16 +40,88 @@ #include "blowpipe.h" #include "iomap.h" #include "theme.h" -#include "extension_saveload.h" +#include "tracker.h" #include "loadoptions.h" #include "language.h" -#include "vinifera_gitinfo.h" +#include "extension.h" #include "hooker.h" #include "hooker_macros.h" #include "debughandler.h" #include "asserthandler.h" +/** + * This function is for intercepting the calls to Detach_This_From_All to also + * process the object through the extension interface. + * + * @author: CCHyper + */ +static void _Detach_This_From_All_Intercept(TARGET target, bool all) +{ + Extension::Detach_This_From_All(target, all); + + Detach_This_From_All(target, all); +} + + +/** + * This function is for intercepting the calls to Free_Heaps to also process + * the extension interface. + * + * @author: CCHyper + */ +static void _Free_Heaps_Intercept() +{ + Extension::Free_Heaps(); + + Free_Heaps(); +} + + +/** + * This patch calls the Print_CRCs function from extension interface. + * + * @author: CCHyper + */ +static void _Print_CRCs_Intercept(EventClass *ev) +{ +#if 0 + /** + * Call the original function to print the object CRCs. + */ + DEBUG_INFO("About to call Print_CRCs...\n"); + Print_CRCs(ev); +#endif + + /** + * Calls a reimplementation of Print_CRCs that prints both the original + * information and the new class extension CRCs. + */ + DEBUG_INFO("About to call Extension::Print_CRCs...\n"); + Extension::Print_CRCs(ev); +} + + +/** + * This function is for intercepting the call to Clear_Scenarion in Load_All + * to flag that we are performing a load operation, which stops the game from + * creating extensions while the Windows API calls the class factories to create + * the instances. + * + * @author: tomsons26 + */ +static void _On_Load_Clear_Scenario_Intercept() +{ + Clear_Scenario(); + + /** + * Now the scenario data has been cleaned up, we can now tell the extension + * hooks that we will be creating the extension classes via the class factories. + */ + Vinifera_PerformingLoad = true; +} + + /** * Draws the version text on the main menu. * @@ -331,39 +405,27 @@ DECLARE_PATCH(_Select_Game_Clear_Globals_Patch) */ DECLARE_PATCH(_Save_Game_Put_Game_Version) { - static int version; - version = ViniferaSaveGameVersion; - - /** - * If we are in developer mode, offset the build number as these save - * files should not appear in normal game modes. - * - * For debug builds, we force an offset so they don't appear in any - * other builds or releases. - */ -#ifndef NDEBUG - version *= 3; -#else - if (Vinifera_DeveloperMode) { - version *= 2; - } -#endif - - _asm { mov edx, version }; + _asm { mov edx, ViniferaSaveGameVersion }; JMP(0x005D5064); } /** - * x + * Sanity check on the return value of Load_All(). * * @author: CCHyper */ DECLARE_PATCH(_Load_Game_Check_Return_Value) { GET_REGISTER_STATIC(const char *, filename, esi); + GET_STACK_STATIC(IStream *, pStm, esp, 0x20); + /** + * Replace this with a direct call to the Vinifera Get_All, otherwise we + * get stuck in an infinite loop. + */ +#if 0 _asm { mov ecx, [esp+0x20] } _asm { xor dl, dl } _asm { mov eax, 0x005D6BE0 } @@ -371,6 +433,11 @@ DECLARE_PATCH(_Load_Game_Check_Return_Value) _asm { test al, al } _asm { jz failure } +#endif + + if (!Vinifera_Get_All(pStm)) { + goto failure; + } DEBUG_INFO("Loading of save game \"%s\" complete.\n", filename); JMP(0x005D6B1C); @@ -389,25 +456,22 @@ DECLARE_PATCH(_Load_Game_Check_Return_Value) */ DECLARE_PATCH(_LoadOptionsClass_Read_File_Check_Game_Version) { - GET_REGISTER_STATIC(int, version, eax); - static int ver; + GET_REGISTER_STATIC(FileEntryClass *, file, ebp); + GET_REGISTER_STATIC(int, file_version, eax); + GET_REGISTER_OFFSET_STATIC(WIN32_FIND_DATA *, wfd, esp, 0x348); + //GET_REGISTER_OFFSET_STATIC(WWSaveLoadClass *, saveload, esp, 0x0C); /** * If the version in the save file does not match our build * version exactly, then don't add this file to the listing. */ - ver = ViniferaSaveGameVersion; -#ifndef NDEBUG - ver *= 3; -#else - if (Vinifera_DeveloperMode) { - ver *= 2; - } -#endif - if (version != ver) { + if (file_version != ViniferaSaveGameVersion) { + DEBUG_WARNING("Save file \"%s\" is incompatible! File version 0x%X, Expected version 0x%X.\n", wfd->cFileName, file_version, ViniferaSaveGameVersion); JMP(0x00505AAD); } + DEV_DEBUG_INFO("Save file \"%s\" is compatible.\n", wfd->cFileName); + JMP(0x00505ABB); } @@ -562,7 +626,7 @@ DECLARE_PATCH(_Load_All_Vinifera_Data) /** * Call to the Vinifera data stream loader. */ - if (!Vinifera_Load_All(pStm)) { + if (!Vinifera_Get_All(pStm)) { goto failed; } @@ -631,33 +695,26 @@ DECLARE_PATCH(_Do_Lose_Create_Lose_WWMessageBox) { #if !defined(RELEASE) && defined(NDEBUG) /** - * We disable loading in non-release builds or if extensions are disabled. + * We disable loading in non-release. */ - if (!Vinifera_ClassExtensionsDisabled) { - Vinifera_Do_WWMessageBox("Saving and Loading is disabled for non-release builds.", Text_String(TXT_OK)); - - } else { -#endif - - /** - * If no save games are available, notify the user and return back - * and reissue the main dialog. - */ - if (!_Save_Games_Available()) { - Vinifera_Do_WWMessageBox("No saved games available.", Text_String(TXT_OK)); - goto retry_dialog; - } - - /** - * Show the load game dialog. - */ - ret = _Do_Load_Dialog(); - if (ret) { - Theme.Stop(); - JMP(0x005DCE48); - } + Vinifera_Do_WWMessageBox("Saving and Loading is disabled for non-release builds.", Text_String(TXT_OK)); +#else + /** + * If no save games are available, notify the user and return back + * and reissue the main dialog. + */ + if (!_Save_Games_Available()) { + Vinifera_Do_WWMessageBox("No saved games available.", Text_String(TXT_OK)); + goto retry_dialog; + } -#if !defined(RELEASE) && defined(NDEBUG) + /** + * Show the load game dialog. + */ + ret = _Do_Load_Dialog(); + if (ret) { + Theme.Stop(); + JMP(0x005DCE48); } #endif @@ -700,6 +757,17 @@ static void Decrypt_Serial(char *buffer) } +/** + * Export function that returns the supported save file version. + * + * @author: CCHyper + */ +__declspec(dllexport) uint32_t __cdecl Vinifera_Save_File_Version() +{ + return Extension::Get_Save_Version_Number(); +} + + void Vinifera_Hooks() { /** @@ -777,16 +845,16 @@ void Vinifera_Hooks() Patch_Jump(0x0060DBFF, &_SwizzleManagerClass_Process_Tables_Remap_Failed_Error); /** - * Enable and hook the new save and load system only if extensions are disabled. + * Patch in the new save and load system functions. */ - if (Vinifera_ClassExtensionsDisabled) { - Patch_Jump(0x005D68F7, &_Put_All_Vinifera_Data); - Patch_Jump(0x005D78ED, &_Load_All_Vinifera_Data); + Patch_Call(0x005D5307, &Vinifera_Put_All); + Patch_Call(0x005D6B17, &Vinifera_Get_All); - Patch_Jump(0x004B6D96, &_SaveLoad_Disable_Buttons); - Patch_Jump(0x0057FF8B, &_NewMenuClass_Process_Disable_Load_Button_Firestorm); - Patch_Jump(0x0058004D, &_NewMenuClass_Process_Disable_Load_Button_TiberianSun); - } + /** + * Set the save game version. + */ + ViniferaSaveGameVersion = Extension::Get_Save_Version_Number(); + DEBUG_INFO("Save game version number: 0x%X\n", ViniferaSaveGameVersion); Patch_Jump(0x005DCDFD, &_Do_Lose_Create_Lose_WWMessageBox); @@ -821,4 +889,114 @@ void Vinifera_Hooks() Patch_Byte_Range(0x0057FE2A, 0x90, 10); // NewMenuClass::Process_Game_Select Patch_Byte_Range(0x00580377, 0x90, 10); // NewMenuClass::Process_Game_Select #endif + + /** + * Various patches to intercept the games object tracking and heap processing. + */ + Patch_Call(0x0053DF7A, &_Free_Heaps_Intercept); // MapSeedClass::Init_Random + Patch_Call(0x005DC590, &_Free_Heaps_Intercept); // Clear_Scenario + Patch_Call(0x00601BA2, &_Free_Heaps_Intercept); // Game_Shutdown + + Patch_Call(0x0040DBB3, &_Detach_This_From_All_Intercept); // AircraftClass::~AircraftClass + Patch_Call(0x0040F123, &_Detach_This_From_All_Intercept); // AircraftClass_Fall_To_Death + Patch_Call(0x0040FCD3, &_Detach_This_From_All_Intercept); // AircraftTypeClass::~AircraftTypeClass + Patch_Call(0x00410223, &_Detach_This_From_All_Intercept); // AircraftTypeClass::~AircraftTypeClass + Patch_Call(0x004142C6, &_Detach_This_From_All_Intercept); // AnimClass::~AnimClass + Patch_Call(0x00426662, &_Detach_This_From_All_Intercept); // BuildingClass::~BuildingClass + Patch_Call(0x0043F94D, &_Detach_This_From_All_Intercept); // BuildingTypeClass::~BuildingTypeClass + Patch_Call(0x0044407D, &_Detach_This_From_All_Intercept); // BuildingTypeClass::~BuildingTypeClass + Patch_Call(0x004445F3, &_Detach_This_From_All_Intercept); // BulletClass::~BulletClass + Patch_Call(0x004474D3, &_Detach_This_From_All_Intercept); // BulletClass::~BulletClass + Patch_Call(0x00447DC3, &_Detach_This_From_All_Intercept); // BulletTypeClass::~BulletTypeClass + Patch_Call(0x00448723, &_Detach_This_From_All_Intercept); // BulletTypeClass::~BulletTypeClass + Patch_Call(0x00448AE3, &_Detach_This_From_All_Intercept); // CampaignClass::~CampaignClass + Patch_Call(0x00448EF3, &_Detach_This_From_All_Intercept); // CampaignClass::~CampaignClass + Patch_Call(0x00456A26, &_Detach_This_From_All_Intercept); // CellClass::Wall_Update + Patch_Call(0x00456A58, &_Detach_This_From_All_Intercept); // CellClass::Wall_Update + Patch_Call(0x00456A7F, &_Detach_This_From_All_Intercept); // CellClass::Wall_Update + Patch_Call(0x00456AAB, &_Detach_This_From_All_Intercept); // CellClass::Wall_Update + Patch_Call(0x00456AD2, &_Detach_This_From_All_Intercept); // CellClass::Wall_Update + Patch_Call(0x004571F9, &_Detach_This_From_All_Intercept); // CellClass::Reduce_Wall + Patch_Call(0x004927D3, &_Detach_This_From_All_Intercept); // EMPulseClass::~EMPulseClass + Patch_Call(0x004931E3, &_Detach_This_From_All_Intercept); // EMPulseClass::~EMPulseClass + Patch_Call(0x00496DB3, &_Detach_This_From_All_Intercept); // FactoryClass::~FactoryClass + Patch_Call(0x00497AA3, &_Detach_This_From_All_Intercept); // FactoryClass::~FactoryClass + Patch_Call(0x004BB6DB, &_Detach_This_From_All_Intercept); // HouseClass::~HouseClass + Patch_Call(0x004CDE93, &_Detach_This_From_All_Intercept); // HouseTypeClass::~HouseTypeClass + Patch_Call(0x004CE603, &_Detach_This_From_All_Intercept); // HouseTypeClass::~HouseTypeClass + Patch_Call(0x004D22DC, &_Detach_This_From_All_Intercept); // InfantryClass::~InfantryClass + Patch_Call(0x004DA3B4, &_Detach_This_From_All_Intercept); // InfantryTypeClass::~InfantryTypeClass + Patch_Call(0x004DB133, &_Detach_This_From_All_Intercept); // InfantryTypeClass::~InfantryTypeClass + Patch_Call(0x004F2173, &_Detach_This_From_All_Intercept); // IsometricTileClass::~IsometricTileClass + Patch_Call(0x004F23E3, &_Detach_This_From_All_Intercept); // IsometricTileClass::~IsometricTileClass + Patch_Call(0x004F3344, &_Detach_This_From_All_Intercept); // IsometricTileTypeClass::~IsometricTileTypeClass + Patch_Call(0x005015E3, &_Detach_This_From_All_Intercept); // LightSourceClass::~LightSourceClass + Patch_Call(0x00501DA3, &_Detach_This_From_All_Intercept); // LightSourceClass::~LightSourceClass + Patch_Call(0x00585F9E, &_Detach_This_From_All_Intercept); // ObjectClass::Detach_All + Patch_Call(0x00586DB5, &_Detach_This_From_All_Intercept); // ObjectClass::entry_E4 + Patch_Call(0x0058B563, &_Detach_This_From_All_Intercept); // OverlayClass::~OverlayClass + Patch_Call(0x0058CB13, &_Detach_This_From_All_Intercept); // OverlayClass::~OverlayClass + Patch_Call(0x0058D196, &_Detach_This_From_All_Intercept); // OverlayTypeClass::~OverlayTypeClass + Patch_Call(0x0058DC86, &_Detach_This_From_All_Intercept); // OverlayTypeClass::~OverlayTypeClass + Patch_Call(0x005A32FA, &_Detach_This_From_All_Intercept); // ParticleClass::~ParticleClass + Patch_Call(0x005A503A, &_Detach_This_From_All_Intercept); // ParticleClass::~ParticleClass + Patch_Call(0x005A56D4, &_Detach_This_From_All_Intercept); // ParticleSystemClass::~ParticleSystemClass + Patch_Call(0x005AE573, &_Detach_This_From_All_Intercept); // ParticleSystemTypeClass::~ParticleSystemTypeClass + Patch_Call(0x005AEC63, &_Detach_This_From_All_Intercept); // ParticleSystemTypeClass::~ParticleSystemTypeClass + Patch_Call(0x005AF153, &_Detach_This_From_All_Intercept); // ParticleTypeClass::~ParticleTypeClass + Patch_Call(0x005AFC33, &_Detach_This_From_All_Intercept); // ParticleTypeClass::~ParticleTypeClass + Patch_Call(0x005E78C3, &_Detach_This_From_All_Intercept); // ScriptClass::~ScriptClass + Patch_Call(0x005E7B83, &_Detach_This_From_All_Intercept); // ScriptTypeClass::~ScriptTypeClass + Patch_Call(0x005E81E3, &_Detach_This_From_All_Intercept); // ScriptClass::~ScriptClass + Patch_Call(0x005E8293, &_Detach_This_From_All_Intercept); // ScriptTypeClass::~ScriptTypeClass + Patch_Call(0x005F1AE3, &_Detach_This_From_All_Intercept); // SideClass::~SideClass + Patch_Call(0x005F1D93, &_Detach_This_From_All_Intercept); // SideClass::~SideClass + Patch_Call(0x005FAAD3, &_Detach_This_From_All_Intercept); // SmudgeClass::~SmudgeClass + Patch_Call(0x005FAF03, &_Detach_This_From_All_Intercept); // SmudgeClass::~SmudgeClass + Patch_Call(0x005FB313, &_Detach_This_From_All_Intercept); // SmudgeTypeClass::~SmudgeTypeClass + Patch_Call(0x005FC023, &_Detach_This_From_All_Intercept); // SmudgeTypeClass::~SmudgeTypeClass + Patch_Call(0x00618D03, &_Detach_This_From_All_Intercept); // TActionClass::~TActionClass + Patch_Call(0x0061DAD3, &_Detach_This_From_All_Intercept); // TActionClass::~TActionClass + Patch_Call(0x0061E4B6, &_Detach_This_From_All_Intercept); // TagClass::~TagClass + Patch_Call(0x0061E73B, &_Detach_This_From_All_Intercept); // TagClass::~TagClass + Patch_Call(0x0061E9AA, &_Detach_This_From_All_Intercept); // TagClass::Spring + Patch_Call(0x0061F164, &_Detach_This_From_All_Intercept); // TagTypeClass::~TagTypeClass + Patch_Call(0x00621503, &_Detach_This_From_All_Intercept); // TaskForceClass::~TaskForceClass + Patch_Call(0x00621E43, &_Detach_This_From_All_Intercept); // TaskForceClass::~TaskForceClass + Patch_Call(0x006224E3, &_Detach_This_From_All_Intercept); // TeamClass::~TeamClass + Patch_Call(0x00627EF3, &_Detach_This_From_All_Intercept); // TeamTypeClass::~TeamTypeClass + Patch_Call(0x00629293, &_Detach_This_From_All_Intercept); // TeamTypeClass::~TeamTypeClass + Patch_Call(0x0063F188, &_Detach_This_From_All_Intercept); // TerrainClass::~TerrainClass + Patch_Call(0x00640C38, &_Detach_This_From_All_Intercept); // TerrainClass::~TerrainClass + Patch_Call(0x00641653, &_Detach_This_From_All_Intercept); // TerrainTypeClass::~TerrainTypeClass + Patch_Call(0x00641D83, &_Detach_This_From_All_Intercept); // TerrainTypeClass::~TerrainTypeClass + Patch_Call(0x00642223, &_Detach_This_From_All_Intercept); // TEventClass::~TEventClass + Patch_Call(0x00642F23, &_Detach_This_From_All_Intercept); // TEventClass::~TEventClass + Patch_Call(0x00644A45, &_Detach_This_From_All_Intercept); // TiberiumClass::~TiberiumClass + Patch_Call(0x006491A3, &_Detach_This_From_All_Intercept); // TriggerClass::~TriggerClass + Patch_Call(0x00649943, &_Detach_This_From_All_Intercept); // TriggerClass::~TriggerClass + Patch_Call(0x00649E03, &_Detach_This_From_All_Intercept); // TriggerTypeClass::~TriggerTypeClass + Patch_Call(0x0064AFD3, &_Detach_This_From_All_Intercept); // TubeClass::~TubeClass + Patch_Call(0x0064B603, &_Detach_This_From_All_Intercept); // TubeClass::~TubeClass + Patch_Call(0x0064D8A9, &_Detach_This_From_All_Intercept); // UnitClass::~UnitClass + Patch_Call(0x0065BAD3, &_Detach_This_From_All_Intercept); // UnitTypeClass::~UnitTypeClass + Patch_Call(0x0065C793, &_Detach_This_From_All_Intercept); // UnitTypeClass::~UnitTypeClass + Patch_Call(0x0065DF23, &_Detach_This_From_All_Intercept); // VoxelAnimClass::~VoxelAnimClass + Patch_Call(0x0065F5A3, &_Detach_This_From_All_Intercept); // VoxelAnimTypeClass::~VoxelAnimTypeClass + Patch_Call(0x00660093, &_Detach_This_From_All_Intercept); // VoxelAnimTypeClass::~VoxelAnimTypeClass + Patch_Call(0x00661227, &_Detach_This_From_All_Intercept); // VeinholeMonsterClass::~VeinholeMonsterClass + Patch_Call(0x00661C00, &_Detach_This_From_All_Intercept); // VeinholeMonsterClass::Take_Damage + Patch_Call(0x0066EF73, &_Detach_This_From_All_Intercept); // WarheadTypeClass::~WarheadTypeClass + Patch_Call(0x0066FA93, &_Detach_This_From_All_Intercept); // WarheadTypeClass::~WarheadTypeClass + Patch_Call(0x006702D4, &_Detach_This_From_All_Intercept); // WaveClass::~WaveClass + Patch_Call(0x00672E73, &_Detach_This_From_All_Intercept); // WaveClass::~WaveClass + Patch_Call(0x00673563, &_Detach_This_From_All_Intercept); // WaypointPathClass::~WaypointPathClass + Patch_Call(0x00673AA3, &_Detach_This_From_All_Intercept); // WaypointPathClass::~WaypointPathClass + Patch_Call(0x00680C54, &_Detach_This_From_All_Intercept); // WeaponTypeClass::~WeaponTypeClass + Patch_Call(0x006818F4, &_Detach_This_From_All_Intercept); // WeaponTypeClass::~WeaponTypeClass + + Patch_Call(0x005B1363, &_Print_CRCs_Intercept); + Patch_Call(0x005B5340, &_Print_CRCs_Intercept); + + Patch_Call(0x005D6BEC, &_On_Load_Clear_Scenario_Intercept); // Load_All } diff --git a/src/vinifera/vinifera_saveload.cpp b/src/vinifera/vinifera_saveload.cpp new file mode 100644 index 00000000..d19cae9c --- /dev/null +++ b/src/vinifera/vinifera_saveload.cpp @@ -0,0 +1,667 @@ +/******************************************************************************* +/* O P E N S O U R C E -- V I N I F E R A ** +/******************************************************************************* + * + * @project Vinifera + * + * @file VINIFERA_SAVELOAD.CPP + * + * @authors CCHyper + * + * @brief Utility functions for saving and loading. + * + * @license Vinifera is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version + * 3 of the License, or (at your option) any later version. + * + * Vinifera is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. + * If not, see . + * + ******************************************************************************/ +#include "vinifera_saveload.h" +#include "tibsun_globals.h" +#include "tibsun_functions.h" +#include "tibsun_util.h" +#include "vinifera_util.h" +#include "vinifera_gitinfo.h" +#include "wstring.h" +#include "saveload.h" +#include "extension.h" +#include "debughandler.h" + +#include "aircraft.h" +#include "aircrafttype.h" +#include "anim.h" +#include "animtype.h" +#include "building.h" +#include "buildingtype.h" +#include "buildinglight.h" +#include "bullet.h" +#include "bullettype.h" +#include "campaign.h" +#include "empulse.h" +#include "factory.h" +#include "foggedobject.h" +#include "side.h" +#include "house.h" +#include "housetype.h" +#include "infantry.h" +#include "infantrytype.h" +#include "isotile.h" +#include "isotiletype.h" +#include "lightsource.h" +#include "objecttype.h" +#include "overlay.h" +#include "overlaytype.h" +#include "particle.h" +#include "particletype.h" +#include "particlesys.h" +#include "particlesystype.h" +#include "radarevent.h" +#include "script.h" +#include "scripttype.h" +#include "smudge.h" +#include "smudgetype.h" +#include "super.h" +#include "supertype.h" +#include "taskforce.h" +#include "tag.h" +#include "tagtype.h" +#include "team.h" +#include "teamtype.h" +#include "trigger.h" +#include "triggertype.h" +#include "aitrigtype.h" +#include "terrain.h" +#include "terraintype.h" +#include "tiberium.h" +#include "unit.h" +#include "unittype.h" +#include "voxelanim.h" +#include "voxelanimtype.h" +#include "warheadtype.h" +#include "wave.h" +#include "weapontype.h" +#include "veinholemonster.h" +#include "taction.h" +#include "tevent.h" +#include "tube.h" +#include "waypointpath.h" +#include "alphashape.h" + +#include "scenario.h" +#include "endgame.h" +#include "rules.h" +#include "iomap.h" +#include "logic.h" +#include "tactical.h" +#include "session.h" +#include "addon.h" +#include "ccini.h" + + +/** + * Constant of the current build version number. This number should be + * a sum of all the extended class sizes plus the build date. + */ +unsigned ViniferaSaveGameVersion = 0x0; + + +/** + * Save file header. + */ +typedef struct ViniferaSaveFileHeaderStruct +{ + // Header marker. + char Marker[20]; + + // Git commit hash. + char CommitHash[40]; + + // Constant header marker to check for. + static const char * Marker_String() { return "VINIFERA_SAVE_FILE"; } + +private: + char _padding[1024 + - sizeof(Marker) + - sizeof(CommitHash)]; +}; +static_assert(sizeof(ViniferaSaveFileHeaderStruct), "ViniferaSaveFileHeaderStruct must be 1024 bytes in size!"); + +static ViniferaSaveFileHeaderStruct ViniferaSaveFileHeader; + + +/** + * Saves the header marker for validating data on load. + * + * @author: CCHyper + */ +static bool Vinifera_Save_Header(IStream *pStm) +{ + if (!pStm) { + return false; + } + + /** + * Save the new header. + */ + std::memset(&ViniferaSaveFileHeader, 0, sizeof(ViniferaSaveFileHeader)); + + strncpy(ViniferaSaveFileHeader.Marker, ViniferaSaveFileHeaderStruct::Marker_String(), sizeof(ViniferaSaveFileHeader.Marker)); + strncpy(ViniferaSaveFileHeader.CommitHash, Vinifera_Git_Hash(), sizeof(ViniferaSaveFileHeader.CommitHash)); + + HRESULT hr = pStm->Write(&ViniferaSaveFileHeader, sizeof(ViniferaSaveFileHeader), nullptr); + if (FAILED(hr)) { + return false; + } + + return true; +} + + +/** + * Loads the save data header marker. + * + * @author: CCHyper + */ +static bool Vinifera_Load_Header(IStream *pStm) +{ + if (!pStm) { + return false; + } + + HRESULT hr; + + /** + * Load the new header. + */ + std::memset(&ViniferaSaveFileHeader, 0, sizeof(ViniferaSaveFileHeader)); + + hr = pStm->Read(&ViniferaSaveFileHeader, sizeof(ViniferaSaveFileHeader), nullptr); + if (FAILED(hr)) { + return false; + } + + if (std::strncmp(ViniferaSaveFileHeader.Marker, ViniferaSaveFileHeaderStruct::Marker_String(), sizeof(ViniferaSaveFileHeader.Marker)) != 0) { + DEBUG_WARNING("Invalid header in save file!"); + return false; + } + + if (std::strncmp(ViniferaSaveFileHeader.CommitHash, Vinifera_Git_Hash(), sizeof(ViniferaSaveFileHeader.CommitHash)) != 0) { + DEBUG_WARNING("Git hash mismatch in save file!"); + //return false; + } + + return true; +} + + +/** + * Saves all active objects to the data stream. + * + * @author: CCHyper + */ +template +static HRESULT Vinifera_Save_Vector(LPSTREAM &pStm, DynamicVectorClass &list, const char *heap_name) +{ + DEBUG_INFO("Saving %s...\n", heap_name); + + /** + * Save the number of instances of this class. + */ + int count = list.Count(); + HRESULT hr = pStm->Write(&count, sizeof(count), nullptr); + if (FAILED(hr)) { + DEBUG_ERROR(" Failed to read count!\n"); + return hr; + } + + if (count <= 0) { + DEV_DEBUG_INFO(" Count was zero, skipping save.\n"); + return hr; + } + + DEBUG_INFO(" Count: %d\n", list.Count()); + + /** + * Save each instance of this class. + */ + for (int index = 0; index < count; ++index) { + + /** + * Tell the extension class to persist itself into the data stream. + */ + IPersistStream *lpPS = nullptr; + hr = list[index]->QueryInterface(__uuidof(IPersistStream), (LPVOID *)&lpPS); + if (FAILED(hr)) { + DEBUG_ERROR(" QueryInterface failed!\n"); + return hr; + } + + /** + * Save the object itself. + */ + hr = OleSaveToStream(lpPS, pStm); + if (FAILED(hr)) { + DEBUG_ERROR(" OleSaveToStream failed!\n"); + return false; + } + + /** + * Release the interface. + */ + hr = lpPS->Release(); + if (FAILED(hr)) { + DEBUG_ERROR(" Release failed!\n"); + return false; + } + + } + + return hr; +} + + +/** + * Loads all active objects form the data stream. + * + * @author: CCHyper + */ +template +static bool Vinifera_Load_Vector(IStream *pStm, DynamicVectorClass &list, const char *heap_name) +{ + DEBUG_INFO("Loading %s...\n", heap_name); + + /** + * Read the number of instances of this class. + */ + int count = 0; + HRESULT hr = pStm->Read(&count, sizeof(count), nullptr); + if (FAILED(hr)) { + return hr; + } + + if (count <= 0) { + DEV_DEBUG_INFO(" Count was zero, skipping load.\n"); + return hr; + } + + DEBUG_INFO(" Count: %d\n", count); + + /** + * Read each class instance. + */ + for (int index = 0; index < count; ++index) { + + /** + * Load the object. + */ + IUnknown *spUnk = nullptr; + hr = OleLoadFromStream(pStm, __uuidof(IUnknown), (LPVOID *)&spUnk); + if (FAILED(hr)) { + DEBUG_ERROR(" OleLoadFromStream failed!\n"); + return hr; + } + + } + + return hr; +} + + +/** + * Saves the game state to the file stream. + */ +bool Vinifera_Put_All(IStream *pStm, bool save_net) +{ + /** + * Save the Vinifera data marker which can be used to verify + * the state of the data to follow on load. + */ + DEBUG_INFO("Saving Vinifera header\n"); + if (!Vinifera_Save_Header(pStm)) { + DEBUG_ERROR("\t***** FAILED!\n"); + return false; + } + + /** + * Save the scenario global information. + */ + DEBUG_INFO("Saving Scenario...\n"); + Scen->Save(pStm); + + DEBUG_INFO("Saving EndGame...\n"); + EndGame.Save(pStm); + + DEBUG_INFO("Saving Rule...\n"); + Rule->Save(pStm); + + if (FAILED(Vinifera_Save_Vector(pStm, AnimTypes, "AnimTypes"))) { return false; } + + /** + * Save the map. The map must be saved first, since it saves the Theater. + */ + DEBUG_INFO("Saving Map...\n"); + if (FAILED(Map.Save(pStm))) { return false; } + + if (FAILED(Vinifera_Save_Vector(pStm, Tubes, "Tunnels"))) { return false; } + + /** + * Save miscellaneous variables. + */ + DEBUG_INFO("Saving Misc. Values...\n"); + if (FAILED(Save_Misc_Values(pStm))) { return false; } + + /** + * Save the Logic & Map layers. + */ + DEBUG_INFO("Saving Logic...\n"); + if (FAILED(Logic.Save(pStm))) { return false; } + + DEBUG_INFO("Saving TacticalMap...\n"); + { + if (FAILED(OleSaveToStream(TacticalMap, pStm))) { return false; } + } + + /** + * Save all game objects. This code saves every object that's stored in a DynamicVector class. + */ + if (FAILED(Vinifera_Save_Vector(pStm, HouseTypes, "HouseTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Houses, "Houses"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Units, "Units"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, UnitTypes, "UnitTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, InfantryTypes, "InfantryTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Infantry, "Infantry"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, BuildingTypes, "BuildingTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Buildings, "Buildings"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, AircraftTypes, "AircraftTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Aircrafts, "Aircraft"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Anims, "Anims"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, TaskForces, "TaskForces"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, TeamTypes, "TeamTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Teams, "Teams"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, ScriptTypes, "ScriptTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Scripts, "Scripts"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, TagTypes, "TagTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Tags, "Tags"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, TriggerTypes, "TriggerTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Triggers, "Triggers"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, AITriggerTypes, "AITriggerTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, TActions, "Actions"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, TEvents, "Events"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Factories, "Factories"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, VoxelAnimTypes, "VoxelAnimTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, VoxelAnims, "VoxelAnims"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, WarheadTypes, "Warheads"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, WeaponTypes, "Weapons"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, ParticleTypes, "ParticleTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Particles, "Particles"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, ParticleSystemTypes, "ParticleSystemTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, ParticleSystems, "ParticleSystems"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, BulletTypes, "BulletTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Bullets, "Bullets"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, WaypointPaths, "WaypointPaths"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, SmudgeTypes, "SmudgeTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, OverlayTypes, "OverlayTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, LightSources, "LightSources"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, BuildingLights, "BuildingLights"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Sides, "Sides"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Tiberiums, "Tiberiums"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Empulses, "Empulses"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, SuperWeaponTypes, "SuperWeaponTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Supers, "SuperWeapons"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, TerrainTypes, "TerrianTypes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Terrains, "Terrains"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, FoggedObjects, "FoggedObjects"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, AlphaShapes, "AlphaShapes"))) { return false; } + if (FAILED(Vinifera_Save_Vector(pStm, Waves, "Waves"))) { return false; } + { DEBUG_INFO("Saving VeinholeMonsters...\n"); if (FAILED(VeinholeMonsterClass::Save_All(pStm))) { DEBUG_ERROR("\t***** FAILED!\n"); return false; } } + { DEBUG_INFO("Saving RadarEvents...\n"); if (!RadarEventClass::Save_All(pStm)) { DEBUG_ERROR("\t***** FAILED!\n"); return false; } } + + /** + * Save skirmish values. + */ + if (Session.Type == GAME_SKIRMISH) { + DEBUG_INFO("Saving Skirmish Session.Options...\n"); + if (!Session.Options.Save(pStm)) { return false; } + } + + /** + * Save class extensions here. + */ + DEBUG_INFO("Saving class extensions\n"); + if (!Extension::Save(pStm)) { + DEBUG_ERROR("\t***** FAILED!\n"); + return false; + } + + return true; +} + + +/** + * Loads the game state to the file stream in the same way it was saved out. + * + * @warning: If this routine returns false, the entire game will be in an + * unknown state, so the scenario will have to be re-initialized! + */ +bool Vinifera_Get_All(IStream *pStm, bool load_net) +{ + /** + * Load the Vinifera data marker which can be used to verify + * the state of the data to follow. + */ + DEBUG_INFO("Loading Vinifera header\n"); + if (!Vinifera_Load_Header(pStm)) { + DEBUG_ERROR("\t***** FAILED!\n"); + ShowCursor(TRUE); + MessageBoxA(MainWindow, "Failed to load Vinifera save-file header!\n", "Vinifera", MB_OK|MB_ICONEXCLAMATION); + Vinifera_Generate_Mini_Dump(); + Fatal("Failed to load Vinifera save-file header!\n"); + return false; + } + + /** + * Clear the existing scenario data, ready for loading. + */ + DEBUG_INFO("About to call Clear_Scenario()...\n"); + Clear_Scenario(); + + /** + * Load the scenario global information. + */ + DEBUG_INFO("Loading Scenario...\n"); + Scen->Load(pStm); + + Addon_4071C0(ADDON_NONE); + + DEBUG_INFO("Setting required addon to '%d'\n", Scen->RequiredAddOn); + Set_Required_Addon(Scen->RequiredAddOn); + + if (!Addon_Installed(Scen->RequiredAddOn)) { + DEBUG_ERROR("Addon '%d' is not installed!\n", Scen->RequiredAddOn); + return false; + } + + Addon_407190(Scen->RequiredAddOn); + + DEBUG_INFO("About to call Prep_For_Side()...\n"); + if (!Prep_For_Side(Scen->IsGDI ? SIDE_GDI : SIDE_NOD)) { + DEBUG_ERROR("Prep_For_Side() failed!\n"); + return false; + } + + { + Rect tactical_rect = Get_Tactical_Rect(); + Rect composite_rect(0, 0, tactical_rect.Width, ScreenRect.Height); + Rect tile_rect(0, 0, tactical_rect.Width, ScreenRect.Height); + Rect sidebar_rect(tactical_rect.X, tactical_rect.Y, SidebarClass::SIDE_WIDTH, ScreenRect.Height); + DEBUG_INFO("About to call Allocate_Surfaces()...\n"); + Allocate_Surfaces(&ScreenRect, &composite_rect, &tile_rect, &sidebar_rect); + + DEBUG_INFO("About to call Map.Set_View_Dimensions()...\n"); + Map.Set_View_Dimensions(tactical_rect); + } + + DEBUG_INFO("Loading EndGame...\n"); + EndGame.Load(pStm); + + Init_Theater(Scen->Theater); + + DEBUG_INFO("About to call Load_Art_INI()...\n"); + RulesClass::Load_Art_INI(); + + if (Addon_Enabled(ADDON_FIRESTORM)) { + DEBUG_INFO("About to call Load_ArtFS_INI()...\n"); + RulesClass::Load_ArtFS_INI(); + } + + DEBUG_INFO("Loading Rule...\n"); + Rule->Load(pStm); + + DEBUG_INFO("About to call Prep_Speech_For_Side()...\n"); + if (!Prep_Speech_For_Side(Scen->IsGDI ? SIDE_GDI : SIDE_NOD)) { + DEBUG_ERROR("Prep_Speech_For_Side() failed!\n"); + return false; + } + + if (FAILED(Vinifera_Load_Vector(pStm, AnimTypes, "AnimTypes"))) { return false; } + + /** + * Load the map. The map must be loaded first, since it initialises the Theater. + */ + DEBUG_INFO("Loading Map...\n"); + if (FAILED(Map.Load(pStm))) { return false; } + + if (FAILED(Vinifera_Load_Vector(pStm, Tubes, "Tunnels"))) { return false; } + + /** + * Load miscellaneous variables. + */ + DEBUG_INFO("Loading Misc. Values...\n"); + if (FAILED(Load_Misc_Values(pStm))) { return false; } + + DEBUG_INFO("About to call Map.Clear_SubZones()...\n"); + Map.Clear_SubZones(); + + /** + * Load the Logic & Map layers. + */ + DEBUG_INFO("Loading Logic...\n"); + if (FAILED(Logic.Load(pStm))) { return false; } + + DEBUG_INFO("Loading TacticalMap...\n"); + { + delete TacticalMap; + IUnknown *spUnk = nullptr; + if (FAILED(OleLoadFromStream(pStm, __uuidof(IUnknown), (LPVOID *)&spUnk))) { return false; } + } + + /** + * Load all game objects. This code loads every object that's stored in a DynamicVector class. + */ + if (FAILED(Vinifera_Load_Vector(pStm, HouseTypes, "HouseTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Houses, "Houses"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Units, "Units"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, UnitTypes, "UnitTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, InfantryTypes, "InfantryTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Infantry, "Infantry"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, BuildingTypes, "BuildingTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Buildings, "Buildings"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, AircraftTypes, "AircraftTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Aircrafts, "Aircraft"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Anims, "Anims"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, TaskForces, "TaskForces"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, TeamTypes, "TeamTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Teams, "Teams"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, ScriptTypes, "ScriptTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Scripts, "Scripts"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, TagTypes, "TagTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Tags, "Tags"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, TriggerTypes, "TriggerTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Triggers, "Triggers"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, AITriggerTypes, "AITriggerTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, TActions, "Actions"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, TEvents, "Events"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Factories, "Factories"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, VoxelAnimTypes, "VoxelAnimTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, VoxelAnims, "VoxelAnims"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, WarheadTypes, "Warheads"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, WeaponTypes, "Weapons"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, ParticleTypes, "ParticleTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Particles, "Particles"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, ParticleSystemTypes, "ParticleSystemTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, ParticleSystems, "ParticleSystems"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, BulletTypes, "BulletTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Bullets, "Bullets"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, WaypointPaths, "WaypointPaths"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, SmudgeTypes, "SmudgeTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, OverlayTypes, "OverlayTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, LightSources, "LightSources"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, BuildingLights, "BuildingLights"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Sides, "Sides"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Tiberiums, "Tiberiums"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Empulses, "Empulses"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, SuperWeaponTypes, "SuperWeaponTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Supers, "SuperWeapons"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, TerrainTypes, "TerrianTypes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Terrains, "Terrains"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, FoggedObjects, "FoggedObjects"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, AlphaShapes, "AlphaShapes"))) { return false; } + if (FAILED(Vinifera_Load_Vector(pStm, Waves, "Waves"))) { return false; } + { DEBUG_INFO("Loading VeinholeMonsters...\n"); if (FAILED(VeinholeMonsterClass::Load_All(pStm))) { DEBUG_ERROR("\t***** FAILED!\n"); return false; } } + { DEBUG_INFO("Loading RadarEvents...\n"); if (!RadarEventClass::Load_All(pStm)) { DEBUG_ERROR("\t***** FAILED!\n"); return false; } } + + /** + * Load skirmish values. + */ + if (Session.Type == GAME_SKIRMISH) { + DEBUG_INFO("Loading Skirmish Session.Options...\n"); + if (!Session.Options.Load(pStm)) { return false; } + } + + /** + * Load class extensions here. + */ + DEBUG_INFO("Loading class extensions\n"); + if (!Extension::Load(pStm)) { + DEBUG_ERROR("\t***** FAILED!\n"); + return false; + } + + Map.Flag_To_Redraw(2); + + //Vinifera_Remap_Extension_Pointers(); + + /** + * We have finished loading the game data, reset the load flag. + */ + Vinifera_PerformingLoad = false; + + return true; +} + + +/** + * Request remapping of all the extension pointers so the swizzle manager + * can fix up any reference to extension classes. + * + * @author: CCHyper + */ +bool Vinifera_Remap_Extension_Pointers() +{ + DEBUG_INFO("Remapping extension pointers\n"); + if (!Extension::Request_Pointer_Remap()) { + DEBUG_ERROR("\t***** FAILED!\n"); + return false; + } + + return true; +} diff --git a/src/vinifera/vinifera_saveload.h b/src/vinifera/vinifera_saveload.h index 8aafb6c0..d3a1bd5c 100644 --- a/src/vinifera/vinifera_saveload.h +++ b/src/vinifera/vinifera_saveload.h @@ -8,7 +8,7 @@ * * @authors CCHyper * - * @brief + * @brief Utility functions for saving and loading. * * @license Vinifera is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -35,6 +35,9 @@ #include "newswizzle.h" +struct IStream; + + /** * Wrappers for the new swizzle manager for providing debug information. */ @@ -49,7 +52,7 @@ { \ Wstring funcname = __FUNCTION__; \ funcname += "()"; \ - ((ViniferaSwizzleManagerClass &)SwizzleManager).Swizzle_Dbg(pointer, __FILE__, __LINE__, funcname.Peek_Buffer(), variable); \ + ((ViniferaSwizzleManagerClass &)SwizzleManager).Swizzle_Dbg((void **)&pointer, __FILE__, __LINE__, funcname.Peek_Buffer(), variable); \ } #define VINIFERA_SWIZZLE_REQUEST_POINTER_REMAP_LIST(vector, variable) \ @@ -65,7 +68,7 @@ { \ Wstring funcname = __FUNCTION__; \ funcname += "()"; \ - ((ViniferaSwizzleManagerClass &)SwizzleManager).Fetch_Swizzle_ID_Dbg(pointer, id, __FILE__, __LINE__, funcname.Peek_Buffer(), variable); \ + ((ViniferaSwizzleManagerClass &)SwizzleManager).Fetch_Swizzle_ID_Dbg((void *)pointer, (LONG *)&id, __FILE__, __LINE__, funcname.Peek_Buffer(), variable); \ } #define VINIFERA_SWIZZLE_REGISTER_POINTER(id, pointer, variable) \ @@ -82,3 +85,10 @@ #define VINIFERA_SWIZZLE_FETCH_SWIZZLE_ID(pointer, id, variable) SWIZZLE_FETCH_POINTER_ID(pointer, id); #define VINIFERA_SWIZZLE_REGISTER_POINTER(id, pointer, variable) SWIZZLE_REGISTER_POINTER(id, pointer); #endif + + +extern unsigned ViniferaSaveGameVersion; + +bool Vinifera_Put_All(IStream *pStm, bool save_net = false); +bool Vinifera_Get_All(IStream *pStm, bool load_net = false); +bool Vinifera_Remap_Extension_Pointers();