From 48cd2ea758b41bc4f9b1abeacbb40b44a39b0c68 Mon Sep 17 00:00:00 2001
From: CCHyper <73803386+CCHyper@users.noreply.github.com>
Date: Mon, 21 Nov 2022 18:48:43 +0000
Subject: [PATCH] Rewrite of the class extension system, implements save game
support.
---
CMakeLists.txt | 29 -
src/extensions/abstract/abstractext.cpp | 257 +++
src/extensions/abstract/abstractext.h | 138 ++
.../abstractext_hooks.cpp} | 29 +-
.../abstractext_hooks.h} | 6 +-
src/extensions/abstract/abstractext_init.cpp | 103 +
.../abstractext_init.h} | 6 +-
.../abstracttype/abstracttypeext.cpp | 161 ++
src/extensions/abstracttype/abstracttypeext.h | 68 +
src/extensions/aircraft/aircraftext.cpp | 64 +-
src/extensions/aircraft/aircraftext.h | 33 +-
src/extensions/aircraft/aircraftext_hooks.cpp | 31 +-
src/extensions/aircraft/aircraftext_init.cpp | 130 +-
.../aircrafttype/aircrafttypeext.cpp | 74 +-
src/extensions/aircrafttype/aircrafttypeext.h | 38 +-
.../aircrafttype/aircrafttypeext_init.cpp | 144 +-
src/extensions/anim/animext.cpp | 64 +-
src/extensions/anim/animext.h | 36 +-
src/extensions/anim/animext_hooks.cpp | 80 +-
src/extensions/anim/animext_init.cpp | 153 +-
src/extensions/animtype/animtypeext.cpp | 85 +-
src/extensions/animtype/animtypeext.h | 38 +-
src/extensions/animtype/animtypeext_hooks.cpp | 3 +
src/extensions/animtype/animtypeext_init.cpp | 178 +-
src/extensions/building/buildingext.cpp | 91 +-
src/extensions/building/buildingext.h | 34 +-
src/extensions/building/buildingext_hooks.cpp | 84 +-
src/extensions/building/buildingext_init.cpp | 131 +-
.../buildingtype/buildingtypeext.cpp | 77 +-
src/extensions/buildingtype/buildingtypeext.h | 37 +-
.../buildingtype/buildingtypeext_hooks.cpp | 3 +
.../buildingtype/buildingtypeext_init.cpp | 145 +-
src/extensions/bullet/bulletext_hooks.cpp | 41 +-
src/extensions/bullettype/bullettypeext.cpp | 78 +-
src/extensions/bullettype/bullettypeext.h | 37 +-
.../bullettype/bullettypeext_init.cpp | 176 +-
src/extensions/campaign/campaignext.cpp | 78 +-
src/extensions/campaign/campaignext.h | 37 +-
src/extensions/campaign/campaignext_hooks.cpp | 14 +-
src/extensions/campaign/campaignext_init.cpp | 92 +-
src/extensions/ccfile/ccfileext_hooks.cpp | 6 +-
src/extensions/ccini/cciniext_hooks.cpp | 24 +-
src/extensions/combat/combatext_hooks.cpp | 18 +-
src/extensions/command/commandext.cpp | 90 +-
src/extensions/command/commandext.h | 21 +-
.../command/commandext_functions.cpp | 49 +-
src/extensions/command/commandext_hooks.cpp | 6 +
src/extensions/container.h | 282 ---
src/extensions/display/displayext_hooks.cpp | 5 +-
src/extensions/empulse/empulseext_hooks.cpp | 29 +-
src/extensions/extension.cpp | 2023 ++++++++++++++++-
src/extensions/extension.h | 477 ++--
src/extensions/extension_globals.cpp | 68 +
src/extensions/extension_globals.h | 148 ++
src/extensions/extension_hooks.cpp | 319 +--
src/extensions/extension_hooks.h | 2 +-
src/extensions/extension_saveload.cpp | 486 ----
src/extensions/foot/footext.cpp | 127 ++
.../technotypeext_init.h => foot/footext.h} | 27 +-
src/extensions/foot/footext_hooks.cpp | 23 +-
src/extensions/house/houseext.cpp | 64 +-
src/extensions/house/houseext.h | 40 +-
src/extensions/house/houseext_hooks.cpp | 3 +-
src/extensions/house/houseext_init.cpp | 137 +-
src/extensions/housetype/housetypeext.cpp | 74 +-
src/extensions/housetype/housetypeext.h | 38 +-
.../housetype/housetypeext_init.cpp | 142 +-
src/extensions/infantry/infantryext.cpp | 64 +-
src/extensions/infantry/infantryext.h | 33 +-
src/extensions/infantry/infantryext_hooks.cpp | 17 +-
src/extensions/infantry/infantryext_init.cpp | 130 +-
.../infantrytype/infantrytypeext.cpp | 75 +-
src/extensions/infantrytype/infantrytypeext.h | 37 +-
.../infantrytype/infantrytypeext_init.cpp | 143 +-
src/extensions/isotiletype/isotiletypeext.cpp | 74 +-
src/extensions/isotiletype/isotiletypeext.h | 38 +-
.../isotiletype/isotiletypeext_hooks.cpp | 9 +-
.../isotiletype/isotiletypeext_init.cpp | 149 +-
src/extensions/movie/playmovie_hooks.cpp | 7 +-
src/extensions/object/objectext.cpp | 151 ++
src/extensions/object/objectext.h | 59 +
src/extensions/objecttype/objecttypeext.cpp | 75 +-
src/extensions/objecttype/objecttypeext.h | 45 +-
.../objecttype/objecttypeext_hooks.cpp | 21 +-
.../objecttype/objecttypeext_init.cpp | 176 --
src/extensions/options/optionsext.cpp | 100 +-
src/extensions/options/optionsext.h | 29 +-
src/extensions/options/optionsext_init.cpp | 72 +-
src/extensions/overlaytype/overlaytypeext.cpp | 74 +-
src/extensions/overlaytype/overlaytypeext.h | 38 +-
.../overlaytype/overlaytypeext_hooks.cpp | 3 +
.../overlaytype/overlaytypeext_init.cpp | 145 +-
.../particlesystype/particlesystypeext.cpp | 74 +-
.../particlesystype/particlesystypeext.h | 38 +-
.../particlesystypeext_init.cpp | 142 +-
.../particletype/particletypeext.cpp | 74 +-
src/extensions/particletype/particletypeext.h | 38 +-
.../particletype/particletypeext_init.cpp | 182 +-
src/extensions/rawfile/rawfileext_hooks.cpp | 10 +-
src/extensions/rules/rulesext.cpp | 268 ++-
src/extensions/rules/rulesext.h | 31 +-
src/extensions/rules/rulesext_hooks.cpp | 21 +-
src/extensions/rules/rulesext_init.cpp | 140 +-
src/extensions/scenario/scenarioext.cpp | 77 +-
src/extensions/scenario/scenarioext.h | 30 +-
.../scenario/scenarioext_functions.cpp | 5 +-
src/extensions/scenario/scenarioext_init.cpp | 126 +-
src/extensions/session/sessionext.cpp | 94 +-
src/extensions/session/sessionext.h | 28 +-
src/extensions/session/sessionext_init.cpp | 65 +-
src/extensions/side/sideext.cpp | 74 +-
src/extensions/side/sideext.h | 38 +-
src/extensions/side/sideext_init.cpp | 82 +-
src/extensions/sidebar/sidebarext_hooks.cpp | 9 +-
src/extensions/smudgetype/smudgetypeext.cpp | 74 +-
src/extensions/smudgetype/smudgetypeext.h | 38 +-
.../smudgetype/smudgetypeext_init.cpp | 140 +-
src/extensions/super/superext.cpp | 64 +-
src/extensions/super/superext.h | 38 +-
src/extensions/super/superext_init.cpp | 132 +-
src/extensions/supertype/supertypeext.cpp | 84 +-
src/extensions/supertype/supertypeext.h | 43 +-
.../supertype/supertypeext_init.cpp | 144 +-
src/extensions/tactical/tacticalext.cpp | 161 +-
src/extensions/tactical/tacticalext.h | 36 +-
src/extensions/tactical/tacticalext_hooks.cpp | 70 +-
src/extensions/tactical/tacticalext_init.cpp | 128 +-
src/extensions/techno/technoext.cpp | 132 +-
src/extensions/techno/technoext.h | 27 +-
src/extensions/techno/technoext_functions.cpp | 31 +-
src/extensions/techno/technoext_hooks.cpp | 166 +-
src/extensions/techno/technoext_init.cpp | 205 --
src/extensions/technotype/technotypeext.cpp | 88 +-
src/extensions/technotype/technotypeext.h | 32 +-
.../technotype/technotypeext_hooks.cpp | 5 -
.../technotype/technotypeext_init.cpp | 217 --
src/extensions/terrain/terrainext.cpp | 67 +-
src/extensions/terrain/terrainext.h | 32 +-
src/extensions/terrain/terrainext_hooks.cpp | 25 +-
src/extensions/terrain/terrainext_init.cpp | 143 +-
src/extensions/terraintype/terraintypeext.cpp | 75 +-
src/extensions/terraintype/terraintypeext.h | 37 +-
.../terraintype/terraintypeext_init.cpp | 139 +-
.../textlabel/txtlabelext_hooks.cpp | 6 +-
src/extensions/theme/themeext.cpp | 92 +-
src/extensions/theme/themeext.h | 24 +-
src/extensions/theme/themeext_hooks.cpp | 14 +-
src/extensions/theme/themeext_init.cpp | 26 +-
src/extensions/tiberium/tiberiumext.cpp | 74 +-
src/extensions/tiberium/tiberiumext.h | 38 +-
src/extensions/tiberium/tiberiumext_init.cpp | 117 +-
src/extensions/unit/unitext.cpp | 64 +-
src/extensions/unit/unitext.h | 35 +-
src/extensions/unit/unitext_hooks.cpp | 73 +-
src/extensions/unit/unitext_init.cpp | 131 +-
src/extensions/unittype/unittypeext.cpp | 80 +-
src/extensions/unittype/unittypeext.h | 37 +-
src/extensions/unittype/unittypeext_init.cpp | 147 +-
.../voxelanimtype/voxelanimtypeext.cpp | 74 +-
.../voxelanimtype/voxelanimtypeext.h | 38 +-
.../voxelanimtype/voxelanimtypeext_init.cpp | 182 +-
src/extensions/warheadtype/warheadtypeext.cpp | 78 +-
src/extensions/warheadtype/warheadtypeext.h | 37 +-
.../warheadtype/warheadtypeext_init.cpp | 187 +-
src/extensions/wave/waveext.cpp | 64 +-
src/extensions/wave/waveext.h | 32 +-
src/extensions/wave/waveext_init.cpp | 139 +-
src/extensions/weapontype/weapontypeext.cpp | 74 +-
src/extensions/weapontype/weapontypeext.h | 37 +-
.../weapontype/weapontypeext_init.cpp | 148 +-
src/hooker/hooker_macros.h | 9 +
src/hooker/setup_hooks.cpp | 21 +-
src/new/ebolt.cpp | 28 +-
src/new/swizzle/newswizzle_hooks.cpp | 6 +-
src/vinifera/vinifera_defines.h | 81 +-
src/vinifera/vinifera_functions.cpp | 19 +-
src/vinifera/vinifera_globals.cpp | 3 +-
src/vinifera/vinifera_globals.h | 3 +-
src/vinifera/vinifera_hooks.cpp | 312 ++-
src/vinifera/vinifera_saveload.cpp | 669 ++++++
src/vinifera/vinifera_saveload.h | 16 +-
181 files changed, 8748 insertions(+), 8281 deletions(-)
create mode 100644 src/extensions/abstract/abstractext.cpp
create mode 100644 src/extensions/abstract/abstractext.h
rename src/extensions/{extension_saveload.h => abstract/abstractext_hooks.cpp} (71%)
rename src/extensions/{objecttype/objecttypeext_init.h => abstract/abstractext_hooks.h} (88%)
create mode 100644 src/extensions/abstract/abstractext_init.cpp
rename src/extensions/{techno/technoext_init.h => abstract/abstractext_init.h} (93%)
create mode 100644 src/extensions/abstracttype/abstracttypeext.cpp
create mode 100644 src/extensions/abstracttype/abstracttypeext.h
delete mode 100644 src/extensions/container.h
create mode 100644 src/extensions/extension_globals.cpp
create mode 100644 src/extensions/extension_globals.h
delete mode 100644 src/extensions/extension_saveload.cpp
create mode 100644 src/extensions/foot/footext.cpp
rename src/extensions/{technotype/technotypeext_init.h => foot/footext.h} (65%)
create mode 100644 src/extensions/object/objectext.cpp
create mode 100644 src/extensions/object/objectext.h
delete mode 100644 src/extensions/objecttype/objecttypeext_init.cpp
delete mode 100644 src/extensions/techno/technoext_init.cpp
delete mode 100644 src/extensions/technotype/technotypeext_init.cpp
create mode 100644 src/vinifera/vinifera_saveload.cpp
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0ab856781..d007c6aab 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 000000000..8733a5278
--- /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 000000000..309c7b967
--- /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 5c22dcc85..bc32e0c20 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 80b98b081..ba1e6a99a 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 000000000..65500c2f0
--- /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 4cc97beb5..09886a367 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 000000000..e73081722
--- /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 000000000..c435548b4
--- /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 255b96f8c..3c36eac9c 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 db9a906e8..93f0a7213 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 b2a58c611..6b020f266 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 d7df11d4e..f7c698a54 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 4b31efa36..120b4aade 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 3624244e8..58ac4acb6 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 fa9d30c43..54eda40a4 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 283a19988..5465abccc 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 a0f5d206d..fc991d150 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 48a8011e4..f8be329d7 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 3361ba9e1..8576e0ce9 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 03fa9d887..2f0934d75 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 ec72cde17..3f8ae31d2 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 6828a6eea..339d5c851 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 801f6c2a0..46b6f600f 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 9812ed931..c2de93d17 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 2c90afaac..2b05613a5 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 de0b879bc..20443ddff 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 f5c54bf7c..1a65e131e 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 d34c60155..f24c01db5 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 63e2b38cc..b3e79ae4c 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 ce43d97af..65f850273 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 cc6ba6b3f..82624df6c 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 e1585520d..a230a9c0f 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 059e8f928..394e5d776 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 057c76412..80c709434 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 9dcb7263d..a9f401e35 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 ae0aa446c..8071f358f 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 7a10a2f43..bbc0195b2 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 fcb905517..921f1a32f 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 485a331b2..69828ccde 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 8be3c6464..3711d3dfe 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 ddbef85f5..d1c4ab5b6 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 69e7b9c9f..a6cc46f07 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 9957cf7ee..4412fe7d1 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 4b002bc42..aab6dc4f4 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 2608b8316..7c0b05967 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 4007aa240..2703d806e 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 04839f9a8..000000000
--- 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 8a0886c16..2d3ed68e4 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 053a5ef70..ae77a964d 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 ca590f2f7..cbb269ddf 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