├── .gitignore ├── DEVELOPMENT.md ├── README.md ├── common ├── IArchive.cpp ├── IArchive.h ├── IBufferStream.cpp ├── IBufferStream.h ├── IConsole.cpp ├── IConsole.h ├── ICriticalSection.h ├── IDataStream.cpp ├── IDataStream.h ├── IDatabase.cpp ├── IDatabase.h ├── IDatabase.inc ├── IDebugLog.cpp ├── IDebugLog.h ├── IDirectoryIterator.cpp ├── IDirectoryIterator.h ├── IDynamicCreate.cpp ├── IDynamicCreate.h ├── IErrors.cpp ├── IErrors.h ├── IEvent.cpp ├── IEvent.h ├── IFIFO.cpp ├── IFIFO.h ├── IFileStream.cpp ├── IFileStream.h ├── IInterlockedLong.cpp ├── IInterlockedLong.h ├── ILinkedList.h ├── IMemPool.cpp ├── IMemPool.h ├── IMutex.cpp ├── IMutex.h ├── IObjectPool.cpp ├── IObjectPool.h ├── IPipeClient.cpp ├── IPipeClient.h ├── IPipeServer.cpp ├── IPipeServer.h ├── IPrefix.cpp ├── IPrefix.h ├── IRangeMap.cpp ├── IRangeMap.h ├── IReadWriteLock.cpp ├── IReadWriteLock.h ├── ISegmentStream.cpp ├── ISegmentStream.h ├── ISingleton.cpp ├── ISingleton.h ├── ITextParser.cpp ├── ITextParser.h ├── IThread.cpp ├── IThread.h ├── ITimer.cpp ├── ITimer.h ├── ITypes.cpp ├── ITypes.h ├── common.vcproj ├── common_license.txt ├── common_vc9.vcproj ├── common_vc9.vcxproj └── common_vc9.vcxproj.filters ├── nvse ├── Algohol │ ├── algMath.cpp │ ├── algMath.h │ ├── algTypes.h │ ├── license.txt │ ├── paramTypes.cpp │ └── paramTypes.h ├── loader_common │ ├── Error.cpp │ ├── Error.h │ ├── IdentifyEXE.cpp │ ├── IdentifyEXE.h │ ├── PluginChecker.cpp │ ├── PluginChecker.h │ ├── loader_common.vcproj │ └── loader_common.vcxproj ├── nvse.sln ├── nvse │ ├── ArrayVar.cpp │ ├── ArrayVar.h │ ├── ArrayVarElementContainer.cpp │ ├── CachedScripts.cpp │ ├── CachedScripts.h │ ├── CommandTable.cpp │ ├── CommandTable.h │ ├── Commands_Array.cpp │ ├── Commands_Array.h │ ├── Commands_Console.cpp │ ├── Commands_Console.h │ ├── Commands_Factions.cpp │ ├── Commands_Factions.h │ ├── Commands_Game.cpp │ ├── Commands_Game.h │ ├── Commands_Input.cpp │ ├── Commands_Input.h │ ├── Commands_Inventory.cpp │ ├── Commands_Inventory.h │ ├── Commands_InventoryRef.cpp │ ├── Commands_InventoryRef.h │ ├── Commands_List.cpp │ ├── Commands_List.h │ ├── Commands_Math.cpp │ ├── Commands_Math.h │ ├── Commands_Misc.cpp │ ├── Commands_Misc.h │ ├── Commands_MiscRef.cpp │ ├── Commands_MiscRef.h │ ├── Commands_NetImmerse.cpp │ ├── Commands_NetImmerse.h │ ├── Commands_Packages.cpp │ ├── Commands_Packages.h │ ├── Commands_Quest.cpp │ ├── Commands_Quest.h │ ├── Commands_Script.cpp │ ├── Commands_Script.h │ ├── Commands_Scripting.cpp │ ├── Commands_Scripting.h │ ├── Commands_String.cpp │ ├── Commands_String.h │ ├── Commands_UI.cpp │ ├── Commands_UI.h │ ├── Core_Serialization.cpp │ ├── Core_Serialization.h │ ├── DebuggerVisualizations.natvis │ ├── EventManager.cpp │ ├── EventManager.h │ ├── EventParams.h │ ├── FastStack.h │ ├── FormExtraData.cpp │ ├── FormExtraData.h │ ├── FunctionScripts.cpp │ ├── FunctionScripts.h │ ├── GameAPI.cpp │ ├── GameAPI.h │ ├── GameBSExtraData.cpp │ ├── GameBSExtraData.h │ ├── GameData.cpp │ ├── GameData.h │ ├── GameEffects.h │ ├── GameExtraData.cpp │ ├── GameExtraData.h │ ├── GameForms.cpp │ ├── GameForms.h │ ├── GameOSDepend.cpp │ ├── GameOSDepend.h │ ├── GameObjects.cpp │ ├── GameObjects.h │ ├── GameProcess.cpp │ ├── GameProcess.h │ ├── GameRTTI.cpp │ ├── GameRTTI.h │ ├── GameRTTI_1_4_0_525.inc │ ├── GameRTTI_1_4_0_525ng.inc │ ├── GameRTTI_EDITOR.inc │ ├── GameScript.cpp │ ├── GameScript.h │ ├── GameSettings.cpp │ ├── GameSettings.h │ ├── GameTasks.cpp │ ├── GameTasks.h │ ├── GameTiles.cpp │ ├── GameTiles.h │ ├── GameTypes.cpp │ ├── GameTypes.h │ ├── GameUI.cpp │ ├── GameUI.h │ ├── Hooks_Animation.cpp │ ├── Hooks_Animation.h │ ├── Hooks_CreatedObject.cpp │ ├── Hooks_CreatedObject.h │ ├── Hooks_Dialog.cpp │ ├── Hooks_Dialog.h │ ├── Hooks_DirectInput8Create.cpp │ ├── Hooks_DirectInput8Create.h │ ├── Hooks_Editor.cpp │ ├── Hooks_Editor.h │ ├── Hooks_Gameplay.cpp │ ├── Hooks_Gameplay.h │ ├── Hooks_Logging.cpp │ ├── Hooks_Logging.h │ ├── Hooks_Memory.cpp │ ├── Hooks_Memory.h │ ├── Hooks_Other.cpp │ ├── Hooks_Other.h │ ├── Hooks_SaveLoad.cpp │ ├── Hooks_SaveLoad.h │ ├── Hooks_Script.cpp │ ├── Hooks_Script.h │ ├── InventoryInfo.cpp │ ├── InventoryInfo.h │ ├── InventoryRef.cpp │ ├── InventoryRef.h │ ├── InventoryReference.cpp │ ├── InventoryReference.h │ ├── LambdaManager.cpp │ ├── LambdaManager.h │ ├── Loops.cpp │ ├── Loops.h │ ├── MemoizedMap.h │ ├── MemoryPool.cpp │ ├── MemoryPool.h │ ├── MemoryTracker.h │ ├── NVSEAst.h │ ├── NVSECompiler.cpp │ ├── NVSECompiler.h │ ├── NVSECompilerUtils.cpp │ ├── NVSECompilerUtils.h │ ├── NVSELexer.cpp │ ├── NVSELexer.h │ ├── NVSEParser.cpp │ ├── NVSEParser.h │ ├── NVSEScope.h │ ├── NVSETreePrinter.cpp │ ├── NVSETreePrinter.h │ ├── NVSETypeChecker.cpp │ ├── NVSETypeChecker.h │ ├── NVSEVisitor.h │ ├── NiNodes.cpp │ ├── NiNodes.h │ ├── NiObjects.cpp │ ├── NiObjects.h │ ├── NiPoint.h │ ├── NiTypes.cpp │ ├── NiTypes.h │ ├── OverloadsGlobal.cpp │ ├── ParamInfos.h │ ├── PluginAPI.h │ ├── PluginManager.cpp │ ├── PluginManager.h │ ├── SafeWrite.cpp │ ├── SafeWrite.h │ ├── ScriptAnalyzer.cpp │ ├── ScriptAnalyzer.h │ ├── ScriptTokenCache.cpp │ ├── ScriptTokenCache.h │ ├── ScriptTokens.cpp │ ├── ScriptTokens.h │ ├── ScriptUtils.cpp │ ├── ScriptUtils.h │ ├── Serialization.cpp │ ├── Serialization.h │ ├── SmallObjectsAllocator.h │ ├── StackVariables.cpp │ ├── StackVariables.h │ ├── StackVector.h │ ├── StringVar.cpp │ ├── StringVar.h │ ├── ThreadLocal.cpp │ ├── ThreadLocal.h │ ├── UnitTests.cpp │ ├── UnitTests.h │ ├── Utilities.cpp │ ├── Utilities.h │ ├── VarMap.h │ ├── commands_Algohol.cpp │ ├── commands_Algohol.h │ ├── containers.cpp │ ├── containers.h │ ├── exports.def │ ├── nvse.cpp │ ├── nvse.vcproj │ ├── nvse.vcxproj │ ├── nvse.vcxproj.filters │ ├── nvse_version.h │ ├── nvse_version.rc │ ├── prefix.h │ ├── printf.cpp │ ├── printf.h │ ├── rewrites.h │ ├── unit_tests │ │ ├── new_compiler │ │ │ ├── binary_operations.txt │ │ │ ├── call_test.txt │ │ │ ├── comments.txt │ │ │ ├── disabled │ │ │ │ └── in_operator_syntax.txt │ │ │ ├── for_loops.txt │ │ │ ├── foreachalt.txt │ │ │ ├── misc.txt │ │ │ ├── stack_vars.txt │ │ │ ├── ternary_operations.txt │ │ │ ├── udfs │ │ │ │ └── TestUDF.txt │ │ │ └── unary_operations.txt │ │ └── old_compiler │ │ │ ├── CallAfterFrames.txt │ │ │ ├── TestExpr.txt │ │ │ ├── array_functions.txt │ │ │ ├── conversions_between_num_and_string.txt │ │ │ ├── event_handler_functions.txt │ │ │ ├── event_handler_priority_system.txt │ │ │ ├── let_macro.txt │ │ │ ├── multi_arg_command_trailing_boundary.txt │ │ │ ├── multiple_variable_declarations_macro.txt │ │ │ ├── short_and_long_param_types_in_UDF.txt │ │ │ ├── strings_and_parentheses.txt │ │ │ └── udf_functions.txt │ ├── utility.cpp │ └── utility.h ├── nvse_loader │ ├── Inject.cpp │ ├── Inject.h │ ├── Options.cpp │ ├── Options.h │ ├── main.cpp │ ├── nvse_loader.ico │ ├── nvse_loader.vcproj │ ├── nvse_loader.vcxproj │ └── resources.rc └── steam_loader │ ├── PluginPreload.h │ ├── main.cpp │ ├── steam_loader.vcproj │ ├── steam_loader.vcxproj │ └── steam_loader.vcxproj.filters └── nvse_plugin_example ├── dllmain.c ├── exports.def ├── fn_intro_to_script_functions.h ├── fn_typed_functions.h ├── main.cpp ├── nvse_plugin_example.sln ├── nvse_plugin_example.vcproj ├── nvse_plugin_example.vcxproj └── nvse_plugin_example.vcxproj.filters /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | 5 | 6 |

7 | 8 | **New Vegas Script Extender** (xNVSE) expands the engine and scripting capabilities of Fallout New Vegas. 9 | 10 | ## Download 11 | 12 | [Download the latest NVSE](https://github.com/xNVSE/NVSE/releases) 13 | 14 | -Changelogs and all releases are provided in the [releases section](https://github.com/xNVSE/NVSE/releases). Do not try to install using the Code .zip source code button GitHub shows. 15 | 16 | Releases are also available on [Nexus Mods](https://www.nexusmods.com/newvegas/mods/67883) and [Mod Pub](https://mod.pub/falloutnv/41-new-vegas-script-extender-nvse-xnvse). 17 | 18 | ## Installation 19 | 20 | 1. Copy the .dll and .exe files to your Fallout NV directory. For Steam this is usually in your Program Files folder under *Steam\\steamapps\\common\\Fallout New Vegas\\*. If you see files named FalloutNV.exe and FalloutNVLauncher.exe, this is the correct folder. **Do not copy these files to the Data folder or install it with MO2 as with a normal mod.** 21 | 22 | 2. Launch NV via running *nvse_loader.exe* or, if you have patched the game using [FNV 4GB Patcher](https://www.nexusmods.com/newvegas/mods/62552/), *FalloutNV.exe*. Enabling the Steam Community option (enabled by default) will allow you to launch the game via Steam's standard UI. 23 | 24 | xNVSE is compatible with the Steam and GOG versions of the game. German No Gore, Xbox Gamepass, and Bethesda.net versions are not supported. Epic Games Store users can use the [Epic Games Patcher](https://www.nexusmods.com/newvegas/mods/81281). 25 | 26 | ## Support 27 | 28 | For support, contact us in the [xNVSE Discord server](https://discord.gg/EebN93s). For bug reports and other problems, [create a new GitHub issue](https://github.com/NVSEx/NVSE/issues). 29 | 30 | If you experience a crash related to installing xNVSE, please try disabling all other mods to see if xNVSE is the culprit. If the problem persists, please include a crash log generated by a [Crash Logger](https://www.nexusmods.com/newvegas/mods/82540) inside your bug report. 31 | 32 | ## Description 33 | 34 | **New Vegas Script Extender** (NVSE) is a modder's resource that expands the scripting capabilities of Fallout: New Vegas. It does so without modifying the executable files on disk, so there are no permanent side effects. 35 | 36 | 37 | For documentation on how to write scripts utilizing NVSE, see [GECK Wiki](https://geckwiki.com/index.php?title=Main_Page). 38 | 39 | ## Making a Plugin, and/or Contributing 40 | See [DEVELOPMENT.md](https://github.com/xNVSE/NVSE/blob/master/DEVELOPMENT.md). 41 | 42 | ## Credits 43 | 44 | The original NVSE was created and maintained by *Ian Patterson*, 45 | *Stephen Abel*, *Paul Connelly*, and *Hugues LE PORS* 46 | (ianpatt, behippo, scruggsywuggsy the ferret, and hlp) 47 | 48 | xNVSE is developed by *korri123* (Kormákur), *jazzisparis*, and *Demorome*. 49 | 50 | xNVSE has contributions from *lStewieAl*, *c6* and *carxt* 51 | -------------------------------------------------------------------------------- /common/IArchive.cpp: -------------------------------------------------------------------------------- 1 | #include "IArchive.h" 2 | #include "IErrors.h" 3 | 4 | #if ENABLE_IDYNAMICCREATE 5 | 6 | IDynamic * IArchive::iterator::Instantiate(void) 7 | { 8 | IDataSubStream subStream(owner->theStream, GetDataOffset(), GetDataLength()); 9 | 10 | return IClassRegistry::Instantiate(GetTypeID(), &subStream); 11 | } 12 | 13 | void * IArchive::iterator::GetBuffer(UInt32 * outLength) 14 | { 15 | HeaderEntry * entry = GetData(); 16 | UInt8 * buf = new UInt8[entry->dataLength]; 17 | 18 | owner->theStream->SetOffset(entry->dataOffset); 19 | owner->theStream->ReadBuf(buf, entry->dataLength); 20 | 21 | if(outLength) 22 | *outLength = entry->dataLength; 23 | 24 | return buf; 25 | } 26 | 27 | void IArchive::iterator::NextOfType(UInt32 typeID) 28 | { 29 | idx++; 30 | 31 | while((GetData()->typeID != typeID) && (idx < owner->header.numEntries)) 32 | idx++; 33 | } 34 | 35 | void IArchive::iterator::PrevOfType(UInt32 typeID) 36 | { 37 | idx--; 38 | 39 | while((GetData()->typeID != typeID) && (idx > 0)) 40 | idx--; 41 | } 42 | 43 | IArchive::IArchive() 44 | :theStream(NULL), entries(NULL), nameTable(NULL) 45 | { 46 | 47 | } 48 | 49 | IArchive::IArchive(IDataStream * stream) 50 | :theStream(NULL), entries(NULL), nameTable(NULL) 51 | { 52 | AttachStream(stream); 53 | } 54 | 55 | IArchive::~IArchive() 56 | { 57 | Dispose(); 58 | } 59 | 60 | void IArchive::AttachStream(IDataStream * inStream) 61 | { 62 | Dispose(); 63 | 64 | theStream = inStream; 65 | } 66 | 67 | void IArchive::Dispose(void) 68 | { 69 | if(entries) 70 | { 71 | delete entries; 72 | entries = NULL; 73 | } 74 | 75 | if(nameTable) 76 | { 77 | delete nameTable; 78 | nameTable = NULL; 79 | } 80 | } 81 | 82 | void IArchive::ReadHeader(void) 83 | { 84 | ASSERT(theStream); 85 | 86 | theStream->Rewind(); 87 | 88 | theStream->ReadBuf(&header, sizeof(FileHeader)); 89 | 90 | entries = new HeaderEntry[header.numEntries]; 91 | theStream->ReadBuf(entries, header.numEntries * sizeof(HeaderEntry)); 92 | 93 | if(header.nameTableLength) 94 | { 95 | nameTable = new char[header.nameTableLength]; 96 | 97 | theStream->SetOffset(header.nameTableOffset); 98 | theStream->ReadBuf(nameTable, header.nameTableLength); 99 | } 100 | } 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /common/IArchive.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/IDataStream.h" 4 | #include "common/IDynamicCreate.h" 5 | 6 | #if ENABLE_IDYNAMICCREATE 7 | 8 | /** 9 | * An object archive 10 | * 11 | * This class implements reading and instantiating objects from an object archive. 12 | */ 13 | class IArchive 14 | { 15 | public: 16 | class iterator; 17 | friend iterator; 18 | 19 | IArchive(); 20 | IArchive(IDataStream * inStream); 21 | ~IArchive(); 22 | 23 | void AttachStream(IDataStream * inStream); 24 | void Dispose(void); 25 | 26 | iterator begin(void) { return iterator(0, this); } 27 | iterator end(void) { return iterator(header.numEntries, this); } 28 | 29 | static const UInt32 kFileID = CHAR_CODE(0x00, 'A', 'R', 0x01); 30 | static const UInt32 kCurrentVersion = VERSION_CODE(1, 0, 0); 31 | 32 | private: 33 | struct FileHeader 34 | { 35 | UInt32 fileID; // IArchive::kFileID 36 | UInt32 version; // IArchive::kCurrentVersion 37 | UInt32 numEntries; 38 | UInt32 nameTableOffset; 39 | UInt32 nameTableLength; 40 | }; 41 | 42 | struct HeaderEntry 43 | { 44 | UInt32 typeID; 45 | UInt32 subID; 46 | UInt32 dataOffset; 47 | UInt32 dataLength; 48 | UInt32 nameOffset; 49 | }; 50 | 51 | void ReadHeader(void); 52 | 53 | IDataStream * theStream; 54 | 55 | FileHeader header; 56 | HeaderEntry * entries; 57 | 58 | char * nameTable; 59 | 60 | public: 61 | class iterator 62 | { 63 | public: 64 | iterator() { idx = 0; owner = NULL; } 65 | iterator(UInt32 inIdx, IArchive * inArchive) { idx = inIdx; owner = inArchive; } 66 | ~iterator() { } 67 | 68 | IDynamic * Instantiate(void); 69 | 70 | UInt32 GetTypeID(void) { return GetData()->typeID; } 71 | UInt32 GetSubID(void) { return GetData()->subID; } 72 | UInt32 GetDataLength(void) { return GetData()->dataLength; } 73 | char * GetName(void) { return &owner->nameTable[GetData()->nameOffset]; } 74 | void * GetBuffer(UInt32 * outLength); 75 | 76 | iterator & operator++() { Next(); return *this; } 77 | iterator & operator--() { Prev(); return *this; } 78 | 79 | void NextOfType(UInt32 typeID); 80 | void Next(void) { idx++; } 81 | 82 | void PrevOfType(UInt32 typeID); 83 | void Prev(void) { idx--; } 84 | 85 | private: 86 | HeaderEntry * GetData(void) { return &owner->entries[idx]; } 87 | 88 | UInt32 GetDataOffset(void) { return GetData()->dataOffset; } 89 | 90 | UInt32 idx; 91 | IArchive * owner; 92 | }; 93 | }; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /common/IBufferStream.cpp: -------------------------------------------------------------------------------- 1 | #include "IBufferStream.h" 2 | 3 | IBufferStream::IBufferStream() 4 | :streamBuf(NULL), flags(0) 5 | { 6 | 7 | } 8 | 9 | IBufferStream::IBufferStream(const IBufferStream & rhs) 10 | { 11 | // explicitly not supporting copy constructor for self-owned buffers 12 | ASSERT((flags & kFlag_OwnedBuf) == 0); 13 | } 14 | 15 | IBufferStream::IBufferStream(void * buf, UInt64 inLength) 16 | :streamBuf(NULL), flags(0) 17 | { 18 | SetBuffer(buf, inLength); 19 | } 20 | 21 | IBufferStream::~IBufferStream() 22 | { 23 | if(flags & kFlag_OwnedBuf) 24 | { 25 | delete [] streamBuf; 26 | } 27 | } 28 | 29 | IBufferStream & IBufferStream::operator=(IBufferStream & rhs) 30 | { 31 | // explicitly not supporting copying for self-owned buffers 32 | ASSERT((flags & kFlag_OwnedBuf) == 0); 33 | 34 | streamBuf = rhs.streamBuf; 35 | flags = rhs.flags; 36 | 37 | return *this; 38 | } 39 | 40 | void IBufferStream::SetBuffer(void * buf, UInt64 inLength) 41 | { 42 | streamBuf = (UInt8 *)buf; 43 | streamLength = inLength; 44 | 45 | Rewind(); 46 | } 47 | 48 | void IBufferStream::ReadBuf(void * buf, UInt32 inLength) 49 | { 50 | memcpy(buf, &streamBuf[streamOffset], inLength); 51 | streamOffset += inLength; 52 | } 53 | 54 | void IBufferStream::WriteBuf(const void * buf, UInt32 inLength) 55 | { 56 | memcpy(&streamBuf[streamOffset], buf, inLength); 57 | streamOffset += inLength; 58 | } 59 | -------------------------------------------------------------------------------- /common/IBufferStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/IDataStream.h" 4 | 5 | class IBufferStream : public IDataStream 6 | { 7 | public: 8 | IBufferStream(); 9 | IBufferStream(const IBufferStream & rhs); 10 | IBufferStream(void * buf, UInt64 inLength); 11 | virtual ~IBufferStream(); 12 | 13 | IBufferStream & operator=(IBufferStream & rhs); 14 | 15 | void SetBuffer(void * buf, UInt64 inLength); 16 | void * GetBuffer(void) { return streamBuf; } 17 | 18 | void OwnBuffer(void) { flags |= kFlag_OwnedBuf; } 19 | void DisownBuffer(void) { flags &= ~kFlag_OwnedBuf; } 20 | 21 | // read 22 | virtual void ReadBuf(void * buf, UInt32 inLength); 23 | 24 | // write 25 | virtual void WriteBuf(const void * buf, UInt32 inLength); 26 | 27 | protected: 28 | UInt8 * streamBuf; 29 | UInt32 flags; 30 | 31 | enum 32 | { 33 | kFlag_OwnedBuf = 1 << 0 34 | }; 35 | }; 36 | -------------------------------------------------------------------------------- /common/IConsole.cpp: -------------------------------------------------------------------------------- 1 | #include "common/IConsole.h" 2 | #include 3 | #include 4 | #include 5 | 6 | IConsole::IConsole() 7 | { 8 | AllocConsole(); 9 | 10 | SetConsoleTitle("Console"); 11 | 12 | inputHandle = GetStdHandle(STD_INPUT_HANDLE); 13 | outputHandle = GetStdHandle(STD_OUTPUT_HANDLE); 14 | 15 | ASSERT_STR(inputHandle, "IConsole: couldn't get input handle"); 16 | ASSERT_STR(outputHandle, "IConsole: couldn't get output handle"); 17 | 18 | SetConsoleMode(inputHandle, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT); 19 | SetConsoleMode(outputHandle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT); 20 | } 21 | 22 | IConsole::~IConsole() 23 | { 24 | 25 | } 26 | 27 | /** 28 | * Writes a string to the console 29 | */ 30 | void IConsole::Write(char * buf) 31 | { 32 | UInt32 charsWritten; 33 | 34 | WriteConsole(outputHandle, buf, std::strlen(buf), &charsWritten, NULL); 35 | } 36 | 37 | /** 38 | * Writes a formatted string to the console 39 | * 40 | * You may specify a temp buffer to use for the formatted text, but if NULL 41 | * is used a local buffer will be provided. 42 | * 43 | * @param buf a temporary buffer, or NULL to use the internal buffer 44 | * @param fmt the format string 45 | */ 46 | void IConsole::Write(char * buf, UInt32 bufLen, const char * fmt, ...) 47 | { 48 | static char tempBuf[4096]; 49 | 50 | if(!buf) 51 | { 52 | buf = tempBuf; 53 | bufLen = sizeof(tempBuf); 54 | } 55 | 56 | va_list args; 57 | 58 | va_start(args, fmt); 59 | vsprintf_s(buf, bufLen, fmt, args); 60 | va_end(args); 61 | 62 | Write(buf); 63 | } 64 | 65 | /** 66 | * Reads a single character from the console 67 | */ 68 | char IConsole::ReadChar(void) 69 | { 70 | char data; 71 | UInt32 charsRead; 72 | 73 | ReadConsole(inputHandle, &data, 1, &charsRead, NULL); 74 | 75 | return data; 76 | } 77 | 78 | /** 79 | * Reads a newline-terminated string from the console 80 | * 81 | * @param buf output buffer 82 | * @param len buffer size 83 | * @return number of characters read 84 | */ 85 | UInt32 IConsole::ReadBuf(char * buf, UInt32 len) 86 | { 87 | UInt32 charsRead; 88 | 89 | buf[0] = 0; 90 | 91 | do 92 | { 93 | ReadConsole(inputHandle, buf, len, &charsRead, NULL); 94 | } 95 | while(!charsRead); 96 | 97 | int done = 0; 98 | for(UInt32 i = charsRead - 1; (i > 0) && !done; i--) 99 | { 100 | switch(buf[i]) 101 | { 102 | case 0x0A: 103 | case 0x0D: 104 | buf[i] = 0; 105 | break; 106 | 107 | default: 108 | done = 1; 109 | break; 110 | } 111 | } 112 | 113 | buf[charsRead] = 0; 114 | 115 | return charsRead; 116 | } 117 | -------------------------------------------------------------------------------- /common/IConsole.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/ITypes.h" 4 | #include "common/ISingleton.h" 5 | #include 6 | 7 | /** 8 | * Wrapper class for a standard Windows console 9 | * 10 | * @todo make nonblocking 11 | */ 12 | class IConsole : public ISingleton 13 | { 14 | public: 15 | IConsole(); 16 | ~IConsole(); 17 | 18 | void Write(char * buf); 19 | void Write(char * buf, UInt32 bufLen, const char * fmt, ...); 20 | 21 | char ReadChar(void); 22 | UInt32 ReadBuf(char * buf, UInt32 len); 23 | 24 | private: 25 | HANDLE inputHandle, outputHandle; 26 | }; 27 | -------------------------------------------------------------------------------- /common/ICriticalSection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if 0 4 | 5 | class ICriticalSection 6 | { 7 | public: 8 | ICriticalSection() { InitializeCriticalSection(&critSection); } 9 | ~ICriticalSection() { DeleteCriticalSection(&critSection); } 10 | 11 | void Enter(void) { EnterCriticalSection(&critSection); } 12 | void Leave(void) { LeaveCriticalSection(&critSection); } 13 | bool TryEnter(void) { return TryEnterCriticalSection(&critSection) != 0; } 14 | 15 | private: 16 | CRITICAL_SECTION critSection; 17 | }; 18 | 19 | class ScopedLock 20 | { 21 | public: 22 | ScopedLock(ICriticalSection& critSection) : m_critSection(critSection) 23 | { 24 | m_critSection.Enter(); 25 | } 26 | 27 | ~ScopedLock() 28 | { 29 | m_critSection.Leave(); 30 | } 31 | 32 | private: 33 | ICriticalSection& m_critSection; 34 | }; 35 | 36 | #else 37 | 38 | class ICriticalSection 39 | { 40 | DWORD owningThread; 41 | DWORD enterCount; 42 | 43 | public: 44 | ICriticalSection() : owningThread(0), enterCount(0) {} 45 | 46 | void Enter() 47 | { 48 | DWORD currThread = GetCurrentThreadId(); 49 | if (owningThread == currThread) 50 | { 51 | enterCount++; 52 | return; 53 | } 54 | if (InterlockedCompareExchange(&owningThread, currThread, 0)) 55 | { 56 | DWORD fastIdx = 10000; 57 | do { 58 | Sleep(--fastIdx >> 0x1F); 59 | } while (InterlockedCompareExchange(&owningThread, currThread, 0)); 60 | } 61 | enterCount = 1; 62 | } 63 | 64 | __forceinline void Leave() 65 | { 66 | if (!--enterCount) 67 | owningThread = 0; 68 | } 69 | }; 70 | 71 | class ScopedLock 72 | { 73 | ICriticalSection *m_cs; 74 | 75 | public: 76 | ScopedLock(ICriticalSection &cs) : m_cs(&cs) {cs.Enter();} 77 | ~ScopedLock() {m_cs->Leave();} 78 | }; 79 | 80 | #endif -------------------------------------------------------------------------------- /common/IDataStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/IErrors.h" 4 | 5 | /** 6 | * An arbitrary data stream 7 | */ 8 | class IDataStream 9 | { 10 | public: 11 | IDataStream(); 12 | virtual ~IDataStream(); 13 | 14 | // read 15 | virtual UInt8 Read8(void); 16 | virtual UInt16 Read16(void); 17 | virtual UInt32 Read32(void); 18 | virtual UInt64 Read64(void); 19 | virtual float ReadFloat(void); 20 | virtual UInt32 ReadString(char * buf, UInt32 bufLength, char altTerminator = 0, char altTerminator2 = 0); 21 | virtual void ReadBuf(void * buf, UInt32 inLength) = 0; 22 | 23 | // peek 24 | virtual UInt8 Peek8(void); 25 | virtual UInt16 Peek16(void); 26 | virtual UInt32 Peek32(void); 27 | virtual UInt64 Peek64(void); 28 | virtual float PeekFloat(void); 29 | virtual void PeekBuf(void * buf, UInt32 inLength); 30 | 31 | virtual void Skip(SInt64 inBytes); 32 | 33 | // write 34 | virtual void Write8(UInt8 inData); 35 | virtual void Write16(UInt16 inData); 36 | virtual void Write32(UInt32 inData); 37 | virtual void Write64(UInt64 inData); 38 | virtual void WriteFloat(float inData); 39 | virtual void WriteString(const char * buf); 40 | virtual void WriteBuf(const void * buf, UInt32 inLength) = 0; 41 | 42 | SInt64 GetLength(void); 43 | SInt64 GetRemain(void); 44 | SInt64 GetOffset(void); 45 | bool HitEOF(void); 46 | 47 | virtual void SetOffset(SInt64 inOffset); 48 | void Rewind(void) { SetOffset(0); } 49 | 50 | void SwapBytes(bool inSwapBytes); 51 | 52 | virtual SInt64 GetParentOffset(void) { return GetOffset(); } 53 | virtual IDataStream * GetParent(void) { return NULL; } 54 | 55 | IDataStream * GetRootParent(void); 56 | 57 | static void CopyStreams(IDataStream * out, IDataStream * in, UInt64 bufferSize = 1024 * 1024, UInt8 * buf = NULL); 58 | static void CopySubStreams(IDataStream * out, IDataStream * in, UInt64 remain, UInt64 bufferSize = 1024 * 1024, UInt8 * buf = NULL); 59 | 60 | protected: 61 | SInt64 streamLength; 62 | SInt64 streamOffset; 63 | bool swapBytes; 64 | }; 65 | 66 | /** 67 | * A utility class to automatically save and restore the current position of an IDataStream 68 | */ 69 | class IDataStream_PositionSaver 70 | { 71 | public: 72 | IDataStream_PositionSaver(IDataStream * tgt); 73 | ~IDataStream_PositionSaver(); 74 | 75 | private: 76 | IDataStream * stream; 77 | SInt64 offset; 78 | }; 79 | 80 | class IDataSubStream : public IDataStream 81 | { 82 | public: 83 | IDataSubStream(); 84 | IDataSubStream(IDataStream * inStream, SInt64 inOffset, SInt64 inLength); 85 | ~IDataSubStream(); 86 | 87 | void Attach(IDataStream * inStream, SInt64 inOffset, SInt64 inLength); 88 | 89 | void ReadBuf(void * buf, UInt32 inLength); 90 | void WriteBuf(const void * buf, UInt32 inLength); 91 | void SetOffset(SInt64 inOffset); 92 | 93 | virtual SInt64 GetParentOffset(void) { return stream->GetOffset(); } 94 | virtual IDataStream * GetParent(void) { return stream; } 95 | 96 | SInt64 GetSubBase(void) { return subBase; } 97 | 98 | private: 99 | IDataStream * stream; 100 | 101 | SInt64 subBase; 102 | }; 103 | -------------------------------------------------------------------------------- /common/IDatabase.cpp: -------------------------------------------------------------------------------- 1 | #include "IDatabase.h" 2 | -------------------------------------------------------------------------------- /common/IDatabase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "common/IDataStream.h" 5 | #include "common/IFilestream.h" 6 | 7 | template 8 | class IDatabase 9 | { 10 | public: 11 | typedef std::map DataMapType; 12 | typedef typename DataMapType::iterator DataMapIterator; 13 | 14 | static const UInt64 kGUIDMask = 0x0FFFFFFFFFFFFFFF; 15 | 16 | IDatabase() { newKeyHint = 1; } 17 | virtual ~IDatabase() { } 18 | 19 | DataType *Get(UInt64 key) 20 | { 21 | key &= kGUIDMask; 22 | 23 | if(!key) 24 | return NULL; 25 | 26 | DataMapIterator iter = theDataMap.find(key); 27 | 28 | return (iter == theDataMap.end()) ? NULL : &((*iter).second); 29 | } 30 | 31 | DataType * Alloc(UInt64 key) 32 | { 33 | key &= kGUIDMask; 34 | 35 | if(!key) 36 | return NULL; 37 | 38 | DataMapIterator iter = theDataMap.find(key); 39 | 40 | return (iter == theDataMap.end()) ? &theDataMap[key] : NULL; 41 | } 42 | 43 | DataType * Alloc(UInt64 * key) 44 | { 45 | UInt64 newKey = newKeyHint; 46 | 47 | do 48 | { 49 | if(!newKey) 50 | newKey++; 51 | 52 | DataMapIterator iter = theDataMap.find(newKey); 53 | 54 | // is 'newKey' unused? 55 | if(iter == theDataMap.end()) 56 | { 57 | *key = newKey; 58 | newKeyHint = (newKey + 1) & kGUIDMask; 59 | return &theDataMap[newKey]; 60 | } 61 | else 62 | { 63 | ++iter; 64 | if(iter == theDataMap.end()) 65 | { 66 | newKey = 1; 67 | } 68 | else 69 | { 70 | UInt64 nextKey = (newKey + 1) & kGUIDMask; 71 | if(iter->first != nextKey) 72 | { 73 | *key = nextKey; 74 | newKeyHint = (nextKey + 1) & kGUIDMask; 75 | return &theDataMap[nextKey]; 76 | } 77 | } 78 | } 79 | } 80 | while(1); 81 | 82 | *key = 0; 83 | 84 | return NULL; 85 | } 86 | 87 | void Delete(UInt64 key) 88 | { 89 | if(key) 90 | { 91 | key &= kGUIDMask; 92 | 93 | theDataMap.erase(key); 94 | 95 | newKeyHint = key; 96 | } 97 | } 98 | 99 | void Save(IDataStream * stream); 100 | void Load(IDataStream * stream); 101 | 102 | bool SaveToFile(char * name); 103 | bool LoadFromFile(char * name); 104 | 105 | DataMapType & GetData(void) { return theDataMap; } 106 | 107 | DataMapIterator Begin(void) { return theDataMap.begin(); } 108 | DataMapIterator End(void) { return theDataMap.end(); } 109 | UInt32 Length(void) { return theDataMap.size(); } 110 | 111 | private: 112 | DataMapType theDataMap; 113 | UInt64 newKeyHint; 114 | }; 115 | 116 | #include "common/IDatabase.inc" 117 | -------------------------------------------------------------------------------- /common/IDatabase.inc: -------------------------------------------------------------------------------- 1 | template 2 | void IDatabase ::Save(IDataStream * stream) 3 | { 4 | stream->Write32(theDataMap.size()); 5 | stream->Write64(newKeyHint); 6 | 7 | for(DataMapIterator iter = theDataMap.begin(); iter != theDataMap.end(); iter++) 8 | { 9 | stream->Write64((*iter).first); 10 | stream->WriteBuf(&((*iter).second), sizeof(DataType)); 11 | } 12 | } 13 | 14 | template 15 | void IDatabase ::Load(IDataStream * stream) 16 | { 17 | UInt32 numEntries = stream->Read32(); 18 | newKeyHint = stream->Read64(); 19 | 20 | theDataMap.clear(); 21 | 22 | for(UInt32 i = 0; i < numEntries; i++) 23 | { 24 | UInt64 key = stream->Read64(); 25 | stream->ReadBuf(&(theDataMap[key]), sizeof(DataType)); 26 | } 27 | } 28 | 29 | template 30 | bool IDatabase ::SaveToFile(char * name) 31 | { 32 | IFileStream stream; 33 | 34 | if(stream.Create(name)) 35 | { 36 | Save(&stream); 37 | return true; 38 | } 39 | 40 | return false; 41 | } 42 | 43 | template 44 | bool IDatabase ::LoadFromFile(char * name) 45 | { 46 | IFileStream stream; 47 | 48 | if(stream.Open(name)) 49 | { 50 | Load(&stream); 51 | return true; 52 | } 53 | 54 | return false; 55 | } 56 | -------------------------------------------------------------------------------- /common/IDirectoryIterator.cpp: -------------------------------------------------------------------------------- 1 | #include "IDirectoryIterator.h" 2 | #include 3 | 4 | IDirectoryIterator::IDirectoryIterator(const char * path, const char * match) 5 | :m_searchHandle(INVALID_HANDLE_VALUE), m_done(false) 6 | { 7 | if(!match) match = "*"; 8 | 9 | strcpy_s(m_path, sizeof(m_path), path); 10 | 11 | char wildcardPath[MAX_PATH]; 12 | sprintf_s(wildcardPath, sizeof(wildcardPath), "%s\\%s", path, match); 13 | 14 | m_searchHandle = FindFirstFile(wildcardPath, &m_result); 15 | if(m_searchHandle == INVALID_HANDLE_VALUE) 16 | m_done = true; 17 | } 18 | 19 | IDirectoryIterator::~IDirectoryIterator() 20 | { 21 | if(m_searchHandle != INVALID_HANDLE_VALUE) 22 | FindClose(m_searchHandle); 23 | } 24 | 25 | void IDirectoryIterator::GetFullPath(char * out, UInt32 outLen) 26 | { 27 | sprintf_s(out, outLen, "%s\\%s", m_path, m_result.cFileName); 28 | } 29 | 30 | std::string IDirectoryIterator::GetFullPath(void) 31 | { 32 | return std::string(m_path) + std::string(m_result.cFileName); 33 | } 34 | 35 | void IDirectoryIterator::Next(void) 36 | { 37 | BOOL result = FindNextFile(m_searchHandle, &m_result); 38 | if(!result) 39 | m_done = true; 40 | } 41 | 42 | bool IDirectoryIterator::Done(void) 43 | { 44 | return m_done; 45 | } 46 | -------------------------------------------------------------------------------- /common/IDirectoryIterator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class IDirectoryIterator 5 | { 6 | public: 7 | IDirectoryIterator(const char * path, const char * match = NULL); 8 | virtual ~IDirectoryIterator(); 9 | 10 | WIN32_FIND_DATA * Get(void) { return &m_result; } 11 | void GetFullPath(char * out, UInt32 outLen); 12 | std::string GetFullPath(void); 13 | 14 | void Next(void); 15 | bool Done(void); 16 | 17 | private: 18 | IDirectoryIterator(); // undefined, disallow 19 | 20 | HANDLE m_searchHandle; 21 | WIN32_FIND_DATA m_result; 22 | bool m_done; 23 | 24 | char m_path[MAX_PATH]; 25 | }; 26 | -------------------------------------------------------------------------------- /common/IDynamicCreate.cpp: -------------------------------------------------------------------------------- 1 | #include "IDynamicCreate.h" 2 | 3 | #if ENABLE_IDYNAMICCREATE 4 | 5 | IClassRegistry _gClassRegistry; 6 | 7 | IClassRegistry::IClassRegistry() 8 | { 9 | // 10 | } 11 | 12 | IClassRegistry::~IClassRegistry() 13 | { 14 | // 15 | } 16 | 17 | void IClassRegistry::RegisterClassInfo(UInt32 id, IDynamicType * typeInfo) 18 | { 19 | theClassRegistry[id] = typeInfo; 20 | } 21 | 22 | IDynamicType * IClassRegistry::LookupClassInfo(UInt32 id) 23 | { 24 | ClassRegistryType::iterator iter = theClassRegistry.find(id); 25 | 26 | return (iter == theClassRegistry.end()) ? NULL : (*iter).second; 27 | } 28 | 29 | IDynamicType * IClassRegistry::LookupClassInfo(char * name) 30 | { 31 | for(ClassRegistryType::iterator iter = theClassRegistry.begin(); iter != theClassRegistry.end(); iter++) 32 | if(!strcmp((*iter).second->GetName(), name)) 33 | return (*iter).second; 34 | 35 | return NULL; 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /common/IErrors.cpp: -------------------------------------------------------------------------------- 1 | #include "common/IErrors.h" 2 | #include "common/IDebugLog.h" 3 | #include 4 | 5 | __declspec(noreturn) static void IErrors_Halt(void) 6 | { 7 | // crash 8 | *((int *)0) = 0xDEADBEEF; 9 | } 10 | 11 | /** 12 | * Report a failed assertion and exit the program 13 | * 14 | * @param file the file where the error occured 15 | * @param line the line number where the error occured 16 | * @param desc an error message 17 | */ 18 | void _AssertionFailed(const char * file, unsigned long line, const char * desc) 19 | { 20 | _FATALERROR("Assertion failed in %s (%d): %s", file, line, desc); 21 | 22 | IErrors_Halt(); 23 | } 24 | 25 | /** 26 | * Report a failed assertion and exit the program 27 | * 28 | * @param file the file where the error occured 29 | * @param line the line number where the error occured 30 | * @param desc an error message 31 | * @param code the error code 32 | */ 33 | void _AssertionFailed_ErrCode(const char * file, unsigned long line, const char * desc, unsigned long long code) 34 | { 35 | if(code & 0xFFFFFFFF00000000) 36 | _FATALERROR("Assertion failed in %s (%d): %s (code = %16I64X (%I64d))", file, line, desc, code, code); 37 | else 38 | { 39 | UInt32 code32 = code; 40 | _FATALERROR("Assertion failed in %s (%d): %s (code = %08X (%d))", file, line, desc, code32, code32); 41 | } 42 | 43 | IErrors_Halt(); 44 | } 45 | 46 | /** 47 | * Report a failed assertion and exit the program 48 | * 49 | * @param file the file where the error occured 50 | * @param line the line number where the error occured 51 | * @param desc an error message 52 | * @param code the error code 53 | */ 54 | void _AssertionFailed_ErrCode(const char * file, unsigned long line, const char * desc, const char * code) 55 | { 56 | _FATALERROR("Assertion failed in %s (%d): %s (code = %s)", file, line, desc, code); 57 | 58 | IErrors_Halt(); 59 | } 60 | -------------------------------------------------------------------------------- /common/IErrors.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void _AssertionFailed(const char * file, unsigned long line, const char * desc); 4 | void _AssertionFailed_ErrCode(const char * file, unsigned long line, const char * desc, unsigned long long code); 5 | void _AssertionFailed_ErrCode(const char * file, unsigned long line, const char * desc, const char * code); 6 | 7 | //! Exit the program if the condition is not true 8 | #define ASSERT(a) do { if(!(a)) _AssertionFailed(__FILE__, __LINE__, #a); } while(0) 9 | //! Exit the program if the condition is not true, with an error message 10 | #define ASSERT_STR(a, b) do { if(!(a)) _AssertionFailed(__FILE__, __LINE__, b); } while(0) 11 | //! Exit the program if the condition is not true, reporting an error code 12 | #define ASSERT_CODE(a, b) do { if(!(a)) _AssertionFailed_ErrCode(__FILE__, __LINE__, #a, b); } while(0) 13 | //! Exit the program if the condition is not true, reporting an error code and message 14 | #define ASSERT_STR_CODE(a, b, c) do { if(!(a)) _AssertionFailed_ErrCode(__FILE__, __LINE__, b, c); } while(0) 15 | //! Exit the program with an error message 16 | #define HALT(a) do { _AssertionFailed(__FILE__, __LINE__, a); } while(0) 17 | //! Exit the program with and error code and message 18 | #define HALT_CODE(a, b) do { _AssertionFailed_ErrCode(__FILE__, __LINE__, a, b); } while(0) 19 | 20 | // based on the boost implementation of static asserts 21 | template struct StaticAssertFailure; 22 | template <> struct StaticAssertFailure { enum { a = 1 }; }; 23 | template struct static_assert_test { }; 24 | 25 | #define __MACRO_JOIN__(a, b) __MACRO_JOIN_2__(a, b) 26 | #define __MACRO_JOIN_2__(a, b) __MACRO_JOIN_3__(a, b) 27 | #define __MACRO_JOIN_3__(a, b) a##b 28 | #define __PREPRO_TOKEN_STR2__(a) #a 29 | #define __PREPRO_TOKEN_STR__(a) __PREPRO_TOKEN_STR2__(a) 30 | #define __LOC__ __FILE__ "("__PREPRO_TOKEN_STR__(__LINE__)") : " 31 | 32 | //#define STATIC_ASSERT(a) typedef static_assert_test )> __MACRO_JOIN__(static_assert_typedef_, __COUNTER__) 33 | #define STATIC_ASSERT(a) static_assert(a) 34 | -------------------------------------------------------------------------------- /common/IEvent.cpp: -------------------------------------------------------------------------------- 1 | #include "IEvent.h" 2 | 3 | IEvent::IEvent() 4 | { 5 | theEvent = CreateEvent(NULL, true, true, NULL); 6 | ASSERT(theEvent); 7 | 8 | blockCount.Set(0); 9 | } 10 | 11 | IEvent::~IEvent() 12 | { 13 | CloseHandle(theEvent); 14 | } 15 | 16 | bool IEvent::Block(void) 17 | { 18 | if(blockCount.Increment() == 1) 19 | return (ResetEvent(theEvent) != 0); 20 | else 21 | return true; 22 | } 23 | 24 | bool IEvent::UnBlock(void) 25 | { 26 | if(blockCount.Decrement() == 0) 27 | return (SetEvent(theEvent) != 0); 28 | else 29 | return true; 30 | } 31 | 32 | bool IEvent::Wait(UInt32 timeout) 33 | { 34 | switch(WaitForSingleObject(theEvent, timeout)) 35 | { 36 | case WAIT_ABANDONED: 37 | HALT("IEvent::Wait: got abandoned event"); 38 | return false; 39 | 40 | case WAIT_OBJECT_0: 41 | return true; 42 | 43 | default: 44 | case WAIT_TIMEOUT: 45 | gLog.FormattedMessage("IEvent::Wait: timeout"); 46 | return false; 47 | } 48 | } 49 | 50 | bool IAutoEvent::Wait(UInt32 timeout) 51 | { 52 | switch(WaitForSingleObject(theEvent, timeout)) 53 | { 54 | case WAIT_ABANDONED: 55 | HALT("IAutoEvent::Wait: got abandoned event"); 56 | return false; 57 | 58 | case WAIT_OBJECT_0: 59 | return true; 60 | 61 | default: 62 | case WAIT_TIMEOUT: 63 | gLog.FormattedMessage("IAutoEvent::Wait: timeout"); 64 | return false; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /common/IEvent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/IInterlockedLong.h" 4 | 5 | class IEvent 6 | { 7 | public: 8 | static const UInt32 kDefaultTimeout = 1000 * 10; 9 | 10 | IEvent(); 11 | ~IEvent(); 12 | 13 | bool Block(void); 14 | bool UnBlock(void); 15 | bool Wait(UInt32 timeout = kDefaultTimeout); 16 | 17 | bool IsBlocked(void) { return blockCount.Get() > 0; } 18 | 19 | private: 20 | HANDLE theEvent; 21 | IInterlockedLong blockCount; 22 | }; 23 | 24 | class IAutoEvent 25 | { 26 | public: 27 | static const UInt32 kDefaultTimeout = 1000 * 10; 28 | 29 | IAutoEvent() { ASSERT(theEvent = CreateEvent(NULL, false, true, NULL)); } 30 | ~IAutoEvent() { CloseHandle(theEvent); } 31 | 32 | void Pulse(void) { PulseEvent(theEvent); } 33 | bool Wait(UInt32 timeout = kDefaultTimeout); 34 | 35 | private: 36 | HANDLE theEvent; 37 | }; 38 | -------------------------------------------------------------------------------- /common/IFIFO.cpp: -------------------------------------------------------------------------------- 1 | #include "IFIFO.h" 2 | 3 | IFIFO::IFIFO(UInt32 length) 4 | { 5 | fifoBuf = new UInt8[length]; 6 | fifoBufSize = length; 7 | fifoBase = 0; 8 | fifoDataLength = 0; 9 | } 10 | 11 | IFIFO::~IFIFO() 12 | { 13 | delete fifoBuf; 14 | } 15 | 16 | bool IFIFO::Push(UInt8 * buf, UInt32 length) 17 | { 18 | // would that overflow the buffer? 19 | if(length > GetBufferRemain()) 20 | return false; 21 | 22 | UInt32 writeOffset = GetWriteOffset(); 23 | 24 | // will this cross the end of the buffer? 25 | if(writeOffset + length > fifoBufSize) 26 | { 27 | UInt32 segmentLength = fifoBufSize - writeOffset; 28 | 29 | std::memcpy(&fifoBuf[writeOffset], buf, segmentLength); 30 | std::memcpy(fifoBuf, &buf[segmentLength], length - segmentLength); 31 | } 32 | else 33 | { 34 | std::memcpy(&fifoBuf[writeOffset], buf, length); 35 | } 36 | 37 | // update pointers 38 | fifoDataLength += length; 39 | 40 | return true; 41 | } 42 | 43 | bool IFIFO::Pop(UInt8 * buf, UInt32 length) 44 | { 45 | bool result = Peek(buf, length); 46 | 47 | // update pointers if we were successful 48 | if(result) 49 | { 50 | fifoDataLength -= length; 51 | fifoBase = ToRawOffset(fifoBase + length); 52 | } 53 | 54 | return result; 55 | } 56 | 57 | bool IFIFO::Peek(UInt8 * buf, UInt32 length) 58 | { 59 | // would that underflow the buffer? 60 | if(length > fifoDataLength) 61 | return false; 62 | 63 | // will this cross the end of the buffer? 64 | if(fifoBase + length > fifoBufSize) 65 | { 66 | UInt32 segmentLength = fifoBufSize - fifoBase; 67 | 68 | std::memcpy(buf, &fifoBuf[fifoBase], segmentLength); 69 | std::memcpy(&buf[segmentLength], fifoBuf, length - segmentLength); 70 | } 71 | else 72 | { 73 | std::memcpy(buf, &fifoBuf[fifoBase], length); 74 | } 75 | 76 | return true; 77 | } 78 | 79 | void IFIFO::Clear(void) 80 | { 81 | fifoDataLength = 0; 82 | 83 | // this isn't needed, but staying away from the buffer end is always good 84 | fifoBase = 0; 85 | } 86 | -------------------------------------------------------------------------------- /common/IFIFO.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class IFIFO 4 | { 5 | public: 6 | IFIFO(UInt32 length = 0); 7 | virtual ~IFIFO(); 8 | 9 | virtual bool Push(UInt8 * buf, UInt32 length); 10 | virtual bool Pop(UInt8 * buf, UInt32 length); 11 | virtual bool Peek(UInt8 * buf, UInt32 length); 12 | virtual void Clear(void); 13 | 14 | UInt32 GetBufferSize(void) { return fifoBufSize; } 15 | UInt32 GetBufferRemain(void) { return fifoBufSize - fifoDataLength; } 16 | UInt32 GetDataLength(void) { return fifoDataLength; } 17 | 18 | private: 19 | UInt32 ToRawOffset(UInt32 in) { return in % fifoBufSize; } 20 | UInt32 ToDataOffset(UInt32 in) { return ToRawOffset(fifoBase + in); } 21 | UInt32 GetWriteOffset(void) { return ToDataOffset(fifoDataLength); } 22 | 23 | UInt8 * fifoBuf; 24 | UInt32 fifoBufSize; // size of the buffer (in bytes) 25 | UInt32 fifoBase; // pointer to the beginning of the data block 26 | UInt32 fifoDataLength; // size of the data block 27 | }; 28 | -------------------------------------------------------------------------------- /common/IFileStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/IDataStream.h" 4 | 5 | /** 6 | * An input file stream 7 | */ 8 | class IFileStream : public IDataStream 9 | { 10 | public: 11 | IFileStream(); 12 | IFileStream(const char * name); 13 | ~IFileStream(); 14 | 15 | bool Open(const char * name); 16 | bool BrowseOpen(void); 17 | 18 | bool Create(const char * name); 19 | bool BrowseCreate(const char * defaultName = NULL, const char * defaultPath = NULL, const char * title = NULL); 20 | 21 | void Close(void); 22 | 23 | HANDLE GetHandle(void) { return theFile; } 24 | 25 | virtual void ReadBuf(void * buf, UInt32 inLength); 26 | virtual void WriteBuf(const void * buf, UInt32 inLength); 27 | virtual void SetOffset(SInt64 inOffset); 28 | 29 | static void MakeAllDirs(const char * path); 30 | static char * ExtractFileName(char * path); 31 | 32 | protected: 33 | HANDLE theFile; 34 | }; 35 | -------------------------------------------------------------------------------- /common/IInterlockedLong.cpp: -------------------------------------------------------------------------------- 1 | #include "IInterlockedLong.h" 2 | 3 | // all functions are inlined 4 | -------------------------------------------------------------------------------- /common/IInterlockedLong.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct IInterlockedLong 4 | { 5 | public: 6 | long Increment(void) { return InterlockedIncrement(&value); } 7 | long Decrement(void) { return InterlockedDecrement(&value); } 8 | long Get(void) { return value; } 9 | long Set(long in) { return InterlockedExchange(&value, in); } 10 | long TrySetIf(long newValue, long expectedOldValue) 11 | { return InterlockedCompareExchange(&value, newValue, expectedOldValue); } 12 | 13 | // interlock variable semantics 14 | bool Claim(void) { return TrySetIf(1, 0) == 0; } 15 | bool Release(void) { return TrySetIf(0, 1) == 1; } 16 | 17 | private: 18 | volatile long value; 19 | }; 20 | -------------------------------------------------------------------------------- /common/ILinkedList.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ILink members must be public 4 | template 5 | struct ILink 6 | { 7 | static const UInt32 s_offset; 8 | 9 | ILink * next; 10 | ILink * prev; 11 | 12 | T * GetObj(void) { return (T *)(((uintptr_t)this) - s_offset); } 13 | 14 | static ILink * GetLink(T * obj) { return (ILink *)(((uintptr_t)obj) + s_offset); } 15 | 16 | void Unlink(void) 17 | { 18 | if(next) next->prev = prev; 19 | if(prev) prev->next = next; 20 | 21 | next = prev = NULL; 22 | } 23 | 24 | void LinkBefore(T * obj) 25 | { 26 | LinkBefore(GetLink(obj)); 27 | } 28 | 29 | void LinkAfter(T * obj) 30 | { 31 | LinkAfter(GetLink(obj)); 32 | } 33 | 34 | void LinkBefore(ILink * link) 35 | { 36 | link->next = this; 37 | link->prev = prev; 38 | 39 | if(prev) 40 | { 41 | prev->next = link; 42 | } 43 | 44 | prev = link; 45 | } 46 | 47 | void LinkAfter(ILink * link) 48 | { 49 | link->next = next; 50 | link->prev = this; 51 | 52 | if(next) 53 | { 54 | next->prev = link; 55 | } 56 | 57 | next = link; 58 | } 59 | }; 60 | 61 | template 62 | struct ILinkedList 63 | { 64 | ILink begin; 65 | ILink end; 66 | 67 | void Reset(void) 68 | { 69 | begin.next = &end; 70 | begin.prev = NULL; 71 | end.next = NULL; 72 | end.prev = &begin; 73 | } 74 | 75 | void PushFront(T * obj) 76 | { 77 | ILink * objLink = ILink ::GetLink(obj); 78 | 79 | objLink->next = begin.next; 80 | objLink->prev = &begin; 81 | 82 | if(objLink->next) 83 | { 84 | objLink->next->prev = objLink; 85 | } 86 | 87 | begin.next = objLink; 88 | } 89 | }; 90 | 91 | #define ILINK_INIT(baseType, memberName) template const UInt32 ILink ::s_offset = offsetof(baseType, memberName) 92 | -------------------------------------------------------------------------------- /common/IMemPool.cpp: -------------------------------------------------------------------------------- 1 | #include "IMemPool.h" 2 | 3 | void Test_IMemPool(void) 4 | { 5 | IMemPool pool; 6 | 7 | _DMESSAGE("main: pool test"); 8 | gLog.Indent(); 9 | 10 | _DMESSAGE("start"); 11 | pool.Dump(); 12 | 13 | UInt32 * data0, * data1, * data2; 14 | 15 | data0 = pool.Allocate(); 16 | _DMESSAGE("alloc0 = %08X", data0); 17 | pool.Dump(); 18 | 19 | data1 = pool.Allocate(); 20 | _DMESSAGE("alloc1 = %08X", data1); 21 | pool.Dump(); 22 | 23 | data2 = pool.Allocate(); 24 | _DMESSAGE("alloc2 = %08X", data2); 25 | pool.Dump(); 26 | 27 | _DMESSAGE("free0 %08X", data0); 28 | pool.Free(data0); 29 | pool.Dump(); 30 | 31 | data0 = pool.Allocate(); 32 | _DMESSAGE("alloc0 = %08X", data0); 33 | pool.Dump(); 34 | 35 | _DMESSAGE("free2 %08X", data2); 36 | pool.Free(data2); 37 | pool.Dump(); 38 | 39 | _DMESSAGE("done"); 40 | pool.Dump(); 41 | 42 | gLog.Outdent(); 43 | } 44 | -------------------------------------------------------------------------------- /common/IMutex.cpp: -------------------------------------------------------------------------------- 1 | #include "IMutex.h" 2 | 3 | IMutex::IMutex() 4 | { 5 | theMutex = CreateMutex(NULL, true, NULL); 6 | } 7 | 8 | IMutex::~IMutex() 9 | { 10 | CloseHandle(theMutex); 11 | } 12 | 13 | bool IMutex::Wait(UInt32 timeout) 14 | { 15 | switch(WaitForSingleObject(theMutex, timeout)) 16 | { 17 | case WAIT_ABANDONED: 18 | HALT("IMutex::Wait: got abandoned mutex"); 19 | return false; 20 | 21 | case WAIT_OBJECT_0: 22 | return true; 23 | 24 | default: 25 | case WAIT_TIMEOUT: 26 | gLog.FormattedMessage("IMutex::Wait: timeout"); 27 | return false; 28 | } 29 | } 30 | 31 | void IMutex::Release(void) 32 | { 33 | ASSERT_STR(ReleaseMutex(theMutex), "IMutex::Release: failed to release mutex"); 34 | } 35 | -------------------------------------------------------------------------------- /common/IMutex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class IMutex 4 | { 5 | public: 6 | static const UInt32 kDefaultTimeout = 1000 * 10; 7 | 8 | IMutex(); 9 | ~IMutex(); 10 | 11 | bool Wait(UInt32 timeout = kDefaultTimeout); 12 | void Release(void); 13 | 14 | private: 15 | HANDLE theMutex; 16 | }; 17 | -------------------------------------------------------------------------------- /common/IObjectPool.cpp: -------------------------------------------------------------------------------- 1 | #include "common/IObjectPool.h" 2 | -------------------------------------------------------------------------------- /common/IObjectPool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/ITypes.h" 4 | #include "common/IErrors.h" 5 | 6 | #pragma warning(push) 7 | #pragma warning(disable: 4804) 8 | 9 | /** 10 | * A memory pool of statically allocated objects 11 | */ 12 | template 13 | class IObjectPool 14 | { 15 | public: 16 | IObjectPool() { lastFreed = 0; ASSERT_STR(numObjects > 0, "IObjectPool: bad numObjects"); } 17 | ~IObjectPool() { } 18 | 19 | //! Get an object from the pool 20 | T & Alloc(void) 21 | { 22 | UInt32 traverse = lastFreed; 23 | 24 | for(UInt32 i = 0; i < numObjects; i++) 25 | { 26 | if(!pool[traverse].allocated) 27 | return pool[traverse].data; 28 | 29 | traverse++; 30 | if(traverse > numObjects) 31 | traverse = 0; 32 | } 33 | 34 | HALT("IObjectPool::Alloc: couldn't find free entry"); 35 | 36 | return pool[0].data; 37 | } 38 | 39 | //! Release an object back to the pool 40 | void Free(T & in) 41 | { 42 | for(UInt32 i = 0; i < numObjects; i++) 43 | { 44 | if(pool[i].allocated && (&in == &pool[i].data)) 45 | { 46 | pool[i].allocated = 0; 47 | lastFreed = i; 48 | 49 | return; 50 | } 51 | } 52 | 53 | HALT("IObjectPool::Free: object not in list"); 54 | } 55 | 56 | private: 57 | //! Object storage with an "allocated" flag 58 | struct Pair 59 | { 60 | T data; //!< the object 61 | UInt32 allocated; //!< is this object allocated? 62 | }; 63 | 64 | Pair pool[numObjects]; //!< the object pool 65 | UInt32 lastFreed; //!< the last freed object 66 | }; 67 | 68 | #pragma warning(pop) 69 | -------------------------------------------------------------------------------- /common/IPipeClient.cpp: -------------------------------------------------------------------------------- 1 | #include "IPipeClient.h" 2 | 3 | IPipeClient::IPipeClient() 4 | :m_pipe(INVALID_HANDLE_VALUE) 5 | { 6 | // 7 | } 8 | 9 | IPipeClient::~IPipeClient() 10 | { 11 | Close(); 12 | } 13 | 14 | bool IPipeClient::Open(const char * name) 15 | { 16 | Close(); 17 | 18 | m_pipe = CreateFile( 19 | name, 20 | GENERIC_READ | GENERIC_WRITE, 21 | 0, 22 | NULL, 23 | OPEN_EXISTING, 24 | 0, 25 | NULL); 26 | 27 | return m_pipe != INVALID_HANDLE_VALUE; 28 | } 29 | 30 | void IPipeClient::Close(void) 31 | { 32 | if(m_pipe != INVALID_HANDLE_VALUE) 33 | { 34 | CloseHandle(m_pipe); 35 | m_pipe = INVALID_HANDLE_VALUE; 36 | } 37 | } 38 | 39 | bool IPipeClient::ReadMessage(UInt8 * buf, UInt32 length) 40 | { 41 | UInt32 bytesRead; 42 | 43 | ReadFile(m_pipe, buf, length, &bytesRead, NULL); 44 | 45 | IPipeServer::MessageHeader * header = (IPipeServer::MessageHeader *)buf; 46 | 47 | return 48 | (bytesRead >= sizeof(IPipeServer::MessageHeader)) && // has a valid header 49 | (bytesRead >= (sizeof(IPipeServer::MessageHeader) + header->length)); 50 | } 51 | 52 | bool IPipeClient::WriteMessage(IPipeServer::MessageHeader * msg) 53 | { 54 | UInt32 bytesWritten; 55 | UInt32 length = sizeof(IPipeServer::MessageHeader) + msg->length; 56 | 57 | WriteFile(m_pipe, msg, length, &bytesWritten, NULL); 58 | 59 | return bytesWritten >= length; 60 | } 61 | -------------------------------------------------------------------------------- /common/IPipeClient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "common/IPipeServer.h" 6 | 7 | class IPipeClient 8 | { 9 | public: 10 | IPipeClient(); 11 | virtual ~IPipeClient(); 12 | 13 | bool Open(const char * name); 14 | void Close(void); 15 | 16 | bool ReadMessage(UInt8 * buf, UInt32 length); 17 | bool WriteMessage(IPipeServer::MessageHeader * msg); 18 | 19 | private: 20 | HANDLE m_pipe; 21 | std::string m_name; 22 | }; 23 | -------------------------------------------------------------------------------- /common/IPipeServer.cpp: -------------------------------------------------------------------------------- 1 | #include "IPipeServer.h" 2 | 3 | IPipeServer::IPipeServer() 4 | :m_pipe(INVALID_HANDLE_VALUE) 5 | { 6 | // 7 | } 8 | 9 | IPipeServer::~IPipeServer() 10 | { 11 | Close(); 12 | } 13 | 14 | bool IPipeServer::Open(const char * name) 15 | { 16 | Close(); 17 | 18 | m_pipe = CreateNamedPipe( 19 | name, 20 | PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, 21 | PIPE_TYPE_MESSAGE | PIPE_TYPE_MESSAGE | PIPE_WAIT, 22 | PIPE_UNLIMITED_INSTANCES, 23 | 8192, 8192, 24 | 10 * 1000, // 10 seconds 25 | NULL); 26 | 27 | return m_pipe != INVALID_HANDLE_VALUE; 28 | } 29 | 30 | void IPipeServer::Close(void) 31 | { 32 | if(m_pipe != INVALID_HANDLE_VALUE) 33 | { 34 | CloseHandle(m_pipe); 35 | m_pipe = INVALID_HANDLE_VALUE; 36 | } 37 | } 38 | 39 | bool IPipeServer::WaitForClient(void) 40 | { 41 | bool result = ConnectNamedPipe(m_pipe, NULL) != 0; 42 | 43 | // already connected? 44 | if(!result) 45 | { 46 | if(GetLastError() == ERROR_PIPE_CONNECTED) 47 | result = true; 48 | } 49 | 50 | return result; 51 | } 52 | 53 | bool IPipeServer::ReadMessage(UInt8 * buf, UInt32 length) 54 | { 55 | UInt32 bytesRead; 56 | 57 | ReadFile(m_pipe, buf, length, &bytesRead, NULL); 58 | 59 | MessageHeader * header = (MessageHeader *)buf; 60 | 61 | return 62 | (bytesRead >= sizeof(MessageHeader)) && // has a valid header 63 | (bytesRead >= (sizeof(MessageHeader) + header->length)); 64 | } 65 | 66 | bool IPipeServer::WriteMessage(MessageHeader * msg) 67 | { 68 | UInt32 bytesWritten; 69 | UInt32 length = sizeof(MessageHeader) + msg->length; 70 | 71 | WriteFile(m_pipe, msg, length, &bytesWritten, NULL); 72 | 73 | return bytesWritten >= length; 74 | } 75 | -------------------------------------------------------------------------------- /common/IPipeServer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class IPipeServer 4 | { 5 | public: 6 | struct MessageHeader 7 | { 8 | UInt32 type; 9 | UInt32 length; 10 | }; 11 | 12 | IPipeServer(); 13 | virtual ~IPipeServer(); 14 | 15 | bool Open(const char * name); 16 | void Close(void); 17 | 18 | bool WaitForClient(void); 19 | 20 | bool ReadMessage(UInt8 * buf, UInt32 length); 21 | bool WriteMessage(MessageHeader * msg); 22 | 23 | private: 24 | HANDLE m_pipe; 25 | }; 26 | -------------------------------------------------------------------------------- /common/IPrefix.cpp: -------------------------------------------------------------------------------- 1 | #include "IPrefix.h" 2 | -------------------------------------------------------------------------------- /common/IPrefix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4018 - signed/unsigned mismatch 4 | // 4244 - loss of data by assignment 5 | // 4267 - possible loss of data (truncation) 6 | // 4305 - truncation by assignment 7 | // 4288 - disable warning for crap microsoft extension screwing up the scope of variables defined in for loops 8 | // 4311 - pointer truncation 9 | // 4312 - pointer extension 10 | #pragma warning(disable: 4018 4244 4267 4305 4288 4312 4311) 11 | 12 | #include 13 | #include 14 | #include 15 | #include "common/ITypes.h" 16 | #include "common/IErrors.h" 17 | #include "common/IDynamicCreate.h" 18 | #include "common/IDebugLog.h" 19 | #include "common/ISingleton.h" 20 | #include 21 | #include 22 | -------------------------------------------------------------------------------- /common/IRangeMap.cpp: -------------------------------------------------------------------------------- 1 | #include "IRangeMap.h" 2 | -------------------------------------------------------------------------------- /common/IReadWriteLock.cpp: -------------------------------------------------------------------------------- 1 | #include "IReadWriteLock.h" 2 | 3 | IReadWriteLock::IReadWriteLock() 4 | { 5 | readCount.Set(0); 6 | readBlocker.UnBlock(); 7 | writeBlocker.UnBlock(); 8 | } 9 | 10 | IReadWriteLock::~IReadWriteLock() 11 | { 12 | // 13 | } 14 | 15 | void IReadWriteLock::StartRead(void) 16 | { 17 | enterBlocker.Enter(); 18 | readBlocker.Wait(); 19 | if(readCount.Increment() == 1) 20 | writeBlocker.Block(); 21 | enterBlocker.Leave(); 22 | } 23 | 24 | void IReadWriteLock::EndRead(void) 25 | { 26 | if(!readCount.Decrement()) 27 | writeBlocker.UnBlock(); 28 | } 29 | 30 | void IReadWriteLock::StartWrite(void) 31 | { 32 | writeMutex.Enter(); 33 | enterBlocker.Enter(); 34 | readBlocker.Block(); 35 | writeBlocker.Wait(); 36 | enterBlocker.Leave(); 37 | } 38 | 39 | void IReadWriteLock::EndWrite(void) 40 | { 41 | readBlocker.UnBlock(); 42 | writeMutex.Leave(); 43 | } 44 | -------------------------------------------------------------------------------- /common/IReadWriteLock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/ICriticalSection.h" 4 | #include "common/IEvent.h" 5 | #include "common/IInterlockedLong.h" 6 | 7 | class IReadWriteLock 8 | { 9 | public: 10 | IReadWriteLock(); 11 | ~IReadWriteLock(); 12 | 13 | void StartRead(void); 14 | void EndRead(void); 15 | void StartWrite(void); 16 | void EndWrite(void); 17 | 18 | private: 19 | IEvent readBlocker; 20 | IEvent writeBlocker; 21 | ICriticalSection enterBlocker; 22 | ICriticalSection writeMutex; 23 | IInterlockedLong readCount; 24 | }; 25 | -------------------------------------------------------------------------------- /common/ISegmentStream.cpp: -------------------------------------------------------------------------------- 1 | #include "common/ISegmentStream.h" 2 | 3 | ISegmentStream::ISegmentStream() 4 | { 5 | streamLength = 0; 6 | } 7 | 8 | ISegmentStream::~ISegmentStream() 9 | { 10 | 11 | } 12 | 13 | void ISegmentStream::AttachStream(IDataStream * inStream) 14 | { 15 | parent = inStream; 16 | streamLength = 0; 17 | streamOffset = 0; 18 | } 19 | 20 | void ISegmentStream::AddSegment(UInt64 offset, UInt64 length, UInt64 parentOffset) 21 | { 22 | segmentInfo.push_back(SegmentInfo(offset, length, parentOffset)); 23 | 24 | if(streamLength < (parentOffset + length)) 25 | streamLength = parentOffset + length; 26 | } 27 | 28 | void ISegmentStream::ReadBuf(void * buf, UInt32 inLength) 29 | { 30 | UInt32 remain = inLength; 31 | UInt8 * out = (UInt8 *)buf; 32 | 33 | while(remain > 0) 34 | { 35 | SegmentInfo * info = LookupInfo(streamOffset); 36 | ASSERT(info); 37 | 38 | UInt64 segmentOffset = streamOffset - info->offset; 39 | UInt64 transferLength = info->length - segmentOffset; 40 | 41 | if(transferLength > remain) 42 | transferLength = remain; 43 | 44 | parent->SetOffset(info->parentOffset + segmentOffset); 45 | parent->ReadBuf(out, transferLength); 46 | 47 | streamOffset += transferLength; 48 | remain -= transferLength; 49 | } 50 | } 51 | 52 | void ISegmentStream::WriteBuf(const void * buf, UInt32 inLength) 53 | { 54 | HALT("ISegmentStream::WriteBuf: writing unsupported"); 55 | } 56 | 57 | void ISegmentStream::SetOffset(SInt64 inOffset) 58 | { 59 | SegmentInfo * info = LookupInfo(inOffset); 60 | ASSERT(info); 61 | 62 | UInt64 segmentOffset = inOffset - info->offset; 63 | 64 | parent->SetOffset(info->parentOffset + segmentOffset); 65 | 66 | streamOffset = inOffset; 67 | } 68 | 69 | ISegmentStream::SegmentInfo * ISegmentStream::LookupInfo(UInt64 offset) 70 | { 71 | for(SegmentInfoListType::iterator iter = segmentInfo.begin(); iter != segmentInfo.end(); iter++) 72 | if((offset >= (*iter).offset) && (offset < (*iter).offset + (*iter).length)) 73 | return &(*iter); 74 | 75 | return NULL; 76 | } 77 | -------------------------------------------------------------------------------- /common/ISegmentStream.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/IDataStream.h" 4 | #include 5 | 6 | /** 7 | * An stream composed of many non-contiguous segments of a larger stream 8 | */ 9 | class ISegmentStream : public IDataStream 10 | { 11 | public: 12 | ISegmentStream(); 13 | ~ISegmentStream(); 14 | 15 | void AttachStream(IDataStream * inStream); 16 | 17 | void AddSegment(UInt64 offset, UInt64 length, UInt64 parentOffset); 18 | 19 | virtual void ReadBuf(void * buf, UInt32 inLength); 20 | virtual void WriteBuf(const void * buf, UInt32 inLength); 21 | virtual void SetOffset(SInt64 inOffset); 22 | 23 | protected: 24 | IDataStream * parent; 25 | 26 | struct SegmentInfo 27 | { 28 | SegmentInfo(UInt64 inOffset, UInt64 inLength, UInt64 inParentOffset) 29 | { 30 | offset = inOffset; 31 | length = inLength; 32 | parentOffset = inParentOffset; 33 | } 34 | 35 | UInt64 offset; 36 | UInt64 length; 37 | UInt64 parentOffset; 38 | }; 39 | 40 | typedef std::vector SegmentInfoListType; 41 | SegmentInfoListType segmentInfo; 42 | 43 | SegmentInfo * LookupInfo(UInt64 offset); 44 | }; 45 | -------------------------------------------------------------------------------- /common/ISingleton.cpp: -------------------------------------------------------------------------------- 1 | #include "common/ISingleton.h" 2 | 3 | //template T * Singleton ::ms_Singleton = 0; -------------------------------------------------------------------------------- /common/ISingleton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/IErrors.h" 4 | 5 | #pragma warning(push) 6 | #pragma warning(disable: 4311 4312) 7 | 8 | /** 9 | * A singleton base class 10 | * 11 | * Singletons are useful when you have a class that will be instantiated once, 12 | * like a global manager. 13 | */ 14 | template 15 | class ISingleton 16 | { 17 | static T * ms_Singleton; 18 | 19 | public: 20 | ISingleton() 21 | { 22 | ASSERT(!ms_Singleton); 23 | int offset = (int)(T *)1 - (int)(ISingleton *)(T *)1; 24 | ms_Singleton = (T *)((int)this + offset); 25 | } 26 | 27 | virtual ~ISingleton() 28 | { 29 | ASSERT(ms_Singleton); 30 | ms_Singleton = 0; 31 | } 32 | 33 | /** 34 | * Returns the single instance of the derived class 35 | */ 36 | static T& GetSingleton(void) 37 | { 38 | ASSERT(ms_Singleton); 39 | return *ms_Singleton; 40 | } 41 | 42 | /** 43 | * Returns a pointer to the single instance of the derived class 44 | */ 45 | static T * GetSingletonPtr(void) 46 | { 47 | return ms_Singleton; 48 | } 49 | }; 50 | 51 | template T * ISingleton ::ms_Singleton = 0; 52 | 53 | #pragma warning(pop) 54 | -------------------------------------------------------------------------------- /common/ITextParser.cpp: -------------------------------------------------------------------------------- 1 | #include "ITextParser.h" 2 | #include "IDataStream.h" 3 | 4 | ITextParser::ITextParser() 5 | :m_stream(NULL) 6 | { 7 | // 8 | } 9 | 10 | ITextParser::ITextParser(IDataStream * stream) 11 | :m_stream(stream) 12 | { 13 | // 14 | } 15 | 16 | ITextParser::~ITextParser() 17 | { 18 | // 19 | } 20 | 21 | void ITextParser::Attach(IDataStream * stream) 22 | { 23 | m_stream = stream; 24 | } 25 | 26 | void ITextParser::SkipWhitespace(void) 27 | { 28 | while(!m_stream->HitEOF()) 29 | { 30 | char data = m_stream->Peek8(); 31 | 32 | if(!isspace(data)) 33 | break; 34 | 35 | m_stream->Skip(1); 36 | } 37 | } 38 | 39 | void ITextParser::SkipLine(void) 40 | { 41 | while(!m_stream->HitEOF()) 42 | { 43 | char data = m_stream->Peek8(); 44 | 45 | if((data != '\n') && (data != '\r')) 46 | break; 47 | 48 | m_stream->Skip(1); 49 | } 50 | } 51 | 52 | void ITextParser::ReadLine(char * out, UInt32 length) 53 | { 54 | m_stream->ReadString(out, length, '\n', '\r'); 55 | } 56 | 57 | void ITextParser::ReadToken(char * buf, UInt32 bufLength) 58 | { 59 | char * traverse = buf; 60 | 61 | ASSERT_STR(bufLength > 0, "ITextParser::ReadToken: zero-sized buffer"); 62 | 63 | if(bufLength == 1) 64 | { 65 | buf[0] = 0; 66 | } 67 | else 68 | { 69 | bufLength--; 70 | 71 | for(UInt32 i = 0; (i < bufLength) && !m_stream->HitEOF(); i++) 72 | { 73 | UInt8 data = m_stream->Read8(); 74 | 75 | if(isspace(data) || !data) 76 | break; 77 | 78 | *traverse++ = data; 79 | } 80 | 81 | *traverse++ = 0; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /common/ITextParser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/IDataStream.h" 4 | 5 | class ITextParser 6 | { 7 | public: 8 | ITextParser(); 9 | ITextParser(IDataStream * stream); 10 | ~ITextParser(); 11 | 12 | void Attach(IDataStream * stream); 13 | IDataStream * GetStream(void) { return m_stream; } 14 | 15 | bool HitEOF(void) { return m_stream->HitEOF(); } 16 | 17 | void SkipWhitespace(void); 18 | void SkipLine(void); 19 | 20 | void ReadLine(char * out, UInt32 length); 21 | void ReadToken(char * out, UInt32 length); 22 | 23 | private: 24 | IDataStream * m_stream; 25 | }; 26 | -------------------------------------------------------------------------------- /common/IThread.cpp: -------------------------------------------------------------------------------- 1 | #include "IThread.h" 2 | 3 | IThread::IThread() 4 | { 5 | mainProc = NULL; 6 | mainProcParam = NULL; 7 | stopRequested = false; 8 | isRunning = false; 9 | theThread = NULL; 10 | threadID = 0; 11 | } 12 | 13 | IThread::~IThread() 14 | { 15 | ForceStop(); 16 | 17 | if(theThread) 18 | { 19 | CloseHandle(theThread); 20 | } 21 | } 22 | 23 | void IThread::Start(MainProcPtr proc, void * procParam) 24 | { 25 | if(!isRunning) 26 | { 27 | isRunning = true; 28 | stopRequested = false; 29 | 30 | mainProc = proc; 31 | mainProcParam = procParam; 32 | 33 | theThread = CreateThread(NULL, 0, _ThreadProc, static_cast(this), 0, &threadID); 34 | } 35 | } 36 | 37 | void IThread::Stop(void) 38 | { 39 | if(isRunning) 40 | { 41 | stopRequested = true; 42 | } 43 | } 44 | 45 | void IThread::ForceStop(void) 46 | { 47 | if(isRunning) 48 | { 49 | TerminateThread(theThread, 0); 50 | 51 | isRunning = false; 52 | } 53 | } 54 | 55 | UInt32 IThread::_ThreadProc(void * param) 56 | { 57 | IThread * _this = (IThread *)param; 58 | 59 | if(_this->mainProc) 60 | _this->mainProc(_this->mainProcParam); 61 | 62 | _this->isRunning = false; 63 | 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /common/IThread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // TODO: I really don't like the interface for this 4 | 5 | class IThread 6 | { 7 | public: 8 | typedef void (* MainProcPtr)(void * param); 9 | 10 | IThread(); 11 | ~IThread(); 12 | 13 | void Start(MainProcPtr proc, void * procParam = NULL); 14 | void Stop(void); 15 | void ForceStop(void); 16 | 17 | bool IsRunning(void) { return isRunning; } 18 | bool StopRequested(void) { return stopRequested; } 19 | 20 | HANDLE GetHandle(void) { return theThread; } 21 | 22 | protected: 23 | MainProcPtr mainProc; 24 | void * mainProcParam; 25 | volatile bool stopRequested; 26 | bool isRunning; 27 | HANDLE theThread; 28 | UInt32 threadID; 29 | 30 | private: 31 | static UInt32 WINAPI _ThreadProc(void * param); 32 | }; 33 | -------------------------------------------------------------------------------- /common/ITimer.cpp: -------------------------------------------------------------------------------- 1 | #include "ITimer.h" 2 | 3 | // QueryPerformanceCounter is very accurate, but hardware bugs can cause it to return inaccurate results 4 | // this code uses multimedia timers to check for glitches in QPC 5 | 6 | double ITimer::s_secondsPerCount = 0; 7 | TIMECAPS ITimer::s_timecaps = { 0 }; 8 | bool ITimer::s_setTime = false; 9 | UInt64 ITimer::s_lastQPC = 0; 10 | UInt64 ITimer::s_qpcWrapMargin = 0; 11 | bool ITimer::s_hasLastQPC = false; 12 | UInt32 ITimer::s_qpcWrapCount = 0; 13 | UInt32 ITimer::s_qpcInaccurateCount = 0; 14 | 15 | ITimer::ITimer() 16 | :m_qpcBase(0), m_tickBase(0) 17 | { 18 | Init(); 19 | } 20 | 21 | ITimer::~ITimer() 22 | { 23 | 24 | } 25 | 26 | void ITimer::Init(void) 27 | { 28 | if(!s_secondsPerCount) 29 | { 30 | // init qpc 31 | UInt64 countsPerSecond; 32 | BOOL res = QueryPerformanceFrequency((LARGE_INTEGER *)&countsPerSecond); 33 | 34 | ASSERT_STR(res, "ITimer: no high-resolution timer support"); 35 | 36 | s_secondsPerCount = 1.0 / countsPerSecond; 37 | 38 | s_qpcWrapMargin = (UInt64)(-((SInt64)(countsPerSecond * 60))); // detect if we've wrapped around by a delta greater than this - also limits max time 39 | _MESSAGE("s_qpcWrapMargin: %016I64X", s_qpcWrapMargin); 40 | _MESSAGE("wrap time: %fs", ((double)0xFFFFFFFFFFFFFFFF) * s_secondsPerCount); 41 | 42 | // init multimedia timer 43 | timeGetDevCaps(&s_timecaps, sizeof(s_timecaps)); 44 | 45 | _MESSAGE("min timer period = %d", s_timecaps.wPeriodMin); 46 | 47 | s_setTime = (timeBeginPeriod(s_timecaps.wPeriodMin) == TIMERR_NOERROR); 48 | if(!s_setTime) 49 | _WARNING("couldn't change timer period"); 50 | } 51 | } 52 | 53 | void ITimer::DeInit(void) 54 | { 55 | if(s_secondsPerCount) 56 | { 57 | if(s_setTime) 58 | { 59 | timeEndPeriod(s_timecaps.wPeriodMin); 60 | s_setTime = false; 61 | } 62 | 63 | if(s_qpcWrapCount) 64 | _MESSAGE("s_qpcWrapCount: %d", s_qpcWrapCount); 65 | 66 | s_secondsPerCount = 0; 67 | } 68 | } 69 | 70 | void ITimer::Start(void) 71 | { 72 | m_qpcBase = GetQPC(); 73 | m_tickBase = timeGetTime(); 74 | } 75 | 76 | double ITimer::GetElapsedTime(void) 77 | { 78 | UInt64 qpcNow = GetQPC(); 79 | UInt32 tickNow = timeGetTime(); 80 | 81 | UInt64 qpcDelta = qpcNow - m_qpcBase; 82 | UInt64 tickDelta = tickNow - m_tickBase; 83 | 84 | double qpcSeconds = ((double)qpcDelta) * s_secondsPerCount; 85 | double tickSeconds = ((double)tickDelta) * 0.001; // ticks are in milliseconds 86 | double qpcTickDelta = qpcSeconds - tickSeconds; 87 | 88 | if(qpcTickDelta < 0) qpcTickDelta = -qpcTickDelta; 89 | 90 | // if they differ by more than one second, something's wrong, return 91 | if(qpcTickDelta > 1) 92 | { 93 | s_qpcInaccurateCount++; 94 | return tickSeconds; 95 | } 96 | else 97 | { 98 | return qpcSeconds; 99 | } 100 | } 101 | 102 | UInt64 ITimer::GetQPC(void) 103 | { 104 | UInt64 now; 105 | 106 | QueryPerformanceCounter((LARGE_INTEGER *)&now); 107 | 108 | if(s_hasLastQPC) 109 | { 110 | UInt64 delta = now - s_lastQPC; 111 | 112 | if(delta > s_qpcWrapMargin) 113 | { 114 | // we've gone back in time, return a kludged value 115 | 116 | s_lastQPC = now; 117 | now = s_lastQPC + 1; 118 | 119 | s_qpcWrapCount++; 120 | } 121 | else 122 | { 123 | s_lastQPC = now; 124 | } 125 | } 126 | else 127 | { 128 | s_hasLastQPC = true; 129 | s_lastQPC = now; 130 | } 131 | 132 | return now; 133 | } 134 | -------------------------------------------------------------------------------- /common/ITimer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/ITypes.h" 4 | 5 | /** 6 | * A high-resolution timer. 7 | */ 8 | class ITimer 9 | { 10 | public: 11 | ITimer(); 12 | ~ITimer(); 13 | 14 | static void Init(void); 15 | static void DeInit(void); 16 | 17 | void Start(void); 18 | 19 | double GetElapsedTime(void); // seconds 20 | 21 | private: 22 | UInt64 m_qpcBase; // QPC 23 | UInt32 m_tickBase; // timeGetTime 24 | 25 | static double s_secondsPerCount; 26 | static TIMECAPS s_timecaps; 27 | static bool s_setTime; 28 | 29 | // safe QPC stuff 30 | static UInt64 GetQPC(void); 31 | 32 | static UInt64 s_lastQPC; 33 | static UInt64 s_qpcWrapMargin; 34 | static bool s_hasLastQPC; 35 | 36 | static UInt32 s_qpcWrapCount; 37 | static UInt32 s_qpcInaccurateCount; 38 | }; 39 | -------------------------------------------------------------------------------- /common/ITypes.cpp: -------------------------------------------------------------------------------- 1 | #include "ITypes.h" 2 | 3 | Bitstring::Bitstring() 4 | :data(NULL) 5 | { 6 | 7 | } 8 | 9 | Bitstring::Bitstring(UInt32 inLength) 10 | :data(NULL) 11 | { 12 | Alloc(inLength); 13 | } 14 | 15 | Bitstring::~Bitstring() 16 | { 17 | Dispose(); 18 | } 19 | 20 | void Bitstring::Alloc(UInt32 inLength) 21 | { 22 | Dispose(); 23 | 24 | inLength = (inLength + 7) & ~7; 25 | length = inLength >> 3; 26 | 27 | data = new UInt8[length]; 28 | } 29 | 30 | void Bitstring::Dispose(void) 31 | { 32 | delete [] data; 33 | } 34 | 35 | void Bitstring::Clear(void) 36 | { 37 | std::memset(data, 0, length); 38 | } 39 | 40 | void Bitstring::Clear(UInt32 idx) 41 | { 42 | ASSERT_STR(idx < (length << 3), "Bitstring::Clear: out of range"); 43 | 44 | data[idx >> 3] &= ~(1 << (idx & 7)); 45 | } 46 | 47 | void Bitstring::Set(UInt32 idx) 48 | { 49 | ASSERT_STR(idx < (length << 3), "Bitstring::Set: out of range"); 50 | 51 | data[idx >> 3] |= (1 << (idx & 7)); 52 | } 53 | 54 | bool Bitstring::IsSet(UInt32 idx) 55 | { 56 | ASSERT_STR(idx < (length << 3), "Bitstring::IsSet: out of range"); 57 | 58 | return (data[idx >> 3] & (1 << (idx & 7))) ? true : false; 59 | } 60 | 61 | bool Bitstring::IsClear(UInt32 idx) 62 | { 63 | ASSERT_STR(idx < (length << 3), "Bitstring::IsClear: out of range"); 64 | 65 | return (data[idx >> 3] & (1 << (idx & 7))) ? false : true; 66 | } 67 | -------------------------------------------------------------------------------- /common/common_license.txt: -------------------------------------------------------------------------------- 1 | This license applies to all of the files in src/common: 2 | 3 | Copyright (c) 2006-2011 Ian Patterson 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 18 | 2. Altered source versions must be plainly marked as such, and must not be 19 | misrepresented as being the original software. 20 | 21 | 3. This notice may not be removed or altered from any source 22 | distribution. -------------------------------------------------------------------------------- /nvse/Algohol/algMath.h: -------------------------------------------------------------------------------- 1 | #include "algTypes.h" 2 | 3 | 4 | void V3Normalize( Vector3 &v ); 5 | Vector3 V3Crossproduct( Vector3 va, Vector3 vb ); 6 | 7 | Quat fromEuler( Euler e, int flag ); 8 | Quat fromAxisAngle( Vector3 axis, float angle ); 9 | Quat nlerp( Quat q1, Quat q2, float t ); 10 | Quat slerp( Quat q1, Quat q2, float t ); 11 | 12 | Euler fromQuat( Quat q, int flag ); -------------------------------------------------------------------------------- /nvse/Algohol/algTypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Quat 4 | { 5 | public: 6 | Quat() { } 7 | Quat( const Quat & in ) { w = in.w; x = in.x; y = in.y; z = in.z; } 8 | Quat( float inW, float inX, float inY, float inZ ) { w = inW; x = inX; y = inY; z = inZ; } 9 | ~Quat() { } 10 | 11 | Quat & operator*=( float s ) { w *= s; x *= s; y *= s; z *= s; return *this; } 12 | Quat & operator+=( const Quat & q ) { w += q.w; x += q.x; y += q.y; z += q.z; return *this; } 13 | Quat & operator-=( const Quat & q ) { w -= q.w; x -= q.x; y -= q.y; z -= q.z; return *this; } 14 | Quat & operator*=( Quat & q ) 15 | { 16 | float tw = w * q.w - x * q.x - y * q.y - z * q.z; 17 | float tx = w * q.x + x * q.w - y * q.z + z * q.y; 18 | float ty = w * q.y + x * q.z + y * q.w - z * q.x; 19 | float tz = w * q.z - x * q.y + y * q.x + z * q.w; 20 | w = tw; 21 | x = tx; 22 | y = ty; 23 | z = tz; 24 | return *this; 25 | } 26 | Vector3 operator*( Vector3 & v ) 27 | { 28 | float t2 = w * x; 29 | float t3 = w * y; 30 | float t4 = w * z; 31 | float t5 = -x * x; 32 | float t6 = x * y; 33 | float t7 = x * z; 34 | float t8 = -y * y; 35 | float t9 = y * z; 36 | float t10 = -z * z; 37 | Vector3 out; 38 | out.x = 2 * ( ( t8 + t10 ) * v.x + ( t6 + t4 ) * v.y + ( t7 - t3 ) * v.z ) + v.x; 39 | out.y = 2 * ( ( t6 - t4 ) * v.x + ( t5 + t10 ) * v.y + ( t9 + t2 ) * v.z ) + v.y; 40 | out.z = 2 * ( ( t7 + t3 ) * v.x + ( t9 - t2 ) * v.y + ( t5 + t8 ) * v.z ) + v.z; 41 | return out; 42 | } 43 | 44 | Quat operator*( float s ) const { Quat out( *this ); return out *= s; } 45 | Quat operator+( const Quat & q ) const { Quat out( *this ); return out += q; } 46 | Quat operator-( const Quat & q ) const { Quat out( *this ); return out -= q; } 47 | Quat operator*( Quat & q ) const { Quat out( *this ); return out *= q; } 48 | 49 | void normalize( void ); 50 | 51 | union 52 | { 53 | struct 54 | { 55 | float w, x, y, z; 56 | }; 57 | }; 58 | }; 59 | 60 | class Euler 61 | { 62 | public: 63 | Euler() { } 64 | Euler( const Euler & in ) 65 | { 66 | elevation = in.elevation; 67 | bank = in.bank; 68 | heading = in.heading; 69 | } 70 | Euler( float inElevation, float inBank, float inHeading ) 71 | { 72 | elevation = inElevation; 73 | bank = inBank; 74 | heading = inHeading; 75 | } 76 | ~Euler() { } 77 | 78 | union 79 | { 80 | struct 81 | { 82 | float elevation, bank, heading; 83 | }; 84 | }; 85 | }; -------------------------------------------------------------------------------- /nvse/Algohol/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007 by entim. 2 | MIT License 3 | 4 | Permission is hereby granted, free of charge, to any person 5 | obtaining a copy of this software and associated documentation 6 | files (the "Software"), to deal in the Software without 7 | restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the 10 | Software is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /nvse/Algohol/paramTypes.h: -------------------------------------------------------------------------------- 1 | #include "CommandTable.h" 2 | 3 | extern ParamInfo kParams_Vector3Floats[3]; 4 | extern ParamInfo kParams_Vector3Strings3Floats[6]; 5 | extern ParamInfo kParams_QuatEuler4Strings3Floats1Int[8]; 6 | extern ParamInfo kParams_EulerQuat3Strings4Floats1Int[8]; 7 | extern ParamInfo kParams_QuatAxisAngle4Strings4Floats[8]; 8 | extern ParamInfo kParams_Quat4Strings4Floats[8]; 9 | extern ParamInfo kParams_Vector3Strings6Floats[9]; 10 | extern ParamInfo kParams_VectorQuatVector3Strings7Floats[10]; 11 | extern ParamInfo kParams_Quat4Strings8Floats[12]; 12 | extern ParamInfo kParams_Quat4Strings9Floats1Int[14]; -------------------------------------------------------------------------------- /nvse/loader_common/Error.cpp: -------------------------------------------------------------------------------- 1 | #include "Error.h" 2 | 3 | void PrintLoaderError(const char * fmt, ...) 4 | { 5 | va_list args; 6 | 7 | va_start(args, fmt); 8 | 9 | gLog.Log(IDebugLog::kLevel_FatalError, fmt, args); 10 | 11 | char buf[4096]; 12 | vsprintf_s(buf, sizeof(buf), fmt, args); 13 | 14 | MessageBox(NULL, buf, "NVSE Loader", MB_OK | MB_ICONEXCLAMATION); 15 | 16 | va_end(args); 17 | } 18 | -------------------------------------------------------------------------------- /nvse/loader_common/Error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void PrintLoaderError(const char * fmt, ...); 4 | -------------------------------------------------------------------------------- /nvse/loader_common/IdentifyEXE.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | enum 5 | { 6 | kProcType_Steam, 7 | kProcType_Normal, 8 | 9 | kProcType_Packed, 10 | 11 | kProcType_Unknown 12 | }; 13 | 14 | struct ProcHookInfo 15 | { 16 | UInt64 version; 17 | UInt32 procType; 18 | UInt32 hookCallAddr; 19 | UInt32 loadLibAddr; 20 | bool noGore; 21 | }; 22 | 23 | bool IdentifyEXE(const char * procName, bool isEditor, std::string * dllSuffix, ProcHookInfo * hookInfo); 24 | -------------------------------------------------------------------------------- /nvse/loader_common/PluginChecker.cpp: -------------------------------------------------------------------------------- 1 | #include "PluginChecker.h" 2 | #include "imagehlp.h" 3 | 4 | #pragma comment(lib, "imagehlp.lib") 5 | 6 | constexpr UInt32 exportThreshold = 50; 7 | 8 | const PIMAGE_EXPORT_DIRECTORY GetExportDirectory(PLOADED_IMAGE image) { 9 | DWORD size = 0; 10 | return static_cast(ImageDirectoryEntryToData(image->MappedAddress, false, IMAGE_DIRECTORY_ENTRY_EXPORT, &size)); 11 | } 12 | 13 | bool PluginHasExport(const char* fileName, const char* folderPath, const char* functionName) { 14 | bool validPlugin = false; 15 | 16 | LOADED_IMAGE image; 17 | if (!MapAndLoad(fileName, folderPath, &image, true, true)) { 18 | _DMESSAGE("Failed to load \"%s\"", fileName); 19 | return validPlugin; 20 | } 21 | 22 | const PIMAGE_EXPORT_DIRECTORY exportDir = GetExportDirectory(&image); 23 | if (!exportDir) { 24 | _DMESSAGE("Failed to get export directory for \"%s\"", fileName); 25 | goto UNLOAD; 26 | } 27 | 28 | if (exportDir->NumberOfNames == 0) { 29 | _DMESSAGE("No exports found for \"%s\"", image.ModuleName); 30 | goto UNLOAD; 31 | } 32 | 33 | if (exportDir->NumberOfNames > exportThreshold) { 34 | _DMESSAGE("Module \"%s\" over %i exports - are we sure it's an NVSE plugin? Skipping...", fileName, exportThreshold); 35 | goto UNLOAD; 36 | } 37 | 38 | { 39 | const DWORD* dNameRVAs = static_cast(ImageRvaToVa(image.FileHeader, image.MappedAddress, exportDir->AddressOfNames, nullptr)); 40 | for (size_t i = 0; i < exportDir->NumberOfNames; i++) { 41 | const char* funcName = static_cast(ImageRvaToVa(image.FileHeader, image.MappedAddress, dNameRVAs[i], nullptr)); 42 | if (strcmp(funcName, functionName) == 0) { 43 | validPlugin = true; 44 | break; 45 | } 46 | } 47 | } 48 | 49 | UNLOAD: 50 | UnMapAndLoad(&image); 51 | 52 | return validPlugin; 53 | } 54 | 55 | bool IsNVSEPlugin(const char* fileName, const char* folderPath) { 56 | return PluginHasExport(fileName, folderPath, "NVSEPlugin_Query"); 57 | } 58 | 59 | bool IsNVSEPreloadPlugin(const char* fileName, const char* folderPath) { 60 | return PluginHasExport(fileName, folderPath, "NVSEPlugin_Preload"); 61 | } 62 | -------------------------------------------------------------------------------- /nvse/loader_common/PluginChecker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool PluginHasExport(const char* fileName, const char* folderPath, const char* functionName); 4 | 5 | bool IsNVSEPlugin(const char* fileName, const char* folderPath); 6 | 7 | bool IsNVSEPreloadPlugin(const char* fileName, const char* folderPath); -------------------------------------------------------------------------------- /nvse/nvse/CachedScripts.cpp: -------------------------------------------------------------------------------- 1 | #include "CachedScripts.h" 2 | #include 3 | #include 4 | #include "GameScript.h" 5 | #include "GameAPI.h" 6 | 7 | #if NVSE_CORE && RUNTIME 8 | UnorderedMap cachedFileUDFs; 9 | ICriticalSection g_cachedUdfCS; 10 | 11 | Script* CompileAndCacheScript(std::filesystem::path fullPath, bool useLocks, const char* relPath = nullptr) 12 | { 13 | if (!fullPath.has_extension()) 14 | return nullptr; 15 | 16 | std::ifstream ifs(fullPath); 17 | if (!ifs) 18 | return nullptr; 19 | 20 | std::ostringstream ss; 21 | ss << ifs.rdbuf(); 22 | 23 | std::string udfName; 24 | { 25 | if (useLocks) 26 | g_cachedUdfCS.Enter(); 27 | 28 | udfName = "nvseRuntimeScript" 29 | + std::to_string(cachedFileUDFs.Size()) // lock due to accessing this global 30 | + fullPath.stem().string(); 31 | 32 | if (useLocks) 33 | g_cachedUdfCS.Leave(); 34 | } 35 | 36 | auto* script = CompileScriptEx(ss.str().c_str(), udfName.c_str(), true); 37 | if (!script) 38 | return nullptr; 39 | 40 | script->SetEditorID_AtRuntime(udfName.c_str()); 41 | 42 | // Cache result 43 | { 44 | if (useLocks) 45 | g_cachedUdfCS.Enter(); 46 | 47 | if (relPath) 48 | { 49 | cachedFileUDFs[const_cast(relPath)] = script; 50 | } 51 | else 52 | { 53 | std::string filePath = fullPath.string(); 54 | filePath.erase(0, ScriptFilesPath.size()); // turn it into a relative path. 55 | cachedFileUDFs[const_cast(filePath.c_str())] = script; 56 | } 57 | 58 | if (useLocks) 59 | g_cachedUdfCS.Leave(); 60 | } 61 | return script; 62 | } 63 | 64 | Script* CompileAndCacheScript(const char* relPath) 65 | { 66 | // Pretend this is only for UDFs, since for 99% of use cases that's all this will be used for. 67 | std::filesystem::path fullPath = std::string(ScriptFilesPath) + relPath; 68 | if (!std::filesystem::exists(fullPath)) 69 | return nullptr; 70 | 71 | return CompileAndCacheScript(fullPath, true, relPath); 72 | } 73 | 74 | void CacheAllScriptsInPath(std::string_view pathStr) 75 | { 76 | std::filesystem::path path = pathStr; 77 | if (std::filesystem::exists(path) && std::filesystem::is_directory(path)) 78 | { 79 | for (auto const& dir_entry : std::filesystem::recursive_directory_iterator(path)) 80 | { 81 | if (dir_entry.is_regular_file() && (dir_entry.path().has_extension())) //will make it so that it will not compile script file that doesn't have file extension 82 | { 83 | if (!CompileAndCacheScript(dir_entry.path(), false)) 84 | { 85 | std::string errMsg = std::format("xNVSE: Failed to precompile script file at {}", 86 | dir_entry.path().string()); 87 | Console_Print(errMsg.c_str()); 88 | _ERROR(errMsg.c_str()); 89 | } 90 | else 91 | { 92 | std::string compileSuccessMsg = std::format("xNVSE: script file successfully precompiled at {}", 93 | dir_entry.path().string()); 94 | _MESSAGE(compileSuccessMsg.c_str()); 95 | } 96 | } 97 | } 98 | } 99 | } 100 | #endif 101 | -------------------------------------------------------------------------------- /nvse/nvse/CachedScripts.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "common/ICriticalSection.h" 7 | 8 | class Script; 9 | 10 | #if NVSE_CORE && RUNTIME 11 | constexpr std::string_view ScriptFilesPath = "data/nvse/user_defined_functions/"; 12 | 13 | extern UnorderedMap cachedFileUDFs; 14 | extern ICriticalSection g_cachedUdfCS; 15 | Script* CompileAndCacheScript(const char* relPath); 16 | 17 | // Also checks in nested sub-folders in the path. 18 | void CacheAllScriptsInPath(std::string_view pathStr); 19 | #endif -------------------------------------------------------------------------------- /nvse/nvse/Commands_Console.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CommandTable.h" 4 | #include "ParamInfos.h" 5 | 6 | bool ModDebugState(Script * scriptObj); 7 | 8 | DEFINE_CMD_ALT(PrintToConsole, printc, Print formatted string to console, 0, 21, kParams_FormatString) 9 | DEFINE_CMD_ALT(DebugPrint, dbprintc, prints a formatted string to the console if debug mode is enabled for calling script, 0, 21, kParams_FormatString); 10 | DEFINE_CMD_ALT(SetDebugMode, dbmode, toggles debug mode for all scripts belonging to a mod, 0, 2, kParams_OneInt_OneOptionalInt); 11 | DEFINE_CMD_ALT(GetDebugMode, GetDbMode, returns whether debug mode is set for the mod, 0, 1, kParams_OneOptionalInt); 12 | DEFINE_CMD_ALT(SetConsoleEcho, , toggles wether the engine echoes to the console and return previous state, 0, 1, kParams_OneInt); 13 | DEFINE_CMD_ALT(GetConsoleEcho, , returns whether the engine echoes to the console, 0, 1, kParams_OneOptionalInt); 14 | 15 | DEFINE_CMD_ALT(HasConsoleOutputFilename, HasCOF, "return if there is a Console Output Filename active", 0, 0, NULL); 16 | DEFINE_CMD_ALT(GetConsoleOutputFilename, GetCOF, "returns the name of the Console Output Filename", 0, 0, NULL); 17 | -------------------------------------------------------------------------------- /nvse/nvse/Commands_Factions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CommandTable.h" 4 | #include "ParamInfos.h" 5 | #include "GameForms.h" 6 | #include "GameData.h" 7 | 8 | #ifdef RUNTIME 9 | 10 | extern bool Cmd_GetFactionRank_Eval(COMMAND_ARGS_EVAL); 11 | extern bool Cmd_GetFactionRank_Execute(COMMAND_ARGS); 12 | extern bool Cmd_ModFactionRank_Execute(COMMAND_ARGS); 13 | 14 | #endif 15 | 16 | DEFINE_CMD(GetBaseNumFactions, returns the number of factions to which an actor base form belongs, 0, kParams_OneOptionalActorBase); 17 | DEFINE_CMD(GetBaseNthFaction, returns the nth faction to which an actor base form belongs, 0, kParams_OneIntOneOptionalActorBase); 18 | DEFINE_CMD(GetBaseNthRank, returns the nth faction rank to which an actor base form belongs, 0, kParams_OneIntOneOptionalActorBase); 19 | 20 | DEFINE_CMD(GetNumRanks, returns the number of rank of a faction, 0, kParams_OneFaction); 21 | -------------------------------------------------------------------------------- /nvse/nvse/Commands_Game.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CommandTable.h" 4 | #include "ParamInfos.h" 5 | 6 | // windows sdk sucks 7 | #undef MessageBoxEx 8 | 9 | DEFINE_COMMAND(GetNumericGameSetting, returns the value of a numeric game setting, 0, 1, kParams_OneString); 10 | DEFINE_COMMAND(SetNumericGameSetting, sets a numeric game setting, 0, 2, kParams_OneString_OneFloat); 11 | DEFINE_COMMAND(GetNumericIniSetting, returns the value of an ini setting, 0, 1, kParams_OneString); 12 | DEFINE_COMMAND(SetNumericIniSetting, sets an ini setting, 0, 2, kParams_OneString_OneFloat); 13 | DEFINE_COMMAND(GetCrosshairRef, returns the reference under the crosshair, 0, 0, NULL); 14 | DEFINE_COMMAND(GetGameLoaded, returns 1 after a game is loaded, 0, 0, NULL); 15 | DEFINE_COMMAND(GetGameRestarted, returns 1 when the game is restarted, 0, 0, NULL); 16 | DEFINE_COMMAND(IsModLoaded, returns the whether the specified mod is loaded, 0, 1, kParams_OneString); 17 | DEFINE_COMMAND(GetModIndex, returns the index of the specified mod, 0, 1, kParams_OneString); 18 | DEFINE_COMMAND(GetNumLoadedMods, returns the number of loaded mods, 0, 0, NULL); 19 | DEFINE_COMMAND(GetSourceModIndex, returns the index of the mod associated with the form, 0, 1, kParams_OneOptionalForm); 20 | DEFINE_COMMAND(GetLocalRefIndex, returns the index of the ref, 0, 1, kParams_OneOptionalForm); 21 | DEFINE_COMMAND(BuildRef, builds a reference from a mod and ref index, 0, 2, kParams_TwoInts); 22 | DEFINE_COMMAND(GetDebugSelection, returns the current selected object in the console, 0, 0, NULL); 23 | DEFINE_COMMAND(MessageEx, prints a formatted message, 0, 21, kParams_FormatString); 24 | DEFINE_COMMAND(MessageBoxEx, displays a formatted message box, 0, 21, kParams_FormatString); 25 | 26 | DEFINE_COMMAND(GetGridsToLoad, returns the effective value of the uGridsToLoad ini setting, 0, 0, NULL); 27 | DEFINE_CMD_ALT(OutputLocalMapPicturesOverride, OLMPOR, "identical to the OutputLocalMapPictures console command, but overrides the uGridsToLoad ini setting", 0, 0, NULL); 28 | DEFINE_CMD_ALT(SetOutputLocalMapPicturesGrids, SetOLMPGrids, sets the value with which to override uGridsToLoad when generating local maps with OLMPOR, 0, 1, kParams_OneInt); 29 | 30 | DEFINE_COMMAND(AddSpellNS, identical to AddSpell but without the UI message, 0, 1, kParams_OneSpellItem); 31 | 32 | DEFINE_CMD_ALIAS(DisablePlayerControlsAlt, DPCAlt, "Per-mod version with added args", false, kParams_SevenOptionalInts); 33 | DEFINE_CMD_ALIAS(EnablePlayerControlsAlt, EPCAlt, "Per-mod version with added args", false, kParams_SevenOptionalInts); 34 | DEFINE_CMD_ALIAS(GetPlayerControlsDisabledAlt, GPCDAlt, "", false, kParams_EightOptionalInts); 35 | 36 | // Ex versions simply extracts a bitfield instead of multiple args 37 | DEFINE_CMD_ALIAS(DisablePlayerControlsAltEx, DPCEx, "Per-mod version with added args", false, kParams_OneOptionalInt); 38 | DEFINE_CMD_ALIAS(EnablePlayerControlsAltEx, EPCEx, "Per-mod version with added args", false, kParams_OneOptionalInt); 39 | DEFINE_CMD_ALIAS(GetPlayerControlsDisabledAltEx, GPCDEx, "", false, kParams_TwoOptionalInts); 40 | -------------------------------------------------------------------------------- /nvse/nvse/Commands_Input.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CommandTable.h" 4 | #include "ParamInfos.h" 5 | 6 | #define DEFINE_INPUT(name, alias, desc) DEFINE_CMD_ALT(name, alias, desc, 0, 1, kParams_OneInt) 7 | 8 | DEFINE_CMD_COND(IsKeyPressed, return if a dx scancode is down or up, 0, kParams_OneInt_OneOptionalInt); 9 | DEFINE_INPUT(TapKey, tk, Fakes a key press for one frame); 10 | DEFINE_INPUT(HoldKey, hk, Fakes a key press indefinately); 11 | DEFINE_INPUT(ReleaseKey, rk, Releases a key held down by HoldKey); 12 | DEFINE_CMD_ALT(DisableKey, dk, Prevents a player from using a key, 0, 2, kParams_OneInt_OneOptionalInt); 13 | DEFINE_CMD_ALT(EnableKey, ek, Reenables a key previously disabled with DisableKey, 0, 2, kParams_OneInt_OneOptionalInt); 14 | DEFINE_CMD_ALT(GetNumKeysPressed, gnkp, Returns how many keyboard keys are currently being held down, 0, 0, 0); 15 | DEFINE_INPUT(GetKeyPress, gkp, Returns the scancode of the nth key which is currently being held down); 16 | DEFINE_CMD_ALT(GetNumMouseButtonsPressed, gnmbp, Returns how many mouse buttons are currently being held down, 0, 0, 0); 17 | DEFINE_INPUT(GetMouseButtonPress, gmbp, Returns the code of the nth mouse button which is currently being held down); 18 | 19 | DEFINE_COMMAND(GetControl, Returns the key assigned to a control, 0, 1, kParams_OneInt); 20 | DEFINE_COMMAND(GetAltControl, Returns the mouse button assigned to a control, 0, 1, kParams_OneInt); 21 | 22 | DEFINE_INPUT(MenuTapKey, mtk, Fakes a key press for one frame in menu mode); 23 | DEFINE_INPUT(MenuHoldKey, mhk, Fakes a key press indefinately in menu mode); 24 | DEFINE_INPUT(MenuReleaseKey, mrk, Releases a key held down by MenuHoldKey); 25 | DEFINE_CMD_ALT(DisableControl, dc, disables the key and button bound to a control, 0, 2, kParams_OneInt_OneOptionalInt); 26 | DEFINE_CMD_ALT(EnableControl, ec, enables the key and button assigned to a control, 0, 2, kParams_OneInt_OneOptionalInt); 27 | DEFINE_INPUT(TapControl, tc, taps the key or mouse button assigned to control); 28 | DEFINE_COMMAND(SetControl, assigns a new keycode to the specified keyboard control, 0, 2, kParams_TwoInts); 29 | DEFINE_COMMAND(SetAltControl, assigns a new mouse button code to the specified mouse control, 0, 2, kParams_TwoInts); 30 | DEFINE_COMMAND(SetIsControl, sets a key as a custom control, 0, 2, kParams_TwoInts); 31 | DEFINE_COMMAND(IsControl, returns 1 if key is a game control or 2 if a custom control, 0, 1, kParams_OneInt); 32 | DEFINE_COMMAND(IsKeyDisabled, returns 1 if the key has been disabled by a script, 0, 1, kParams_OneInt); 33 | DEFINE_COMMAND(IsControlDisabled, returns 1 if the control has been disabled by a script, 0, 1, kParams_OneInt); 34 | DEFINE_CMD_COND(IsControlPressed, returns 1 if the control is pressed, 0, kParams_OneInt_OneOptionalInt); 35 | 36 | #undef DEFINE_INPUT 37 | 38 | #if RUNTIME 39 | 40 | void Commands_Input_Init(void); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /nvse/nvse/Commands_InventoryRef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CommandTable.h" 4 | #include "ParamInfos.h" 5 | 6 | static ParamInfo kParams_OneOptionalContainerRef[1] = 7 | { 8 | { "containerRef", kParamType_Container, 1 }, 9 | }; 10 | 11 | static ParamInfo kParams_OneContainerRef[1] = 12 | { 13 | { "containerRef", kParamType_Container, 1 }, 14 | }; 15 | 16 | DEFINE_COMMAND(RemoveMeIR, "removes an inventory reference from its container, optionally transferring it to a different container, in much the same way as the vanilla RemoveMe command. The inventory reference becomes invalid once this command is called and should no longer be used.", 17 | 1, 1, kParams_OneOptionalContainerRef); 18 | DEFINE_COMMAND(CopyIR, "copies an inventory reference to the specified container. The calling object needn't be in a container and remains valid after the command is called. If the calling object is equipped, the copy will not be equipped.", 19 | 1, 1, kParams_OneContainerRef); 20 | DEFINE_COMMAND(CopyIRAlt, "copies an inventory reference to the specified container. The calling object needn't be in a container and remains valid after the command is called. If the calling object is equipped, the copy will not be equipped.", 21 | 1, 1, kParams_OneContainerRef); 22 | DEFINE_COMMAND(CreateTempRef, "creates a temporary reference to the specified form. This reference does not exist in the gameworld or in a container, and remains valid for only one frame. It is mostly useful for creating a stack of one or more items to be added to a container with CopyIR", 23 | 0, 1, kParams_OneObjectID); 24 | DEFINE_COMMAND(GetFirstRefForItem, returns the first entry in an array of temp refs to objects of the specified type in the calling container, 25 | 1, 1, kParams_OneObjectID); 26 | DEFINE_COMMAND(GetNextRefForItem, returns the next entry in the array of temp refs to objects of the specified type in the calling container, 27 | 1, 1, kParams_OneObjectID); 28 | 29 | DEFINE_COMMAND(GetInvRefsForItem, returns an array of temp refs to objects of the specified type in the calling container, 30 | 1, 1, kParams_OneObjectID); 31 | 32 | DEFINE_COMMAND(IsInventoryRef, "", true, 0, nullptr); -------------------------------------------------------------------------------- /nvse/nvse/Commands_List.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CommandTable.h" 4 | #include "ParamInfos.h" 5 | 6 | DEFINE_CMD_ALT(ListGetCount, , "returns the count of items in the form list", 0, 1, kParams_FormList); 7 | 8 | DEFINE_CMD_ALT(ListGetNthForm, , returns the nth form in the form list, 0, 2, kParams_FormListInteger); 9 | 10 | static ParamInfo kParams_FormListForm[2] = 11 | { 12 | { "form list", kParamType_FormList, 0 }, 13 | { "form", kParamType_AnyForm, 0 }, 14 | }; 15 | 16 | DEFINE_CMD_ALT_COND(ListGetFormIndex, , returns the index for the specified form, 0, kParams_FormListForm); 17 | DEFINE_CMD_ALT_COND(IsRefInList, , returns the index for the specified form or base Form or permanent base Form, 0, kParams_FormListForm); 18 | 19 | static ParamInfo kParams_AddToFormList[4] = 20 | { 21 | { "form list", kParamType_FormList, 0 }, 22 | { "form", kParamType_AnyForm, 0 }, 23 | { "index", kParamType_Integer, 1 }, 24 | { "bCheckForDuplicates", kParamType_Integer, 1 } 25 | }; 26 | 27 | DEFINE_CMD_ALT(ListAddForm, , adds the form to the list at the given index (or at the end if not provided), false, 4, kParams_AddToFormList); 28 | 29 | static ParamInfo kParams_FormList_OptionalInt[2] = 30 | { 31 | { "form list", kParamType_FormList, 0 }, 32 | { "index", kParamType_Integer, 1 } 33 | }; 34 | static ParamInfo kParams_FormList_TwoOptionalInts[3] = 35 | { 36 | { "form list", kParamType_FormList, 0 }, 37 | { "index", kParamType_Integer, 1 }, 38 | { "bCheckForDuplicates", kParamType_Integer, 1 } 39 | }; 40 | DEFINE_CMD_ALT(ListAddReference, ListAddRef, adds the calling reference at the given index (or at the end if not provided), true, 3, kParams_FormList_TwoOptionalInts); 41 | 42 | DEFINE_CMD_ALT(ListRemoveNthForm, ListRemoveNth, removes the nth form from the list, 0, 2, kParams_FormList_OptionalInt); 43 | DEFINE_CMD_ALT(ListRemoveForm, , removes the specified from from the list., 0, 2, kParams_FormListForm); 44 | 45 | static ParamInfo kParams_ReplaceNthForm[3] = 46 | { 47 | { "form list", kParamType_FormList, 0 }, 48 | { "replaceWith", kParamType_AnyForm, 0 }, 49 | { "formIndex", kParamType_Integer, 1 } 50 | }; 51 | 52 | static ParamInfo kParams_ReplaceForm[3] = 53 | { 54 | { "form list", kParamType_FormList, 0 }, 55 | { "replaceWith", kParamType_AnyForm, 0 }, 56 | { "form", kParamType_AnyForm, 0 }, 57 | }; 58 | 59 | DEFINE_CMD_ALT(ListReplaceNthForm, ListReplaceNth, replaces the nth form of the list with the specified form, 0, 3, kParams_ReplaceNthForm); 60 | DEFINE_CMD_ALT(ListReplaceForm, , replaces the specified from with another., 0, 3, kParams_ReplaceForm); 61 | 62 | DEFINE_CMD_ALT(ListClear, , removes all entries from the list, 0, 1, kParams_FormList); 63 | 64 | static ParamInfo kParams_OneFormList_OneFunction[2] = 65 | { 66 | { "form list", kParamType_FormList, 0 }, 67 | { "condition user defined function", kParamType_AnyForm, 0 }, 68 | }; 69 | 70 | DEFINE_COMMAND(ForEachInList, "invokes a UDF that is called on each form in a formlist.", false, 2, kParams_OneFormList_OneFunction); -------------------------------------------------------------------------------- /nvse/nvse/Commands_NetImmerse.cpp: -------------------------------------------------------------------------------- 1 | #include "Commands_NetImmerse.h" 2 | 3 | -------------------------------------------------------------------------------- /nvse/nvse/Commands_NetImmerse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | -------------------------------------------------------------------------------- /nvse/nvse/Commands_Packages.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CommandTable.h" 4 | #include "ParamInfos.h" 5 | 6 | extern bool Cmd_GetDialogueTarget_Eval(COMMAND_ARGS_EVAL); 7 | extern bool Cmd_GetDialogueTarget_Execute(COMMAND_ARGS); 8 | extern bool Cmd_GetDialogueSubject_Eval(COMMAND_ARGS_EVAL); 9 | extern bool Cmd_GetDialogueSubject_Execute(COMMAND_ARGS); 10 | 11 | DEFINE_CMD_ALT_COND(GetDialogueTarget, GDT, get the NPC talked to, 1, kParams_OneOptionalActorRef); 12 | DEFINE_CMD_ALT_COND(GetDialogueSubject, GDS, get the NPC who started the conversation, 1, kParams_OneOptionalActorRef); 13 | DEFINE_CMD_ALT_COND(GetDialogueSpeaker, GDK, get the NPC who is currently speaking in the conversation, 1, kParams_OneOptionalActorRef); 14 | 15 | DEFINE_COMMAND(GetCurrentPackage, gets the current package from an actor, 0, 1, kParams_OneOptionalObjectRef); 16 | DEFINE_COMMAND(SetPackageLocationReference, sets package start location as a reference, 0, 2, kParams_OneForm_OneOptionalObjectRef); 17 | DEFINE_CMD_ALT(GetPackageLocation, GetPackageLocationReference, gets package start location, 0, 1, kParams_OneForm); 18 | DEFINE_COMMAND(SetPackageLocationRadius, sets package start location radius, 0, 2, kParams_OneForm_OneFloat); 19 | DEFINE_COMMAND(GetPackageLocationRadius, gets package start location radius, 0, 1, kParams_OneForm); 20 | DEFINE_COMMAND(SetPackageTargetReference, sets package target as a reference, 0, 2, kParams_OneForm_OneOptionalObjectRef); 21 | DEFINE_CMD_ALT(SetPackageTargetCount, SetPackageTargetDistance, sets package target count or distance, 0, 2, kParams_OneForm_OneInt); 22 | DEFINE_CMD_ALT(GetPackageTargetCount, GetPackageTargetDistance, gets package target count or distance, 0, 1, kParams_OneForm); 23 | 24 | // NPC_ baseForm package list access and manipulation 25 | 26 | DEFINE_CMD_COND(GetPackageCount, gets the count of packages from an actor base form, 0, kParams_OneOptionalObjectRef); 27 | DEFINE_COMMAND(GetNthPackage, gets the Nth package from an actor base form, 0, 2, kParams_OneIndexOneOptionalObjectRef); 28 | DEFINE_COMMAND(SetNthPackage, sets and returns the Nth package to an actor base form, 0, 3, kParams_OnePackageOneIndexOneOptionalObjectRef); 29 | DEFINE_COMMAND(AddPackageAt, adds the Nth package to an actor base form : 0 at top -1 at end returns index, 0, 3, kParams_OnePackageOneIndexOneOptionalObjectRef); 30 | DEFINE_COMMAND(RemovePackageAt, removes and returns the Nth package from an actor base form, 0, 2, kParams_OneIndexOneOptionalObjectRef); 31 | DEFINE_COMMAND(RemoveAllPackages, removes all packages from an actor base form returns count removed, 0, 1, kParams_OneOptionalObjectRef); 32 | -------------------------------------------------------------------------------- /nvse/nvse/Commands_Quest.cpp: -------------------------------------------------------------------------------- 1 | #include "Commands_Quest.h" 2 | 3 | #if RUNTIME 4 | #include "GameForms.h" 5 | #include "GameObjects.h" 6 | #include "GameAPI.h" 7 | 8 | bool Cmd_GetQuestObjectiveCount_Execute(COMMAND_ARGS) 9 | { 10 | *result = 0; 11 | 12 | TESQuest* pQuest = NULL; 13 | if (ExtractArgs(EXTRACT_ARGS, &pQuest)) { 14 | UInt32 count = pQuest->lVarOrObjectives.Count(); 15 | *result = count; 16 | if (IsConsoleMode()) 17 | Console_Print("%s has %d objectives", GetFullName(pQuest), count); 18 | } 19 | 20 | return true; 21 | } 22 | 23 | bool Cmd_GetNthQuestObjective_Execute(COMMAND_ARGS) 24 | { 25 | *result = 0; 26 | 27 | TESQuest* pQuest = NULL; 28 | UInt32 nIndex = 0; 29 | if (ExtractArgs(EXTRACT_ARGS, &pQuest, &nIndex)) { 30 | if (!pQuest) return true; 31 | BGSQuestObjective* obj = reinterpret_cast(pQuest->lVarOrObjectives.GetNthItem(nIndex)); 32 | if (obj) { 33 | *result = obj->objectiveId; 34 | } 35 | } 36 | return true; 37 | } 38 | 39 | bool Cmd_GetCurrentObjective_Execute(COMMAND_ARGS) 40 | { 41 | 42 | PlayerCharacter* pPC = PlayerCharacter::GetSingleton(); 43 | tList list = pPC->questObjectiveList; 44 | BGSQuestObjective* pCurObjective = (BGSQuestObjective*)list.GetFirstItem(); 45 | if (pCurObjective) { 46 | *result = pCurObjective->objectiveId; 47 | } 48 | 49 | return true; 50 | } 51 | 52 | bool Cmd_SetCurrentQuest_Execute(COMMAND_ARGS) 53 | { 54 | *result = 0; 55 | 56 | TESQuest* pQuest = NULL; 57 | if (ExtractArgs(EXTRACT_ARGS, &pQuest)) { 58 | PlayerCharacter* pPC = PlayerCharacter::GetSingleton(); 59 | pPC->quest = pQuest; 60 | } 61 | return true; 62 | } 63 | #endif -------------------------------------------------------------------------------- /nvse/nvse/Commands_Quest.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CommandTable.h" 4 | #include "ParamInfos.h" 5 | 6 | static ParamInfo kParams_QuestInteger[2] = 7 | { 8 | { "quest", kParamType_Quest, 0 }, 9 | { "index", kParamType_Integer, 0 } 10 | }; 11 | 12 | 13 | DEFINE_CMD_ALT(GetQuestObjectiveCount, GetObjectiveCount, returns the number of objectives for the specified quest, 0, 1, kParams_OneQuest); 14 | DEFINE_CMD_ALT(GetNthQuestObjective, GetNthObjective, returns the objectiveID of the Nth objective of the quest, 0, 2, kParams_QuestInteger); 15 | DEFINE_CMD_ALT(GetCurrentObjective, GetCurObjID, returns the objectiveID of the current objective, 0, 0, NULL); 16 | DEFINE_CMD_ALT(SetCurrentQuest, , sets the current quest to the specified quest, 0, 1, kParams_OneQuest); 17 | -------------------------------------------------------------------------------- /nvse/nvse/Commands_UI.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CommandTable.h" 4 | #include "ParamInfos.h" 5 | 6 | static ParamInfo kParams_SetUIStringEx[] = 7 | { 8 | { "component name", kParamType_String, 0 }, 9 | FORMAT_STRING_PARAMS, 10 | }; 11 | 12 | DEFINE_COMMAND(GetUIFloat, returns the value of a float UI trait, 0, 1, kParams_OneString); 13 | DEFINE_COMMAND(SetUIFloat, sets the value of a float UI trait, 0, 2, kParams_OneString_OneFloat); 14 | DEFINE_COMMAND(SetUIString, sets the value of a string UI trait, 0, 2, kParams_TwoStrings); 15 | DEFINE_COMMAND(SetUIStringEx, sets the value of a string UI trait to a formatted string, 0, 22, kParams_SetUIStringEx); 16 | DEFINE_COMMAND(SortUIListBox, sorts the items in a UI list_box, 0, 2, kParams_TwoStrings); 17 | 18 | DEFINE_COMMAND(GetUIFloatAlt, , 0, 1, kParams_OneString); 19 | DEFINE_COMMAND(SetUIFloatAlt, , 0, 2, kParams_OneString_OneFloat); 20 | DEFINE_COMMAND(SetUIStringAlt, , 0, 22, kParams_SetUIStringEx); 21 | DEFINE_COMMAND(ModUIFloat, , 0, 2, kParams_OneString_OneFloat); 22 | 23 | DEFINE_COMMAND(PrintActiveTile, prints name of highlighted UI component for debug purposes, 0, 0, NULL); 24 | 25 | // VATS camera 26 | DEFINE_COMMAND(EndVATScam, "Remove all targets and close VATS mode", false, 0, NULL) 27 | 28 | // Show LevelUp menu 29 | DEFINE_COMMAND(ShowLevelUpMenu, shows the LevelUp menu, 0, 0, NULL); 30 | -------------------------------------------------------------------------------- /nvse/nvse/Core_Serialization.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern UInt8 s_preloadModRefIDs[0xFF]; 4 | extern UInt8 s_numPreloadMods; 5 | extern std::vector g_modsLoaded; 6 | 7 | UInt8 ResolveModIndexForPreload(UInt8 modIndexIn); 8 | void Init_CoreSerialization_Callbacks(); 9 | 10 | -------------------------------------------------------------------------------- /nvse/nvse/FastStack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "SmallObjectsAllocator.h" 3 | 4 | template class FastStack 5 | { 6 | using Data_Arg = std::conditional_t, T_Data, T_Data&>; 7 | 8 | struct Node 9 | { 10 | Node* next; 11 | T_Data data; 12 | 13 | void Clear() { data.~T_Data(); } 14 | }; 15 | 16 | Node* head; 17 | size_t numItems; 18 | using Allocator = SmallObjectsAllocator::FastAllocator; 19 | static thread_local Allocator s_allocator; 20 | public: 21 | 22 | FastStack() : head(NULL), numItems(0) {} 23 | ~FastStack() { Reset(); } 24 | 25 | bool Empty() const { return !numItems; } 26 | 27 | size_t Size() const { return numItems; } 28 | 29 | T_Data& Top() 30 | { 31 | return head->data; 32 | } 33 | 34 | T_Data* Push(Data_Arg item) 35 | { 36 | Node* newNode = s_allocator.Allocate(); 37 | T_Data* data = &newNode->data; 38 | RawAssign(*data, item); 39 | newNode->next = head; 40 | head = newNode; 41 | numItems++; 42 | return data; 43 | } 44 | 45 | template 46 | T_Data* Push(Args && ...args) 47 | { 48 | Node* newNode = s_allocator.Allocate(); 49 | T_Data* data = &newNode->data; 50 | new (data) T_Data(std::forward(args)...); 51 | newNode->next = head; 52 | head = newNode; 53 | numItems++; 54 | return data; 55 | } 56 | 57 | T_Data* Pop() 58 | { 59 | #if _DEBUG 60 | if (!head || !numItems) DebugBreak(); 61 | #else 62 | if (!head) return NULL; 63 | #endif 64 | T_Data* frontItem = &head->data; 65 | Node* toRemove = head; 66 | head = head->next; 67 | toRemove->Clear(); 68 | s_allocator.Free(toRemove); 69 | numItems--; 70 | return frontItem; 71 | } 72 | 73 | void Reset() 74 | { 75 | if (!head) return; 76 | do 77 | { 78 | Node* pNode = head; 79 | head = head->next; 80 | pNode->Clear(); 81 | s_allocator.Free(pNode); 82 | } while (head); 83 | numItems = 0; 84 | } 85 | }; 86 | 87 | template 88 | thread_local typename FastStack::Allocator FastStack::s_allocator; -------------------------------------------------------------------------------- /nvse/nvse/FormExtraData.cpp: -------------------------------------------------------------------------------- 1 | #include "FormExtraData.h" 2 | #include 3 | #include 4 | #include "SafeWrite.h" 5 | 6 | namespace 7 | { 8 | std::unordered_map>> g_formExtraDataMap; 9 | std::shared_mutex g_formExtraDataCS; 10 | UInt32 g_removeFromAllFormMapsAddr = 0x483C70; 11 | } 12 | 13 | void FormExtraData::Add(TESForm* form, const char* name, FormExtraData* formExtraData) 14 | { 15 | std::unique_lock lock(g_formExtraDataCS); 16 | g_formExtraDataMap[form].emplace_back(std::make_pair(name, formExtraData)); 17 | } 18 | 19 | void FormExtraData::Remove(TESForm* form, const char* name) 20 | { 21 | std::unique_lock lock(g_formExtraDataCS); 22 | auto& datum = g_formExtraDataMap[form]; 23 | auto iter = std::ranges::find_if(datum, [&](auto& iter) 24 | { 25 | return iter.first == name; 26 | }); 27 | if (iter != datum.end()) 28 | { 29 | auto* data = iter->second; 30 | data->~FormExtraData(); 31 | FormHeap_Free(data); 32 | datum.erase(iter); 33 | } 34 | } 35 | 36 | FormExtraData* FormExtraData::Get(TESForm* form, const char* name) 37 | { 38 | std::shared_lock lock(g_formExtraDataCS); 39 | auto iter = g_formExtraDataMap.find(form); 40 | if (iter != g_formExtraDataMap.end()) 41 | { 42 | auto it = std::ranges::find_if(iter->second, [&](auto& item) 43 | { 44 | return item.first == name; 45 | }); 46 | return it->second; 47 | } 48 | return nullptr; 49 | } 50 | 51 | bool __fastcall RemoveFromAllFormsMapHook(TESForm* form) 52 | { 53 | std::unique_lock lock(g_formExtraDataCS); 54 | auto iter = g_formExtraDataMap.find(form); 55 | if (iter != g_formExtraDataMap.end()) 56 | { 57 | for (auto& pair : iter->second) 58 | { 59 | auto* data = pair.second; 60 | data->~FormExtraData(); 61 | FormHeap_Free(data); 62 | } 63 | g_formExtraDataMap.erase(iter); 64 | } 65 | return ThisStdCall(g_removeFromAllFormMapsAddr, form); 66 | } 67 | 68 | void FormExtraData::WriteHooks() 69 | { 70 | WriteRelCall(0x483669, &RemoveFromAllFormsMapHook, &g_removeFromAllFormMapsAddr); 71 | } -------------------------------------------------------------------------------- /nvse/nvse/FormExtraData.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class FormExtraData 4 | { 5 | public: 6 | virtual ~FormExtraData() {}; 7 | static void Add(TESForm* form, const char* name, FormExtraData* formExtraData); 8 | static void Remove(TESForm* form, const char* name); 9 | static FormExtraData* Get(TESForm* form, const char* name); 10 | static void WriteHooks(); 11 | }; 12 | -------------------------------------------------------------------------------- /nvse/nvse/GameBSExtraData.cpp: -------------------------------------------------------------------------------- 1 | #include "GameBSExtraData.h" 2 | #include "GameAPI.h" 3 | #include "GameExtraData.h" 4 | 5 | #if RUNTIME 6 | static const UInt32 s_ExtraDataListVtbl = 0x010143E8; // 0x0100e3a8; 7 | #endif 8 | 9 | bool BaseExtraList::HasType(UInt32 type) const 10 | { 11 | return (m_presenceBitfield[type >> 3] & (1 << (type & 7))) != 0; 12 | } 13 | 14 | void BaseExtraList::MarkType(UInt32 type, bool bCleared) 15 | { 16 | UInt8 bitMask = 1 << (type & 7); 17 | UInt8 &flag = m_presenceBitfield[type >> 3]; 18 | if (bCleared) flag &= ~bitMask; 19 | else flag |= bitMask; 20 | } 21 | 22 | ExtraDataList* ExtraDataList::Create(BSExtraData* xBSData) 23 | { 24 | ExtraDataList* xData = (ExtraDataList*)FormHeap_Allocate(sizeof(ExtraDataList)); 25 | memset(xData, 0, sizeof(ExtraDataList)); 26 | ((UInt32*)xData)[0] = s_ExtraDataListVtbl; 27 | if (xBSData) 28 | xData->Add(xBSData); 29 | return xData; 30 | } 31 | 32 | bool BaseExtraList::IsWorn() 33 | { 34 | return HasType(kExtraData_Worn); 35 | } 36 | 37 | void BaseExtraList::DebugDump() const 38 | { 39 | _MESSAGE("BaseExtraList Dump:"); 40 | gLog.Indent(); 41 | 42 | if (m_data) 43 | { 44 | for(BSExtraData * traverse = m_data; traverse; traverse = traverse->next) { 45 | _MESSAGE("%s", GetObjectClassName(traverse)); 46 | //_MESSAGE("Extra types %4x (%s) %s", traverse->type, GetExtraDataName(traverse->type), GetExtraDataValue(traverse)); 47 | } 48 | } 49 | else 50 | _MESSAGE("No data in list"); 51 | 52 | gLog.Outdent(); 53 | } 54 | 55 | bool BaseExtraList::MarkScriptEvent(UInt32 eventMask, TESForm* eventTarget) 56 | { 57 | return MarkBaseExtraListScriptEvent(eventTarget, this, eventMask); 58 | } 59 | -------------------------------------------------------------------------------- /nvse/nvse/GameBSExtraData.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Added to remove a cyclic dependency between GameForms.h and GameExtraData.h 4 | #include "Utilities.h" 5 | 6 | class TESForm; 7 | 8 | // C+? 9 | class BSExtraData 10 | { 11 | public: 12 | BSExtraData(); 13 | virtual ~BSExtraData(); 14 | 15 | virtual bool Differs(BSExtraData* extra); // 001 16 | 17 | static BSExtraData* Create(UInt8 xType, UInt32 size, UInt32 vtbl); 18 | 19 | // void ** _vtbl; // 000 20 | UInt8 type; // 004 21 | UInt8 pad[3]; // 005 22 | BSExtraData * next; // 008 23 | }; 24 | 25 | // 020 26 | struct BaseExtraList 27 | { 28 | bool HasType(UInt32 type) const; 29 | 30 | __forceinline BSExtraData *GetByType(UInt8 type) const 31 | { 32 | return ThisStdCall(0x410220, this, type); 33 | } 34 | 35 | void MarkType(UInt32 type, bool bCleared); 36 | 37 | __forceinline void Remove(BSExtraData *toRemove, bool doFree) 38 | { 39 | ThisStdCall(0x410020, this, toRemove, doFree); 40 | } 41 | 42 | __forceinline void RemoveByType(UInt32 type) 43 | { 44 | ThisStdCall(0x410140, this, type); 45 | } 46 | 47 | __forceinline BSExtraData *Add(BSExtraData *toAdd) 48 | { 49 | return ThisStdCall(0x40FF60, this, toAdd); 50 | } 51 | 52 | __forceinline void RemoveAll(bool doFree) 53 | { 54 | ThisStdCall(0x40FAE0, this, doFree); 55 | } 56 | 57 | bool MarkScriptEvent(UInt32 eventMask, TESForm* eventTarget); 58 | 59 | __forceinline void Copy(BaseExtraList *from) 60 | { 61 | ThisStdCall(0x411EC0, this, from); 62 | } 63 | 64 | void DebugDump() const; 65 | 66 | bool IsWorn(); 67 | 68 | void ** m_vtbl; // 000 69 | BSExtraData * m_data; // 004 70 | UInt8 m_presenceBitfield[0x15]; // 008 - if a bit is set, then the extralist should contain that extradata 71 | // bits are numbered starting from the lsb 72 | UInt8 pad1D[3]; // 01D 73 | }; 74 | 75 | struct ExtraDataList : public BaseExtraList 76 | { 77 | static ExtraDataList * Create(BSExtraData* xBSData = NULL); 78 | }; 79 | 80 | STATIC_ASSERT(offsetof(BaseExtraList, m_presenceBitfield) == 0x008); 81 | STATIC_ASSERT(sizeof(ExtraDataList) == 0x020); 82 | 83 | -------------------------------------------------------------------------------- /nvse/nvse/GameData.cpp: -------------------------------------------------------------------------------- 1 | #include "GameData.h" 2 | 3 | #if RUNTIME 4 | DataHandler* DataHandler::Get() 5 | { 6 | DataHandler** g_dataHandler = (DataHandler**)0x011C3F2C; 7 | return *g_dataHandler; 8 | } 9 | #else 10 | 11 | DataHandler* DataHandler::Get() 12 | { 13 | DataHandler** g_dataHandler = (DataHandler**)0xED3B0C; 14 | return *g_dataHandler; 15 | } 16 | 17 | #endif 18 | 19 | class LoadedModFinder 20 | { 21 | const char * m_stringToFind; 22 | 23 | public: 24 | LoadedModFinder(const char * str) : m_stringToFind(str) { } 25 | 26 | bool Accept(ModInfo* modInfo) 27 | { 28 | return !StrCompare(modInfo->name, m_stringToFind); 29 | } 30 | }; 31 | 32 | const ModInfo * DataHandler::LookupModByName(const char * modName) 33 | { 34 | return modList.modInfoList.Find(LoadedModFinder(modName)); 35 | } 36 | 37 | const ModInfo ** DataHandler::GetActiveModList() 38 | { 39 | static const ModInfo* activeModList[0x100] = { 0 }; 40 | 41 | if (!(*activeModList)) 42 | { 43 | UInt16 index = 0; 44 | for (index = 0 ; index < DataHandler::Get()->modList.modInfoList.Count() ; index++) 45 | { 46 | ModInfo* entry = DataHandler::Get()->modList.modInfoList.GetNthItem(index); 47 | if (entry->IsLoaded()) 48 | activeModList[index] = entry; 49 | } 50 | } 51 | 52 | return activeModList; 53 | } 54 | 55 | UInt8 DataHandler::GetModIndex(const char* modName) 56 | { 57 | return modList.modInfoList.GetIndexOf(LoadedModFinder(modName)); 58 | } 59 | 60 | const char* DataHandler::GetNthModName(UInt32 modIndex) 61 | { 62 | const ModInfo** activeModList = GetActiveModList(); 63 | if (modIndex < GetActiveModCount() && activeModList[modIndex]) 64 | return activeModList[modIndex]->name; 65 | else 66 | return ""; 67 | } 68 | 69 | void DataHandler::DisableAssignFormIDs(bool shouldAsssign) 70 | { 71 | ThisStdCall(0x464D30, this, shouldAsssign); 72 | } 73 | 74 | struct IsModLoaded 75 | { 76 | bool Accept(ModInfo* pModInfo) const { 77 | return pModInfo->IsLoaded(); 78 | } 79 | }; 80 | 81 | UInt8 DataHandler::GetActiveModCount() const 82 | { 83 | UInt32 count = modList.modInfoList.CountIf(IsModLoaded()); 84 | return count; 85 | } 86 | 87 | ModInfo::ModInfo() { 88 | // 89 | }; 90 | 91 | ModInfo::~ModInfo() { 92 | // 93 | }; 94 | -------------------------------------------------------------------------------- /nvse/nvse/GameOSDepend.cpp: -------------------------------------------------------------------------------- 1 | #include "GameOSDepend.h" 2 | 3 | OSInputGlobals** g_OSInputGlobals = (OSInputGlobals**)0x011F35CC; 4 | 5 | OSGlobals ** g_osGlobals = (OSGlobals **)0x011DEA0C; //in oldWinMain, result of FormHeap_allocate ~Ax. 6 | -------------------------------------------------------------------------------- /nvse/nvse/GameProcess.cpp: -------------------------------------------------------------------------------- 1 | #include "GameProcess.h" 2 | 3 | ActorProcessManager * g_actorProcessManager = (ActorProcessManager*)0x011E0E80; 4 | -------------------------------------------------------------------------------- /nvse/nvse/GameRTTI.cpp: -------------------------------------------------------------------------------- 1 | #include "GameRTTI.h" 2 | 3 | #if RUNTIME 4 | #include "GameRTTI_1_4_0_525.inc" 5 | #elif EDITOR 6 | #include "GameRTTI_EDITOR.inc" 7 | #endif 8 | -------------------------------------------------------------------------------- /nvse/nvse/GameTasks.cpp: -------------------------------------------------------------------------------- 1 | #include "GameTasks.h" 2 | #include "GameAPI.h" 3 | #include "GameForms.h" 4 | #include "GameObjects.h" 5 | #include "Hooks_Gameplay.h" 6 | 7 | // IOManager** g_ioManager = (IOManager**)0x00B33A10; 8 | ModelLoader** g_modelLoader = (ModelLoader**)0x011C3B3C; 9 | UInt32 kModelLoader_QueueReference = 0x00444850; 10 | UInt32 * kBSTaskCounter = (UInt32*) 0x0011C3B38; 11 | 12 | #if 0 13 | bool IOManager::IsInQueue(TESObjectREFR *refr) 14 | { 15 | for (LockFreeQueue< NiPointer >::Node *node = taskQueue->head->next; node; node = node->next) 16 | { 17 | QueuedReference *qr = OBLIVION_CAST(node->data, IOTask, QueuedReference); 18 | if (!qr) 19 | continue; 20 | 21 | if (qr->refr == refr) 22 | return true; 23 | } 24 | 25 | return false; 26 | } 27 | 28 | void IOManager::DumpQueuedTasks() 29 | { 30 | #if 0 31 | _MESSAGE("Dumping queued tasks:"); 32 | for (LockFreeQueue< NiPointer >::Node *node = taskQueue->head->next; node; node = node->next) 33 | { 34 | QueuedReference* qr = OBLIVION_CAST(node->data, IOTask, QueuedReference); 35 | if (!qr) 36 | continue; 37 | else if (qr->refr) 38 | { 39 | Console_Print("\t%s (%08x)", GetFullName(qr->refr), qr->refr->refID); 40 | _MESSAGE("\t%s (%08x)", GetFullName(qr->refr), qr->refr->refID); 41 | } 42 | else 43 | _MESSAGE("NULL reference"); 44 | } 45 | #endif 46 | 47 | } 48 | 49 | IOManager* IOManager::GetSingleton() 50 | { 51 | return *g_ioManager; 52 | } 53 | #endif 54 | 55 | ModelLoader* ModelLoader::GetSingleton() 56 | { 57 | return *g_modelLoader; 58 | } 59 | 60 | void ModelLoader::QueueReference(TESObjectREFR* refr, UInt32 arg1, bool ifInMainThread) 61 | { 62 | ThisStdCall(kModelLoader_QueueReference, this, refr, arg1, (UInt32)ifInMainThread); // arg1 is encoded based on the parent cell and arg2 is most likely a boolean 63 | } 64 | 65 | UInt32* BSTask::GetCounterSingleton() 66 | { 67 | return kBSTaskCounter; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /nvse/nvse/GameTypes.cpp: -------------------------------------------------------------------------------- 1 | #include "GameTypes.h" 2 | #include "GameAPI.h" 3 | 4 | #include 5 | #include 6 | 7 | /*** String ***/ 8 | 9 | String::String() : m_data(NULL), m_dataLen(0), m_bufLen(0) {} 10 | 11 | String::~String() 12 | { 13 | if (m_data) 14 | { 15 | FormHeap_Free(m_data); 16 | m_data = NULL; 17 | } 18 | m_bufLen = m_dataLen = 0; 19 | } 20 | 21 | bool String::Set(const char * src) 22 | { 23 | if (!src) { 24 | FormHeap_Free(m_data); 25 | m_data = 0; 26 | m_bufLen = 0; 27 | m_dataLen = 0; 28 | return true; 29 | } 30 | 31 | UInt32 srcLen = strlen(src); 32 | 33 | // realloc if needed 34 | if(srcLen > m_bufLen) 35 | { 36 | FormHeap_Free(m_data); 37 | m_data = (char *)FormHeap_Allocate(srcLen + 1); 38 | m_bufLen = m_data ? srcLen : 0; 39 | } 40 | 41 | if(m_data) 42 | { 43 | strcpy_s(m_data, m_bufLen + 1, src); 44 | m_dataLen = srcLen; 45 | } 46 | else 47 | { 48 | m_dataLen = 0; 49 | } 50 | 51 | return m_data != NULL; 52 | } 53 | 54 | bool String::Includes(const char *toFind) const 55 | { 56 | if (!m_data || !toFind) //passing null ptr to std::string c'tor = CRASH 57 | return false; 58 | std::string curr(m_data, m_dataLen); 59 | std::string str2(toFind); 60 | std::string::iterator currEnd = curr.end(); 61 | return (std::search(curr.begin(), currEnd, str2.begin(), str2.end(), ci_equal) != currEnd); 62 | } 63 | 64 | bool String::Replace(const char *_toReplace, const char *_replaceWith) 65 | { 66 | if (!m_data || !_toReplace) 67 | return false; 68 | 69 | std::string curr(m_data, m_dataLen); 70 | std::string toReplace(_toReplace); 71 | 72 | std::string::iterator currBegin = curr.begin(); 73 | std::string::iterator currEnd = curr.end(); 74 | std::string::iterator replaceIt = std::search(currBegin, currEnd, toReplace.begin(), toReplace.end(), ci_equal); 75 | if (replaceIt != currEnd) { 76 | std::string replaceWith(_replaceWith); 77 | // we found the substring, now we need to do the modification 78 | std::string::size_type replacePos = distance(currBegin, replaceIt); 79 | curr.replace(replacePos, toReplace.size(), replaceWith); 80 | Set(curr.c_str()); 81 | return true; 82 | } 83 | return false; 84 | } 85 | 86 | bool String::Append(const char* toAppend) 87 | { 88 | std::string curr(""); 89 | if (m_data) 90 | curr = std::string(m_data, m_dataLen); 91 | 92 | curr += toAppend; 93 | Set(curr.c_str()); 94 | return true; 95 | } 96 | 97 | double String::Compare(const String& compareTo, bool caseSensitive) 98 | { 99 | if (!m_data) 100 | return -2; //signal value if comparison could not be made 101 | 102 | std::string first(m_data, m_dataLen); 103 | std::string second(compareTo.m_data, compareTo.m_dataLen); 104 | 105 | if (!caseSensitive) 106 | { 107 | std::transform(first.begin(), first.end(), first.begin(), tolower); 108 | std::transform(second.begin(), second.end(), second.begin(), tolower); 109 | } 110 | 111 | double comp = 0; 112 | if (first < second) 113 | comp = -1; 114 | else if (first > second) 115 | comp = 1; 116 | 117 | return comp; 118 | } 119 | 120 | const char * String::CStr(void) 121 | { 122 | 123 | return (m_data && m_dataLen) ? m_data : ""; 124 | } 125 | -------------------------------------------------------------------------------- /nvse/nvse/Hooks_Animation.cpp: -------------------------------------------------------------------------------- 1 | #include "Hooks_Animation.h" 2 | #include "SafeWrite.h" 3 | #include 4 | #include "Utilities.h" 5 | #include "GameForms.h" 6 | 7 | #if RUNTIME 8 | 9 | #define kHookGetGlobalModelPath 0x0104A1B8 10 | static const UInt32 kOriginalGetGlobalModelPath = 0x00601C30; 11 | 12 | static bool __stdcall doAnimationHook(TESModel* model) 13 | { 14 | return (model && strrchr(model->nifPath.CStr(), '\\')); 15 | } 16 | 17 | static __declspec(naked) char* AnimationHook(void) 18 | { 19 | _asm { 20 | pushad 21 | push ecx 22 | call doAnimationHook 23 | test eax,eax 24 | jz doCallOriginalGetGlobalModelPath 25 | popad 26 | mov eax, [ecx + 4] 27 | retn 28 | 29 | doCallOriginalGetGlobalModelPath: 30 | popad 31 | jmp kOriginalGetGlobalModelPath 32 | } 33 | } 34 | 35 | void Hook_Animation_Init(void) 36 | { 37 | UInt32 enableAnimationHook = 0; 38 | 39 | if(GetNVSEConfigOption_UInt32("Animation", "EnableAnimationHook", &enableAnimationHook) && enableAnimationHook) 40 | { 41 | SafeWrite32(kHookGetGlobalModelPath, (UInt32)AnimationHook); 42 | } 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /nvse/nvse/Hooks_Animation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if RUNTIME 4 | 5 | void Hook_Animation_Init(void); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /nvse/nvse/Hooks_Dialog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if RUNTIME 4 | 5 | void Hook_Dialog_Init(void); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /nvse/nvse/Hooks_DirectInput8Create.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define DIRECTINPUT_VERSION 0x0800 4 | #include 5 | #include 6 | 7 | void Hook_DirectInput8Create_Init(); 8 | 9 | enum 10 | { 11 | kDeviceType_Keyboard = 1, 12 | kDeviceType_Mouse 13 | }; 14 | 15 | enum 16 | { 17 | // first 256 for keyboard, then 8 mouse buttons, then mouse wheel up, wheel down 18 | kMacro_MouseButtonOffset = 256, 19 | kMacro_MouseWheelOffset = kMacro_MouseButtonOffset + 8, 20 | 21 | kMaxMacros = kMacro_MouseWheelOffset + 2, 22 | }; 23 | 24 | class DIHookControl : public ISingleton 25 | { 26 | public: 27 | enum 28 | { 29 | // data sources 30 | kFlag_GameState = 1 << 0, // input passed to game post-filtering 31 | kFlag_RawState = 1 << 1, // user input 32 | kFlag_InsertedState = 1 << 2, // keydown was inserted by script 33 | 34 | // modifiers 35 | kFlag_IgnoreDisabled_User = 1 << 3, // ignore user-disabled keys 36 | kFlag_IgnoreDisabled_Script = 1 << 4, // ignore script-disabled keys 37 | 38 | kFlag_DefaultBackCompat = kFlag_GameState, 39 | }; 40 | 41 | enum 42 | { 43 | kDisable_User = 1 << 0, 44 | kDisable_Script = 1 << 1, 45 | 46 | kDisable_All = kDisable_User | kDisable_Script, 47 | }; 48 | 49 | DIHookControl(); 50 | 51 | bool IsKeyPressed(UInt32 keycode, UInt32 flags = 0); 52 | bool IsKeyDisabled(UInt32 keycode); 53 | bool IsKeyHeld(UInt32 keycode); 54 | bool IsKeyTapped(UInt32 keycode); 55 | 56 | void SetKeyDisableState(UInt32 keycode, bool bDisable, UInt32 mask); 57 | void SetKeyHeldState(UInt32 keycode, bool bHold); 58 | void TapKey(UInt32 keycode); 59 | 60 | void BufferedKeyTap(UInt32 key); 61 | void BufferedKeyPress(UInt32 key); 62 | void BufferedKeyRelease(UInt32 key); 63 | 64 | // hook interface 65 | void ProcessKeyboardData(UInt8 * data); 66 | void ProcessMouseData(DIMOUSESTATE2 * data); 67 | HRESULT ProcessBufferedData(IDirectInputDevice8 * device, DWORD dataSize, DIDEVICEOBJECTDATA * outData, DWORD * outDataLen, DWORD flags); 68 | 69 | private: 70 | struct KeyInfo 71 | { 72 | bool rawState; // state from dinput last update 73 | bool gameState; // state sent to the game last update 74 | bool insertedState; // true if a script pushed/held this key down last update 75 | 76 | bool hold; // key is held down 77 | bool tap; // key is being tapped 78 | bool userDisable; // key cannot be pressed by user 79 | bool scriptDisable; // key cannot be pressed by script 80 | 81 | bool Process(bool keyDown, UInt32 idx); 82 | }; 83 | 84 | KeyInfo m_keys[kMaxMacros]; 85 | 86 | typedef std::queue BufferedPressQueue; 87 | BufferedPressQueue m_bufferedPresses; 88 | }; 89 | 90 | class FramerateTracker 91 | { 92 | public: 93 | FramerateTracker(); 94 | 95 | void Update(void); 96 | 97 | private: 98 | enum 99 | { 100 | kFrameTimeHistoryLength = 32 101 | }; 102 | 103 | UInt32 m_lastTime; 104 | float m_lastFrameLength; // frametime in seconds 105 | 106 | float m_frameTimeHistory[kFrameTimeHistoryLength]; // last kFrameTimeHistoryLength frametimes 107 | UInt32 m_frameTimeHistoryIdx; // slot that will be filled on the next update call 108 | bool m_frameTimeHistoryPrimed; // true after history buffer is full 109 | 110 | float m_averageFrameTime; // average of m_frameTimeHistory 111 | }; 112 | 113 | extern FramerateTracker g_framerateTracker; 114 | -------------------------------------------------------------------------------- /nvse/nvse/Hooks_Editor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if EDITOR 4 | void Hook_Editor_Init(void); 5 | void CreateHookWindow(void); 6 | 7 | void FixEditorFont(void); 8 | 9 | // Add "string_var" as alias for "long" 10 | void CreateTokenTypedefs(void); 11 | 12 | // Disable check on vanilla opcode range for use of commands as conditionals 13 | void PatchConditionalCommands(void); 14 | 15 | // Allow use of special characters '$', '[', and ']' in string params to script commands 16 | void PatchIsAlpha(void); 17 | 18 | // Handle new param types 19 | void PatchDefaultCommandParser(); 20 | #else 21 | void PatchGameCommandParser(); 22 | #endif 23 | 24 | void PatchDisable_ScriptBufferValidateRefVars(bool disable); -------------------------------------------------------------------------------- /nvse/nvse/Hooks_Gameplay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "CommandTable.h" 5 | #include "Utilities.h" 6 | #include "GameObjects.h" 7 | 8 | 9 | class Menu; 10 | extern std::unordered_set g_myMods; 11 | 12 | void Hook_Gameplay_Init(void); 13 | void ToggleUIMessages(bool enableSpam); 14 | void ToggleConsoleOutput(bool enable); 15 | bool RunCommand_NS(COMMAND_ARGS, Cmd_Execute cmd); 16 | 17 | extern DWORD g_mainThreadID; 18 | 19 | // this returns a refID rather than a TESObjectREFR* as dropped items are non-persistent references 20 | UInt32 GetPCLastDroppedItemRef(); 21 | TESForm* GetPCLastDroppedItem(); // returns the base object 22 | 23 | void SetRetainExtraOwnership(bool bRetain); 24 | 25 | namespace TogglePlayerControlsAlt 26 | { 27 | using flags_t = UInt32; 28 | extern UnorderedMap g_disabledFlagsPerMod; 29 | 30 | extern flags_t g_disabledControls; 31 | enum CheckDisabledHow : UInt8; 32 | 33 | void __fastcall DisablePlayerControlsAlt(flags_t flagsToAddForMod, const char* modName); 34 | void __fastcall EnablePlayerControlsAlt(flags_t flagsToRemoveForMod, const char* modName); 35 | bool __cdecl GetPlayerControlsDisabledAlt(CheckDisabledHow disabledHow, flags_t flagsToCheck, const char* modName); 36 | flags_t __fastcall GetDisabledPlayerControls(CheckDisabledHow disabledHow, const char* modName); 37 | 38 | flags_t CondenseVanillaFlagArgs(UInt32 movementFlag, UInt32 pipboyFlag, UInt32 fightingFlag, UInt32 POVFlag, 39 | UInt32 lookingFlag, UInt32 rolloverTextFlag, UInt32 sneakingFlag); 40 | 41 | template 42 | std::pair ExtractArgsForEnableOrDisablePlayerControls(COMMAND_ARGS) 43 | { 44 | UInt32 movementFlag = 1, pipboyFlag = 1, fightingFlag = 1, POVFlag = 1, 45 | lookingFlag = IsEnable ? 1 : 0, rolloverTextFlag = IsEnable ? 1 : 0, sneakingFlag = IsEnable ? 1 : 0; 46 | 47 | if (!ExtractArgsEx(EXTRACT_ARGS_EX, &movementFlag, &pipboyFlag, &fightingFlag, &POVFlag, 48 | &lookingFlag, &rolloverTextFlag, &sneakingFlag)) 49 | { 50 | return std::pair(false, 0); 51 | } 52 | 53 | auto newFlagsForMod = CondenseVanillaFlagArgs(movementFlag, pipboyFlag, fightingFlag, 54 | POVFlag, lookingFlag, rolloverTextFlag, sneakingFlag); 55 | 56 | return std::pair(true, newFlagsForMod); 57 | } 58 | 59 | void ApplyImmediateDisablingEffects(flags_t changedFlagsForMod); 60 | void ApplyImmediateEnablingEffects(flags_t changedFlagsForMod); 61 | 62 | void ResetOnLoad(); 63 | } -------------------------------------------------------------------------------- /nvse/nvse/Hooks_Logging.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if RUNTIME 4 | 5 | void Hook_Logging_Init(void); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /nvse/nvse/Hooks_Memory.cpp: -------------------------------------------------------------------------------- 1 | #include "Hooks_Memory.h" 2 | #include "SafeWrite.h" 3 | #include "Utilities.h" 4 | 5 | // greets to sheson for his work on this 6 | // it must run before static initializers are run 7 | 8 | enum HeapType { 9 | kHeapType_Default = 0, 10 | kHeapType_File, 11 | kHeapType_Max 12 | }; 13 | 14 | const char* heapNames[kHeapType_Max] = { 15 | "Default", 16 | "File", 17 | }; 18 | 19 | // In MB 20 | const UInt32 vanillaHeapSizes[kHeapType_Max] = { 21 | 200, 22 | 64, 23 | }; 24 | 25 | const UInt32 maxHeapSizes[kHeapType_Max] = { 26 | 1024, 27 | 192, 28 | }; 29 | 30 | UInt32 userHeapSizes[kHeapType_Max] = { 31 | 0, 32 | 0, 33 | }; 34 | 35 | constexpr UInt32 heapAddresses[kHeapType_Max] = { 36 | 0x866EA0, 37 | 0x866F89, 38 | }; 39 | 40 | void Hooks_Memory_PreloadCommit(bool isNoGore) 41 | { 42 | GetNVSEConfigOption_UInt32("Memory", "DefaultHeapInitialAllocMB", &userHeapSizes[kHeapType_Default]); 43 | GetNVSEConfigOption_UInt32("Memory", "FileHeapSizeMB", &userHeapSizes[kHeapType_File]); 44 | 45 | // Check if values differ from vanilla 46 | for (UInt32 i = 0; i < kHeapType_Max; i++) { 47 | if (userHeapSizes[i] > maxHeapSizes[i]) { 48 | _MESSAGE("Warning: %s heap size is greater than maximum allowed value. Using maximum value of %i", heapNames[i], maxHeapSizes[i]); 49 | userHeapSizes[i] = maxHeapSizes[i]; 50 | } 51 | else if (userHeapSizes[i] < vanillaHeapSizes[i]) { 52 | _MESSAGE("Warning: %s heap size is less than vanilla value. Using vanilla value of %i", heapNames[i], vanillaHeapSizes[i]); 53 | userHeapSizes[i] = vanillaHeapSizes[i]; 54 | } 55 | 56 | if (userHeapSizes[i] != vanillaHeapSizes[i]) { 57 | _MESSAGE("Overriding %s heap size: %dMB", heapNames[i], userHeapSizes[i]); 58 | SafeWrite32(heapAddresses[i], userHeapSizes[i] * 0x100000); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /nvse/nvse/Hooks_Memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void Hooks_Memory_PreloadCommit(bool isNoGore); 4 | -------------------------------------------------------------------------------- /nvse/nvse/Hooks_Other.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "FastStack.h" 3 | #include "GameAPI.h" 4 | #include "ScriptTokenCache.h" 5 | 6 | namespace OtherHooks 7 | { 8 | struct CurrentScriptContext 9 | { 10 | Script* script = nullptr; 11 | ScriptRunner* scriptRunner = nullptr; 12 | UInt32* lineNumberPtr = nullptr; 13 | TESObjectREFR* scriptOwnerRef = nullptr; 14 | CommandInfo* command = nullptr; 15 | UInt32* curDataPtr = nullptr; 16 | ScriptTokenCacheFormExtraData* scriptExtraData = nullptr; 17 | }; 18 | void CleanUpNVSEVars(ScriptEventList* eventList); 19 | void CleanUpNVSEVar(ScriptEventList* eventList, ScriptLocal* local); 20 | 21 | void DeleteEventList(ScriptEventList* eventList); 22 | 23 | void Hooks_Other_Init(); 24 | 25 | CurrentScriptContext* GetExecutingScriptContext(); 26 | 27 | void PushScriptContext(const CurrentScriptContext& ctx); 28 | void PopScriptContext(); 29 | } 30 | -------------------------------------------------------------------------------- /nvse/nvse/Hooks_SaveLoad.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if RUNTIME 4 | 5 | void Hook_SaveLoad_Init(); 6 | extern bool g_gameLoaded; 7 | extern bool g_gameStarted; 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /nvse/nvse/InventoryRef.cpp: -------------------------------------------------------------------------------- 1 | #include "InventoryRef.h" 2 | #include "GameObjects.h" 3 | 4 | #if 0 5 | // todo: fix this code copied from JIP LN NVSE. Has some missing functions that would need to be ported over. 6 | 7 | ExtraDataList* InventoryRef::CreateExtraData() 8 | { 9 | ExtraContainerChanges::EntryDataList* entryList = containerRef->GetContainerChangesList(); 10 | if (!entryList) return nullptr; 11 | ExtraContainerChanges::EntryData* pEntry = entryList->FindForItem(type); 12 | if (!pEntry) 13 | { 14 | pEntry = ExtraContainerChanges::EntryData::Create(type, 0); 15 | entryList->Prepend(pEntry); 16 | } 17 | xData = ExtraDataList::Create(); 18 | if (pEntry->extendData) 19 | pEntry->extendData->Prepend(xData); 20 | else 21 | { 22 | pEntry->extendData = Game_HeapAlloc(); 23 | pEntry->extendData->Init(xData); 24 | } 25 | containerRef->MarkAsModified(0x20); 26 | return xData; 27 | } 28 | 29 | ExtraDataList* __fastcall InventoryRef::SplitFromStack(SInt32 maxStack) 30 | { 31 | if (auto* xCount = (ExtraCount*)xData->GetByType(kExtraData_Count)) 32 | { 33 | SInt32 delta = xCount->count - maxStack; 34 | if (delta <= 0) 35 | return xData; 36 | ExtraContainerChanges::EntryData* pEntry = containerRef->GetContainerChangesEntry(type); 37 | if (!pEntry) return xData; 38 | ExtraDataList* xDataOut = xData->CreateCopy(); 39 | pEntry->extendData->Prepend(xDataOut); 40 | xDataOut->RemoveByType(kExtraData_Worn); 41 | xDataOut->RemoveByType(kExtraData_Hotkey); 42 | if (delta < 2) 43 | { 44 | xData->RemoveByType(kExtraData_Count); 45 | if (!xData->m_data) 46 | { 47 | pEntry->extendData->Remove(xData); 48 | Game_HeapFree(xData); 49 | } 50 | } 51 | else xCount->count = delta; 52 | xData = xDataOut; 53 | if (maxStack > 1) 54 | { 55 | xCount = (ExtraCount*)xData->GetByType(kExtraData_Count); 56 | xCount->count = maxStack; 57 | } 58 | else xData->RemoveByType(kExtraData_Count); 59 | } 60 | else if (maxStack > 1) 61 | xData->AddExtraCount(maxStack); 62 | return xData; 63 | } 64 | 65 | #endif -------------------------------------------------------------------------------- /nvse/nvse/InventoryRef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GameExtraData.h" 4 | 5 | // 30 6 | // Taken from JIP LN NVSE plugin, with some tweaks. 7 | // This is just a stripped-down version of xNVSE's internal InventoryReference class. 8 | // It exists so plugins have limited access to the internal functions. 9 | struct InventoryRef 10 | { 11 | struct Data 12 | { 13 | TESForm* type; // 00 14 | ExtraContainerChanges::EntryData* entry; // 04 15 | ExtraDataList* xData; // 08 16 | } data; 17 | TESObjectREFR* containerRef; // 0C 18 | TESObjectREFR* tempRef; // 10 19 | UInt8 pad14[24]; // 14 20 | bool doValidation; // 2C 21 | bool removed; // 2D 22 | UInt8 pad2E[2]; // 2E 23 | 24 | SInt32 GetCount() const { return data.entry->countDelta; } 25 | #if 0 26 | // todo: fix these by porting over some functions from JIP 27 | ExtraDataList* CreateExtraData(); 28 | ExtraDataList* __fastcall SplitFromStack(SInt32 maxStack = 1); 29 | #endif 30 | }; 31 | 32 | -------------------------------------------------------------------------------- /nvse/nvse/InventoryReference.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "InventoryInfo.h" 4 | 5 | class TESObjectREFR; 6 | 7 | // InventoryReference represents a temporary reference to a stack of items in an inventory 8 | // temp refs are valid only for the frame during which they were created 9 | 10 | class InventoryReference 11 | { 12 | public: 13 | struct Data 14 | { 15 | TESForm * type; 16 | ExtraContainerChanges::EntryData * entry; 17 | ExtraDataList * xData; 18 | 19 | Data(TESForm* t, ExtraContainerChanges::EntryData* en, ExtraDataList* ex) : type(t), entry(en), xData(ex) { } 20 | Data(const Data& rhs) : type(rhs.type), entry(rhs.entry), xData(rhs.xData) { } 21 | Data() : type(NULL), entry(NULL), xData(NULL) { } 22 | }; 23 | 24 | ~InventoryReference(); 25 | 26 | TESObjectREFR* GetContainer() { return m_containerRef; } 27 | void SetContainer(TESObjectREFR* cont) { m_containerRef = cont; } 28 | bool SetData(const Data &data); 29 | TESObjectREFR* GetRef() { return Validate() ? m_tempRef : NULL; } 30 | static TESObjectREFR* GetRefBySelf(InventoryReference* self) { return self ? self->GetRef() : NULL; } // Needed to get convert the address to a void* 31 | 32 | bool WriteRefDataToContainer(); 33 | bool RemoveFromContainer(); // removes and frees Data pointers 34 | bool MoveToContainer(TESObjectREFR* dest); 35 | bool CopyToContainer(TESObjectREFR* dest, InventoryReference** outInvRef = nullptr); 36 | bool SetEquipped(bool bEquipped); 37 | void SetRemoved() { m_bRemoved = true; } 38 | void Release(); 39 | 40 | static InventoryReference* GetForRefID(UInt32 refID); 41 | 42 | enum ActionType 43 | { 44 | kAction_Equip, 45 | kAction_Remove, 46 | }; 47 | 48 | class DeferredAction 49 | { 50 | ActionType m_type; 51 | Data m_itemData; 52 | TESObjectREFR *m_target; 53 | 54 | public: 55 | // an operation which could potentially invalidate the extradatalist, deferred until inv ref is released 56 | DeferredAction(ActionType type, const Data& data, TESObjectREFR *target = nullptr) : m_type(type), m_itemData(data), m_target(target) {} 57 | 58 | const Data& Data() {return m_itemData;} 59 | bool Execute(InventoryReference* iref); 60 | }; 61 | 62 | Data m_data; 63 | TESObjectREFR *m_containerRef; 64 | TESObjectREFR *m_tempRef; 65 | Stack m_deferredActions; 66 | ExtraContainerChanges::EntryData *m_tempEntry; 67 | UInt8 pad1C[0x10]; // This used to be std::queue; Padded to preserve sizeof == 0x30, for backward compatibility with plugins. 68 | bool m_bDoValidation; 69 | bool m_bRemoved; 70 | 71 | bool Validate(); 72 | void DoDeferredActions(); 73 | SInt32 GetCount(); 74 | }; 75 | 76 | typedef UnorderedMap InventoryReferenceMap; 77 | extern InventoryReferenceMap s_invRefMap; 78 | extern ICriticalSection s_invRefMapCS; 79 | 80 | InventoryReference* CreateInventoryRef(TESObjectREFR* container, const InventoryReference::Data &data, bool bValidate); 81 | ExtraContainerChanges::EntryData *CreateTempEntry(TESForm *itemForm, SInt32 countDelta, ExtraDataList *xData); 82 | TESObjectREFR* __stdcall CreateInventoryRefEntry(TESObjectREFR *container, TESForm *itemForm, SInt32 countDelta, ExtraDataList *xData); -------------------------------------------------------------------------------- /nvse/nvse/LambdaManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "GameScript.h" 3 | 4 | class ExpressionEvaluator; 5 | 6 | namespace LambdaManager 7 | { 8 | extern ICriticalSection g_lambdaCs; 9 | struct ScriptData 10 | { 11 | UInt8* scriptData; 12 | UInt32 size; 13 | ScriptData() = default; 14 | ScriptData(UInt8* scriptData, UInt32 size) : scriptData(scriptData), size(size) {} 15 | }; 16 | 17 | class LambdaVariableContext 18 | { 19 | Script* scriptLambda = nullptr; 20 | public: 21 | 22 | LambdaVariableContext() = default; 23 | LambdaVariableContext(Script* scriptLambda); 24 | LambdaVariableContext(nullptr_t nullScript) {} 25 | 26 | LambdaVariableContext(const LambdaVariableContext& other) = delete; 27 | LambdaVariableContext& operator=(const LambdaVariableContext& other) = delete; 28 | 29 | bool operator==(const LambdaVariableContext& other) const { return scriptLambda == other.scriptLambda; } 30 | 31 | LambdaVariableContext(LambdaVariableContext&& other) noexcept; 32 | LambdaVariableContext& operator=(LambdaVariableContext&& other) noexcept; 33 | 34 | ~LambdaVariableContext(); 35 | }; 36 | 37 | // Stores and gives access to a Script, but avoids needlessly capturing lambda var context until needed. 38 | class Maybe_Lambda 39 | { 40 | Script* m_script = nullptr; 41 | bool m_triedToSaveContext = false; 42 | public: 43 | 44 | Maybe_Lambda() = default; 45 | Maybe_Lambda(Script* script) : m_script(script) {} 46 | 47 | Maybe_Lambda(const Maybe_Lambda& other) = delete; 48 | Maybe_Lambda& operator=(const Maybe_Lambda& other) = delete; 49 | 50 | Maybe_Lambda(Maybe_Lambda&& other) noexcept; 51 | Maybe_Lambda& operator=(Maybe_Lambda&& other) noexcept; 52 | 53 | //Only compares the contained scripts. 54 | bool operator==(const Maybe_Lambda& other) const; 55 | bool operator==(const Script* other) const; 56 | operator bool() const { return m_script != nullptr; } 57 | 58 | [[nodiscard]] Script* Get() const { return m_script; } 59 | void TrySaveContext(); 60 | 61 | ~Maybe_Lambda(); 62 | }; 63 | 64 | Script* CreateLambdaScript(const ScriptData& scriptData, const Script* parentScript); 65 | 66 | Script* CreateLambdaScript(UInt8* position, const ScriptData& scriptData, const ExpressionEvaluator&); 67 | ScriptEventList* GetParentEventList(Script* scriptLambda); 68 | void MarkParentAsDeleted(ScriptEventList* parentEventList); 69 | void MarkScriptAsDeleted(Script* script); 70 | bool IsScriptLambda(Script* scriptLambda); 71 | void DeleteAllForParentScript(Script* parentScript); 72 | void ClearSavedDeletedEventLists(); 73 | 74 | // makes sure that a variable list is not deleted by the game while a lambda is still pending execution 75 | void SaveLambdaVariables(Script* scriptLambda); 76 | void UnsaveLambdaVariables(Script* scriptLambda); 77 | 78 | void EraseUnusedSavedVariableLists(); 79 | } 80 | -------------------------------------------------------------------------------- /nvse/nvse/MemoizedMap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "containers.h" 6 | 7 | template 8 | class MemoizedMap 9 | { 10 | public: 11 | thread_local static UnorderedMap map; 12 | template 13 | V& Get(const K& key, F&& f) 14 | { 15 | if (localToken_ != globalToken_) 16 | { 17 | localToken_ = globalToken_; 18 | map.Clear(); 19 | } 20 | V* value; 21 | if (map.Insert(key, &value)) 22 | *value = 0; // Fix issue that affected Vanilla UI+ with lStewieAl's Tweaks bContainerDefaultToRightSide 23 | if (!*value) 24 | *value = f(key); 25 | return *value; 26 | } 27 | 28 | static void Clear() 29 | { 30 | ++globalToken_; 31 | } 32 | 33 | private: 34 | static std::atomic globalToken_; 35 | thread_local static int localToken_; 36 | }; 37 | 38 | template 39 | std::atomic MemoizedMap::globalToken_ = 0; 40 | 41 | template 42 | thread_local int MemoizedMap::localToken_ = 0; 43 | 44 | template 45 | thread_local UnorderedMap MemoizedMap::map; 46 | -------------------------------------------------------------------------------- /nvse/nvse/MemoryTracker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | template 7 | class MemoryTracker 8 | { 9 | public: 10 | std::unordered_map> infos; 11 | 12 | void Add(T t) 13 | { 14 | if (false) 15 | Get(nullptr); 16 | constexpr int framesToCapture = 16; 17 | std::vector vecTrace((framesToCapture)); 18 | CaptureStackBackTrace(1, framesToCapture, vecTrace.data(), nullptr); 19 | infos[t] = std::move(vecTrace); 20 | } 21 | 22 | void Remove(T t) 23 | { 24 | infos.erase(t); 25 | } 26 | 27 | std::vector* Get(void* t) 28 | { 29 | if (auto iter = infos.find(t); iter != infos.end()) 30 | return &iter->second; 31 | return nullptr; 32 | } 33 | }; 34 | 35 | template 36 | class CallHistoryTracker 37 | { 38 | public: 39 | struct History 40 | { 41 | T t; 42 | std::vector callStack; 43 | 44 | History(T&& t, std::vector&& callStack) 45 | : t(std::move(t)), 46 | callStack(std::move(callStack)) 47 | { 48 | } 49 | }; 50 | std::vector infos; 51 | 52 | void Add(T&& t) 53 | { 54 | constexpr int framesToCapture = 16; 55 | std::vector vecTrace((framesToCapture)); 56 | CaptureStackBackTrace(1, framesToCapture, vecTrace.data(), nullptr); 57 | infos.emplace_back(std::move(t), std::move(vecTrace)); 58 | } 59 | }; -------------------------------------------------------------------------------- /nvse/nvse/NVSEParser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "NVSELexer.h" 4 | #include "NVSEAst.h" 5 | 6 | #include 7 | #include 8 | 9 | class NVSEParseError : public std::runtime_error { 10 | public: 11 | NVSEParseError(const std::string& message) : std::runtime_error(message) {}; 12 | }; 13 | 14 | class NVSEParser { 15 | public: 16 | NVSEParser(NVSELexer& tokenizer); 17 | std::optional Parse(); 18 | StmtPtr Begin(); 19 | 20 | private: 21 | NVSELexer& lexer; 22 | NVSEToken currentToken; 23 | NVSEToken previousToken; 24 | bool panicMode = false; 25 | bool hadError = false; 26 | 27 | std::shared_ptr FnDecl(); 28 | std::shared_ptr VarDecl(bool allowValue = true, bool allowOnlyOneVarDecl = false); 29 | 30 | StmtPtr Statement(); 31 | StmtPtr ExpressionStatement(); 32 | StmtPtr ForStatement(); 33 | StmtPtr IfStatement(); 34 | StmtPtr ReturnStatement(); 35 | StmtPtr WhileStatement(); 36 | std::shared_ptr BlockStatement(); 37 | 38 | ExprPtr Expression(); 39 | ExprPtr Assignment(); 40 | ExprPtr Ternary(); 41 | ExprPtr Pair(); 42 | ExprPtr LogicalOr(); 43 | ExprPtr LogicalAnd(); 44 | ExprPtr Slice(); 45 | ExprPtr Equality(); 46 | ExprPtr Comparison(); 47 | ExprPtr BitwiseOr(); 48 | ExprPtr BitwiseAnd(); 49 | ExprPtr Shift(); 50 | ExprPtr In(); 51 | ExprPtr Term(); 52 | ExprPtr Factor(); 53 | ExprPtr Unary(); 54 | ExprPtr Postfix(); 55 | ExprPtr Call(); 56 | ExprPtr FnExpr(); 57 | ExprPtr ArrayLiteral(); 58 | ExprPtr MapLiteral(); 59 | std::vector> ParseArgs(); 60 | ExprPtr Primary(); 61 | 62 | void Advance(); 63 | bool Match(NVSETokenType type); 64 | bool MatchesType(); 65 | bool Peek(NVSETokenType type) const; 66 | bool PeekType() const; 67 | void Error(std::string message); 68 | void Error(NVSEToken token, std::string message); 69 | NVSEToken Expect(NVSETokenType type, std::string message); 70 | void Synchronize(); 71 | }; 72 | -------------------------------------------------------------------------------- /nvse/nvse/NVSETreePrinter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "NVSEVisitor.h" 3 | 4 | class NVSETreePrinter : public NVSEVisitor { 5 | int curTab = 0; 6 | void PrintTabs(const bool debugOnly = true); 7 | 8 | public: 9 | NVSETreePrinter() = default; 10 | 11 | void VisitNVSEScript(NVSEScript* script) override; 12 | void VisitBeginStmt(BeginStmt* stmt) override; 13 | void VisitFnStmt(FnDeclStmt* stmt) override; 14 | void VisitVarDeclStmt(VarDeclStmt* stmt) override; 15 | 16 | void VisitExprStmt(const ExprStmt* stmt) override; 17 | void VisitForStmt(ForStmt* stmt) override; 18 | void VisitForEachStmt(ForEachStmt* stmt) override; 19 | void VisitIfStmt(IfStmt* stmt) override; 20 | void VisitReturnStmt(ReturnStmt* stmt) override; 21 | void VisitContinueStmt(ContinueStmt* stmt) override; 22 | void VisitBreakStmt(BreakStmt* stmt) override; 23 | void VisitWhileStmt(WhileStmt* stmt) override; 24 | void VisitBlockStmt(BlockStmt* stmt) override; 25 | 26 | void VisitAssignmentExpr(AssignmentExpr* expr) override; 27 | void VisitTernaryExpr(TernaryExpr* expr) override; 28 | void VisitInExpr(InExpr* expr) override; 29 | void VisitBinaryExpr(BinaryExpr* expr) override; 30 | void VisitUnaryExpr(UnaryExpr* expr) override; 31 | void VisitSubscriptExpr(SubscriptExpr* expr) override; 32 | void VisitCallExpr(CallExpr* expr) override; 33 | void VisitGetExpr(GetExpr* expr) override; 34 | void VisitBoolExpr(BoolExpr* expr) override; 35 | void VisitNumberExpr(NumberExpr* expr) override; 36 | void VisitStringExpr(StringExpr* expr) override; 37 | void VisitIdentExpr(IdentExpr* expr) override; 38 | void VisitMapLiteralExpr(MapLiteralExpr* expr) override; 39 | void VisitArrayLiteralExpr(ArrayLiteralExpr* expr) override; 40 | void VisitGroupingExpr(GroupingExpr* expr) override; 41 | void VisitLambdaExpr(LambdaExpr* expr) override; 42 | }; -------------------------------------------------------------------------------- /nvse/nvse/NVSETypeChecker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "NVSELexer.h" 5 | #include "NVSEScope.h" 6 | #include "NVSEVisitor.h" 7 | #include "ScriptTokens.h" 8 | 9 | class NVSETypeChecker : NVSEVisitor { 10 | struct ReturnInfo { 11 | Token_Type returnType {kTokenType_Invalid}; 12 | size_t line {0}; 13 | }; 14 | 15 | bool hadError = false; 16 | NVSEScript *script; 17 | Script* engineScript; 18 | 19 | std::stack insideLoop {}; 20 | std::stack> scopes {}; 21 | std::stack returnType {}; 22 | 23 | uint32_t scopeIndex {1}; 24 | 25 | bool bScopedGlobal = false; 26 | 27 | std::shared_ptr EnterScope(); 28 | void LeaveScope(); 29 | void error(size_t line, std::string msg); 30 | void error(size_t line, size_t column, std::string msg); 31 | 32 | public: 33 | NVSETypeChecker(NVSEScript* script, Script* engineScript) : script(script), engineScript(engineScript) {} 34 | bool check(); 35 | 36 | void VisitNVSEScript(NVSEScript* script) override; 37 | void VisitBeginStmt(BeginStmt* stmt) override; 38 | void VisitFnStmt(FnDeclStmt* stmt) override; 39 | void VisitVarDeclStmt(VarDeclStmt* stmt) override; 40 | void VisitExprStmt(const ExprStmt* stmt) override; 41 | void VisitForStmt(ForStmt* stmt) override; 42 | void VisitForEachStmt(ForEachStmt* stmt) override; 43 | void VisitIfStmt(IfStmt* stmt) override; 44 | void VisitReturnStmt(ReturnStmt* stmt) override; 45 | void VisitContinueStmt(ContinueStmt* stmt) override; 46 | void VisitBreakStmt(BreakStmt* stmt) override; 47 | void VisitWhileStmt(WhileStmt* stmt) override; 48 | void VisitBlockStmt(BlockStmt* stmt) override; 49 | void VisitAssignmentExpr(AssignmentExpr* expr) override; 50 | void VisitTernaryExpr(TernaryExpr* expr) override; 51 | void VisitInExpr(InExpr* expr) override; 52 | void VisitBinaryExpr(BinaryExpr* expr) override; 53 | void VisitUnaryExpr(UnaryExpr* expr) override; 54 | void VisitSubscriptExpr(SubscriptExpr* expr) override; 55 | void VisitCallExpr(CallExpr* expr) override; 56 | void VisitGetExpr(GetExpr* expr) override; 57 | void VisitBoolExpr(BoolExpr* expr) override; 58 | void VisitNumberExpr(NumberExpr* expr) override; 59 | void VisitMapLiteralExpr(MapLiteralExpr* expr) override; 60 | void VisitArrayLiteralExpr(ArrayLiteralExpr* expr) override; 61 | void VisitStringExpr(StringExpr* expr) override; 62 | void VisitIdentExpr(IdentExpr* expr) override; 63 | void VisitGroupingExpr(GroupingExpr* expr) override; 64 | void VisitLambdaExpr(LambdaExpr* expr) override; 65 | }; 66 | -------------------------------------------------------------------------------- /nvse/nvse/NVSEVisitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct NVSEScript; 4 | 5 | struct BeginStmt; 6 | struct FnDeclStmt; 7 | struct VarDeclStmt; 8 | 9 | struct ExprStmt; 10 | struct ForStmt; 11 | struct ForEachStmt; 12 | struct IfStmt; 13 | struct ReturnStmt; 14 | struct ContinueStmt; 15 | struct BreakStmt; 16 | struct WhileStmt; 17 | struct BlockStmt; 18 | 19 | struct AssignmentExpr; 20 | struct TernaryExpr; 21 | struct InExpr; 22 | struct BinaryExpr; 23 | struct UnaryExpr; 24 | struct SubscriptExpr; 25 | struct CallExpr; 26 | struct GetExpr; 27 | struct BoolExpr; 28 | struct NumberExpr; 29 | struct StringExpr; 30 | struct IdentExpr; 31 | struct MapLiteralExpr; 32 | struct ArrayLiteralExpr; 33 | struct GroupingExpr; 34 | struct LambdaExpr; 35 | 36 | class NVSEVisitor { 37 | public: 38 | virtual ~NVSEVisitor() = default; 39 | 40 | virtual void VisitNVSEScript(NVSEScript* script) = 0; 41 | virtual void VisitBeginStmt(BeginStmt* stmt) = 0; 42 | virtual void VisitFnStmt(FnDeclStmt* stmt) = 0; 43 | virtual void VisitVarDeclStmt(VarDeclStmt* stmt) = 0; 44 | 45 | virtual void VisitExprStmt(const ExprStmt* stmt) = 0; 46 | virtual void VisitForStmt(ForStmt* stmt) = 0; 47 | virtual void VisitForEachStmt(ForEachStmt* stmt) = 0; 48 | virtual void VisitIfStmt(IfStmt* stmt) = 0; 49 | virtual void VisitReturnStmt(ReturnStmt* stmt) = 0; 50 | virtual void VisitContinueStmt(ContinueStmt* stmt) = 0; 51 | virtual void VisitBreakStmt(BreakStmt* stmt) = 0; 52 | virtual void VisitWhileStmt(WhileStmt* stmt) = 0; 53 | virtual void VisitBlockStmt(BlockStmt* stmt) = 0; 54 | 55 | virtual void VisitAssignmentExpr(AssignmentExpr* expr) = 0; 56 | virtual void VisitTernaryExpr(TernaryExpr* expr) = 0; 57 | virtual void VisitInExpr(InExpr* in_expr) = 0; 58 | virtual void VisitBinaryExpr(BinaryExpr* expr) = 0; 59 | virtual void VisitUnaryExpr(UnaryExpr* expr) = 0; 60 | virtual void VisitSubscriptExpr(SubscriptExpr* expr) = 0; 61 | virtual void VisitCallExpr(CallExpr* expr) = 0; 62 | virtual void VisitGetExpr(GetExpr* expr) = 0; 63 | virtual void VisitBoolExpr(BoolExpr* expr) = 0; 64 | virtual void VisitNumberExpr(NumberExpr* expr) = 0; 65 | virtual void VisitStringExpr(StringExpr* expr) = 0; 66 | virtual void VisitIdentExpr(IdentExpr* expr) = 0; 67 | virtual void VisitArrayLiteralExpr(ArrayLiteralExpr* expr) = 0; 68 | virtual void VisitMapLiteralExpr(MapLiteralExpr* expr) = 0; 69 | virtual void VisitGroupingExpr(GroupingExpr* expr) = 0; 70 | virtual void VisitLambdaExpr(LambdaExpr* expr) = 0; 71 | }; 72 | -------------------------------------------------------------------------------- /nvse/nvse/NiNodes.cpp: -------------------------------------------------------------------------------- 1 | #include "NiNodes.h" 2 | 3 | #include "GameScript.h" 4 | #include "MemoizedMap.h" 5 | 6 | std::span g_animGroups = { reinterpret_cast(0x011977D8), TESAnimGroup::kAnimGroup_Max }; 7 | 8 | #if RUNTIME 9 | void TextureFormat::InitFromD3DFMT(UInt32 fmt) 10 | { 11 | typedef void (* _D3DFMTToTextureFormat)(UInt32 d3dfmt, TextureFormat * dst); 12 | _D3DFMTToTextureFormat D3DFMTToTextureFormat = (_D3DFMTToTextureFormat)0x00E7C1E0; 13 | 14 | D3DFMTToTextureFormat(fmt, this); 15 | } 16 | 17 | static const UInt32 kNiObjectNET_SetNameAddr = 0x00A5B690; 18 | 19 | void NiObjectNET::SetName(const char* newName) 20 | { 21 | // uses cdecl, not stdcall 22 | _asm 23 | { 24 | push newName 25 | // mov ecx, this (already) 26 | call kNiObjectNET_SetNameAddr 27 | add esp, 4 28 | } 29 | // OBSE : ThisStdCall(kNiObjectNET_SetNameAddr, this, newName); 30 | } 31 | 32 | const char* TESAnimGroup::StringForAnimGroupCode(UInt32 groupCode) 33 | { 34 | return (groupCode < TESAnimGroup::kAnimGroup_Max) ? g_animGroups[groupCode].name : NULL; 35 | } 36 | 37 | MemoizedMap s_animGroupMap; 38 | 39 | UInt32 TESAnimGroup::AnimGroupForString(const char* groupName) 40 | { 41 | return s_animGroupMap.Get(groupName, [](const char* groupName) 42 | { 43 | for (UInt32 i = 0; i < kAnimGroup_Max; i++) 44 | { 45 | if (!_stricmp(g_animGroups[i].name, groupName)) 46 | { 47 | return i; 48 | } 49 | } 50 | return static_cast(kAnimGroup_Max); 51 | }); 52 | } 53 | 54 | void DumpAnimGroups(void) 55 | { 56 | for (UInt32 i = 0; i < TESAnimGroup::kAnimGroup_Max; i++) { 57 | _MESSAGE("%d,%s", i , g_animGroups[i].name); 58 | //if (!_stricmp(s_animGroupInfos[i].name, "JumpLandRight")) 59 | // break; 60 | } 61 | } 62 | #endif 63 | -------------------------------------------------------------------------------- /nvse/nvse/NiObjects.cpp: -------------------------------------------------------------------------------- 1 | #include "NiObjects.h" 2 | 3 | void NiAVObject::Dump(UInt32 level, const char * indent) 4 | { 5 | UInt32 childCount = 0; 6 | char locIndent[257]; 7 | strcpy_s(locIndent, 257, indent); 8 | if (strlen(indent) < 254) 9 | strcat_s(locIndent, 257, " "); 10 | NiNode* niNode = GetAsNiNode(); 11 | if (niNode) 12 | childCount = niNode->m_children.Length(); 13 | _MESSAGE("[%0.4d]%s - name: '%s' [%0.8X] has %d children", level, locIndent, m_pcName, niNode, childCount); 14 | for (UInt32 i = 0; i < childCount; i++) 15 | { 16 | NiAVObject* child = niNode->m_children[i]; 17 | child->Dump(level+1, locIndent); 18 | } 19 | if (0 == level) 20 | _MESSAGE("\n"); 21 | } 22 | -------------------------------------------------------------------------------- /nvse/nvse/NiPoint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | // Ripped from JIP LN. 5 | // Maybe has a little from JG (?). 6 | 7 | #define DECL_FLOAT_OP(op) \ 8 | NiPoint3 operator op(const float n) const \ 9 | { \ 10 | return NiPoint3(x op n, y op n, z op n); \ 11 | } \ 12 | NiPoint3 operator op##=(const float n) \ 13 | { \ 14 | return *this = NiPoint3(x op n, y op n, z op n); \ 15 | } \ 16 | 17 | #define DECL_VEC_OP(op) \ 18 | NiPoint3 operator op(const NiPoint3 v) const \ 19 | { \ 20 | return NiPoint3(x op v.x, y op v.y, z op v.z); \ 21 | } \ 22 | NiPoint3 operator op##=(const NiPoint3 v) \ 23 | { \ 24 | return *this = NiPoint3(x op v.x, y op v.y, z op v.z); \ 25 | } 26 | 27 | 28 | 29 | struct NiPoint3 30 | { 31 | float x, y, z; 32 | 33 | void Scale(float scale) { 34 | x *= scale; 35 | y *= scale; 36 | z *= scale; 37 | }; 38 | 39 | void Init(NiPoint3* point) 40 | { 41 | x = point->x; 42 | y = point->y; 43 | z = point->z; 44 | }; 45 | 46 | NiPoint3() : x(0.f), y(0.f), z(0.f) 47 | { 48 | }; 49 | 50 | NiPoint3(const float x, const float y, const float z) : x(x), y(y), z(z) 51 | { 52 | }; 53 | 54 | 55 | DECL_FLOAT_OP(*); 56 | DECL_FLOAT_OP(/ ); 57 | 58 | DECL_VEC_OP(+); 59 | DECL_VEC_OP(-); 60 | DECL_VEC_OP(*); 61 | DECL_VEC_OP(/ ); 62 | 63 | float length() const 64 | { 65 | return sqrtf(x * x + y * y + z * z); 66 | } 67 | 68 | float length_sqr() const 69 | { 70 | return x * x + y * y + z * z; 71 | } 72 | 73 | NiPoint3 normal() const 74 | { 75 | const auto len = length(); 76 | return len == 0.F ? NiPoint3() : NiPoint3(x / len, y / len, z / len); 77 | } 78 | 79 | static float dot(const NiPoint3& v1, const NiPoint3& v2) 80 | { 81 | return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; 82 | } 83 | 84 | static NiPoint3 cross(const NiPoint3& v1, const NiPoint3& v2) 85 | { 86 | return NiPoint3( 87 | v1.y * v2.z - v1.z * v2.y, 88 | v1.z * v2.x - v1.x * v2.z, 89 | v1.x * v2.y - v1.y * v2.x); 90 | } 91 | 92 | NiPoint3* Add(NiPoint3* toAdd) 93 | { 94 | this->x += toAdd->x; 95 | this->y += toAdd->y; 96 | this->z += toAdd->z; 97 | return this; 98 | } 99 | 100 | NiPoint3* Subtract(NiPoint3* point) 101 | { 102 | this->x -= point->x; 103 | this->y -= point->y; 104 | this->z -= point->z; 105 | return this; 106 | } 107 | 108 | float CalculateDistSquared(NiPoint3* to) 109 | { 110 | float deltaX = (x - to->x); 111 | float deltaY = (y - to->y); 112 | float deltaZ = (z - to->z); 113 | 114 | return deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ; 115 | } 116 | 117 | bool Equals(NiPoint3* compare) 118 | { 119 | return x == compare->x && y == compare->y && z == compare->z; 120 | } 121 | 122 | bool FltEquals(NiPoint3* compare) 123 | { 124 | if (abs(x - compare->x) > FLT_EPSILON) return false; 125 | if (abs(y - compare->y) > FLT_EPSILON) return false; 126 | return (abs(z - compare->z) <= FLT_EPSILON); 127 | } 128 | }; 129 | 130 | struct NiPoint4 131 | { 132 | float x, y, z, r; 133 | }; 134 | 135 | #undef DECL_FLOAT_OP 136 | #undef DECL_VEC_OP 137 | -------------------------------------------------------------------------------- /nvse/nvse/NiTypes.cpp: -------------------------------------------------------------------------------- 1 | #include "NiTypes.h" 2 | 3 | // Copied from JIP LN NVSE 4 | __declspec(naked) float __vectorcall Point3Distance(const NiVector3& pt1, const NiVector3& pt2) 5 | { 6 | __asm 7 | { 8 | movaps xmm2, PS_XYZ0Mask 9 | movups xmm0, [ecx] 10 | andps xmm0, xmm2 11 | movups xmm1, [edx] 12 | andps xmm1, xmm2 13 | subps xmm0, xmm1 14 | mulps xmm0, xmm0 15 | xorps xmm1, xmm1 16 | haddps xmm0, xmm1 17 | haddps xmm0, xmm1 18 | comiss xmm0, xmm1 19 | jz done 20 | movaps xmm1, xmm0 21 | rsqrtss xmm2, xmm0 22 | mulss xmm1, xmm2 23 | mulss xmm1, xmm2 24 | movss xmm3, SS_3 25 | subss xmm3, xmm1 26 | mulss xmm3, xmm2 27 | mulss xmm3, PS_V3_Half 28 | mulss xmm0, xmm3 29 | done : 30 | retn 31 | } 32 | } 33 | 34 | // NiFixedString 35 | 36 | NiFixedString::NiFixedString() 37 | { 38 | m_kHandle = nullptr; 39 | } 40 | 41 | // GAME - 0x438170 42 | NiFixedString::NiFixedString(const char* apcString) 43 | { 44 | if (apcString) 45 | m_kHandle = NiGlobalStringTable::AddString(apcString); 46 | else 47 | m_kHandle = nullptr; 48 | } 49 | 50 | NiFixedString::NiFixedString(const NiFixedString& arString) 51 | { 52 | m_kHandle = arString.m_kHandle; 53 | } 54 | 55 | // GAME - 0x4381B0 56 | NiFixedString::~NiFixedString() 57 | { 58 | NiGlobalStringTable::DecRefCount(m_kHandle); 59 | } 60 | 61 | // GAME - 0xA2E750 62 | NiFixedString& NiFixedString::operator=(const char* apcString) 63 | { 64 | if (m_kHandle != apcString) 65 | { 66 | NiGlobalStringTable::GlobalStringHandle kHandle = m_kHandle; 67 | m_kHandle = NiGlobalStringTable::AddString(apcString); 68 | NiGlobalStringTable::DecRefCount(kHandle); 69 | } 70 | return *this; 71 | } 72 | 73 | NiFixedString& NiFixedString::operator=(const NiFixedString& arString) 74 | { 75 | if (m_kHandle != arString.m_kHandle) { 76 | NiGlobalStringTable::GlobalStringHandle kHandle = arString.m_kHandle; 77 | NiGlobalStringTable::IncRefCount(kHandle); 78 | NiGlobalStringTable::DecRefCount(m_kHandle); 79 | m_kHandle = kHandle; 80 | } 81 | return *this; 82 | } 83 | 84 | NiFixedString::operator const char* () const 85 | { 86 | return m_kHandle; 87 | } 88 | 89 | NiFixedString::operator bool() const 90 | { 91 | return m_kHandle != nullptr; 92 | } 93 | 94 | const char* NiFixedString::c_str() const 95 | { 96 | return m_kHandle; 97 | } 98 | 99 | uint32_t NiFixedString::GetLength() const 100 | { 101 | return NiGlobalStringTable::GetLength(m_kHandle); 102 | } 103 | 104 | bool NiFixedString::Includes(const char* apToFind) const 105 | { 106 | if (!m_kHandle || !apToFind) 107 | return false; 108 | 109 | return strstr(m_kHandle, apToFind) != nullptr; 110 | } 111 | 112 | bool operator==(const NiFixedString& arString1, const NiFixedString& arString2) 113 | { 114 | return arString1.m_kHandle == arString2.m_kHandle; 115 | } 116 | 117 | bool operator==(const NiFixedString& arString, const char* apcString) 118 | { 119 | if (arString.m_kHandle == apcString) 120 | return true; 121 | 122 | if (!arString.m_kHandle || !apcString) 123 | return false; 124 | 125 | return !strcmp(arString.m_kHandle, apcString); 126 | } 127 | 128 | bool operator==(const char* apcString, const NiFixedString& arString) 129 | { 130 | if (arString.m_kHandle == apcString) 131 | return true; 132 | 133 | if (!arString.m_kHandle || !apcString) 134 | return false; 135 | 136 | return !strcmp(arString.m_kHandle, apcString); 137 | } 138 | -------------------------------------------------------------------------------- /nvse/nvse/OverloadsGlobal.cpp: -------------------------------------------------------------------------------- 1 | #include "Utilities.h" 2 | 3 | #if 0 4 | 5 | void* operator new(size_t size) 6 | { 7 | auto* allocation = GameHeapAlloc(size); 8 | if (allocation == nullptr) 9 | { 10 | throw std::bad_alloc(); 11 | } 12 | return allocation; 13 | } 14 | 15 | void operator delete(void* address) 16 | { 17 | GameHeapFree(address); 18 | } 19 | 20 | void* operator new[](size_t size) 21 | { 22 | auto* allocation = GameHeapAlloc(size); 23 | if (allocation == nullptr) 24 | { 25 | throw std::bad_alloc(); 26 | } 27 | return allocation; 28 | } 29 | 30 | void operator delete[](void* address) 31 | { 32 | GameHeapFree(address); 33 | } 34 | 35 | #endif -------------------------------------------------------------------------------- /nvse/nvse/SafeWrite.cpp: -------------------------------------------------------------------------------- 1 | #include "SafeWrite.h" 2 | 3 | void SafeWrite8(UInt32 addr, UInt32 data) 4 | { 5 | UInt32 oldProtect; 6 | 7 | VirtualProtect((void *)addr, 4, PAGE_EXECUTE_READWRITE, &oldProtect); 8 | *((UInt8 *)addr) = data; 9 | VirtualProtect((void *)addr, 4, oldProtect, &oldProtect); 10 | } 11 | 12 | void SafeWrite16(UInt32 addr, UInt32 data) 13 | { 14 | UInt32 oldProtect; 15 | 16 | VirtualProtect((void *)addr, 4, PAGE_EXECUTE_READWRITE, &oldProtect); 17 | *((UInt16 *)addr) = data; 18 | VirtualProtect((void *)addr, 4, oldProtect, &oldProtect); 19 | } 20 | 21 | void SafeWrite32(UInt32 addr, UInt32 data) 22 | { 23 | UInt32 oldProtect; 24 | 25 | VirtualProtect((void *)addr, 4, PAGE_EXECUTE_READWRITE, &oldProtect); 26 | *((UInt32 *)addr) = data; 27 | VirtualProtect((void *)addr, 4, oldProtect, &oldProtect); 28 | } 29 | 30 | void SafeWriteBuf(UInt32 addr, void * data, UInt32 len) 31 | { 32 | UInt32 oldProtect; 33 | 34 | VirtualProtect((void *)addr, len, PAGE_EXECUTE_READWRITE, &oldProtect); 35 | memcpy((void *)addr, data, len); 36 | VirtualProtect((void *)addr, len, oldProtect, &oldProtect); 37 | } 38 | 39 | void WriteRelJump(UInt32 jumpSrc, UInt32 jumpTgt) 40 | { 41 | // jmp rel32 42 | SafeWrite8(jumpSrc, 0xE9); 43 | SafeWrite32(jumpSrc + 1, jumpTgt - jumpSrc - 1 - 4); 44 | } 45 | 46 | void WriteRelCall(UInt32 jumpSrc, UInt32 jumpTgt) 47 | { 48 | // call rel32 49 | SafeWrite8(jumpSrc, 0xE8); 50 | SafeWrite32(jumpSrc + 1, jumpTgt - jumpSrc - 1 - 4); 51 | } 52 | 53 | void WriteRelJnz(UInt32 jumpSrc, UInt32 jumpTgt) 54 | { 55 | // jnz rel32 56 | SafeWrite16(jumpSrc, 0x850F); 57 | SafeWrite32(jumpSrc + 2, jumpTgt - jumpSrc - 2 - 4); 58 | } 59 | 60 | void WriteRelJle(UInt32 jumpSrc, UInt32 jumpTgt) 61 | { 62 | // jle rel32 63 | SafeWrite16(jumpSrc, 0x8E0F); 64 | SafeWrite32(jumpSrc + 2, jumpTgt - jumpSrc - 2 - 4); 65 | } 66 | 67 | void PatchMemoryNop(ULONG_PTR Address, SIZE_T Size) 68 | { 69 | DWORD d = 0; 70 | VirtualProtect((LPVOID)Address, Size, PAGE_EXECUTE_READWRITE, &d); 71 | 72 | for (SIZE_T i = 0; i < Size; i++) 73 | *(volatile BYTE*)(Address + i) = 0x90; //0x90 == opcode for NOP 74 | 75 | VirtualProtect((LPVOID)Address, Size, d, &d); 76 | 77 | FlushInstructionCache(GetCurrentProcess(), (LPVOID)Address, Size); 78 | } 79 | 80 | UInt32 GetRelJumpAddr(UInt32 jumpSrc) 81 | { 82 | return *(UInt32*)(jumpSrc + 1) + jumpSrc + 5; 83 | } 84 | 85 | [[nodiscard]] __declspec(noinline) UInt32 __stdcall DetourVtable(UInt32 addr, UInt32 dst) 86 | { 87 | UInt32 originalFunction = *(UInt32*)addr; 88 | SafeWrite32(addr, dst); 89 | return originalFunction; 90 | } 91 | -------------------------------------------------------------------------------- /nvse/nvse/SafeWrite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define __HOOK __declspec(naked) void 4 | 5 | void SafeWrite8(UInt32 addr, UInt32 data); 6 | void SafeWrite16(UInt32 addr, UInt32 data); 7 | void SafeWrite32(UInt32 addr, UInt32 data); 8 | void SafeWriteBuf(UInt32 addr, void * data, UInt32 len); 9 | 10 | // 5 bytes 11 | void WriteRelJump(UInt32 jumpSrc, UInt32 jumpTgt); 12 | void WriteRelCall(UInt32 jumpSrc, UInt32 jumpTgt); 13 | 14 | // 6 bytes 15 | void WriteRelJnz(UInt32 jumpSrc, UInt32 jumpTgt); 16 | void WriteRelJle(UInt32 jumpSrc, UInt32 jumpTgt); 17 | 18 | void PatchMemoryNop(ULONG_PTR Address, SIZE_T Size); 19 | 20 | template 21 | void WriteRelCall(UInt32 jumpSrc, T jumpTgt, UInt32* originalFunction = nullptr) 22 | { 23 | if (originalFunction && *reinterpret_cast(jumpSrc) == 0xE8) 24 | *originalFunction = *reinterpret_cast(jumpSrc + 1) + jumpSrc + 5; 25 | WriteRelCall(jumpSrc, UInt32(jumpTgt)); 26 | } 27 | 28 | template 29 | void WriteRelJump(UInt32 jumpSrc, T jumpTgt) 30 | { 31 | WriteRelJump(jumpSrc, (UInt32)jumpTgt); 32 | } 33 | 34 | // Credits to lStewieAl 35 | [[nodiscard]] UInt32 __stdcall DetourVtable(UInt32 addr, UInt32 dst); 36 | 37 | // From lStewieAl 38 | // Returns the address of the jump/called function, assuming there is one. 39 | UInt32 GetRelJumpAddr(UInt32 jumpSrc); 40 | 41 | // Stores the function-to-call before overwriting it, to allow calling the overwritten function after our hook is over. 42 | class CallDetour 43 | { 44 | UInt32 overwritten_addr = 0; 45 | public: 46 | void WriteRelCall(UInt32 jumpSrc, UInt32 jumpTgt) 47 | { 48 | if (*reinterpret_cast(jumpSrc) != 0xE8) { 49 | _ERROR("Cannot write detour; jumpSrc is not a function call."); 50 | return; 51 | } 52 | overwritten_addr = GetRelJumpAddr(jumpSrc); 53 | ::WriteRelCall(jumpSrc, jumpTgt); 54 | } 55 | [[nodiscard]] UInt32 GetOverwrittenAddr() const { return overwritten_addr; } 56 | }; -------------------------------------------------------------------------------- /nvse/nvse/ScriptTokenCache.cpp: -------------------------------------------------------------------------------- 1 | #include "ScriptTokenCache.h" 2 | 3 | #include 4 | 5 | TokenCacheEntry& CachedTokens::Get(std::size_t key) 6 | { 7 | return this->container_[key]; 8 | } 9 | 10 | TokenCacheEntry* CachedTokens::Append(ScriptToken* scriptToken) 11 | { 12 | return this->container_.Append(TokenCacheEntry(scriptToken)); 13 | } 14 | 15 | std::size_t CachedTokens::Size() const 16 | { 17 | return container_.Size(); 18 | } 19 | 20 | bool CachedTokens::Empty() const 21 | { 22 | return container_.Empty(); 23 | } 24 | 25 | Vector::Iterator CachedTokens::Begin() 26 | { 27 | return container_.Begin(); 28 | } 29 | 30 | TokenCacheEntry* CachedTokens::DataBegin() const 31 | { 32 | return container_.Data(); 33 | } 34 | 35 | TokenCacheEntry* CachedTokens::DataEnd() const 36 | { 37 | return container_.Data() + container_.Size(); 38 | } 39 | 40 | void CachedTokens::Clear() 41 | { 42 | for (auto iter = Begin(); !iter.End(); ++iter) 43 | { 44 | auto* token = iter.Get().token; 45 | token->cached = false; 46 | delete token; 47 | } 48 | this->container_.Clear(); 49 | } 50 | 51 | CachedTokens::~CachedTokens() 52 | { 53 | Clear(); 54 | } 55 | 56 | CachedTokens& TokenCache::Get(UInt8* key) 57 | { 58 | if (tlsClearAllCookie_ != tlsClearAllToken_) 59 | { 60 | tlsClearAllToken_ = tlsClearAllCookie_; 61 | Clear(); 62 | } 63 | return cache_[key]; 64 | } 65 | 66 | void TokenCache::Clear() 67 | { 68 | for (auto iter = cache_.Begin(); !iter.End(); ++iter) 69 | { 70 | iter.Get().Clear(); 71 | } 72 | this->cache_.Clear(); 73 | } 74 | 75 | std::size_t TokenCache::Size() const 76 | { 77 | return cache_.Size(); 78 | } 79 | 80 | bool TokenCache::Empty() const 81 | { 82 | return cache_.Empty(); 83 | } 84 | 85 | void TokenCache::MarkForClear() 86 | { 87 | // Required since cache is thread_local and needs to be cleared on each thread 88 | ++tlsClearAllCookie_; 89 | } 90 | 91 | std::atomic TokenCache::tlsClearAllCookie_ = 0; 92 | thread_local int TokenCache::tlsClearAllToken_ = 0; 93 | 94 | ScriptTokenCacheFormExtraData* ScriptTokenCacheFormExtraData::Create() 95 | { 96 | auto* item = New(); 97 | new(item) ScriptTokenCacheFormExtraData(); 98 | return item; 99 | } 100 | 101 | NiFixedString& ScriptTokenCacheFormExtraData::GetName() 102 | { 103 | static NiFixedString name = "ScriptTokenCacheFormExtraData"; 104 | return name; 105 | } 106 | 107 | ScriptTokenCacheFormExtraData* ScriptTokenCacheFormExtraData::Get(Script* script) 108 | { 109 | if (auto* existing = FormExtraData::Get(script, GetName())) 110 | { 111 | return static_cast(existing); 112 | } 113 | auto* data = Create(); 114 | FormExtraData::Add(script, GetName(), data); 115 | return data; 116 | } 117 | -------------------------------------------------------------------------------- /nvse/nvse/ScriptTokenCache.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "containers.h" 3 | #include "ScriptTokens.h" 4 | #include 5 | #include "FormExtraData.h" 6 | 7 | 8 | struct TokenCacheEntry 9 | { 10 | ScriptToken* token; 11 | Op_Eval eval; 12 | bool swapOrder; 13 | 14 | TokenCacheEntry(ScriptToken* scriptToken) : token(scriptToken), eval(nullptr), swapOrder(false) {} 15 | }; 16 | 17 | class CachedTokens 18 | { 19 | Vector container_; 20 | public: 21 | std::size_t incrementData; 22 | [[nodiscard]] TokenCacheEntry& Get(std::size_t key); 23 | TokenCacheEntry* Append(ScriptToken* scriptToken); 24 | [[nodiscard]] std::size_t Size() const; 25 | [[nodiscard]] bool Empty() const; 26 | Vector::Iterator Begin(); 27 | [[nodiscard]] TokenCacheEntry *DataBegin() const; 28 | [[nodiscard]] TokenCacheEntry *DataEnd() const; 29 | void Clear(); 30 | ~CachedTokens(); 31 | }; 32 | 33 | class TokenCache 34 | { 35 | UnorderedMap cache_; 36 | static std::atomic tlsClearAllCookie_; 37 | static thread_local int tlsClearAllToken_; 38 | public: 39 | CachedTokens& Get(UInt8* key); 40 | void Clear(); 41 | [[nodiscard]] std::size_t Size() const; 42 | [[nodiscard]] bool Empty() const; 43 | static void MarkForClear(); 44 | }; 45 | 46 | class ScriptTokenCacheFormExtraData : public FormExtraData 47 | { 48 | public: 49 | virtual ~ScriptTokenCacheFormExtraData() override = default; 50 | 51 | TokenCache cache; 52 | 53 | static ScriptTokenCacheFormExtraData* Create(); 54 | static ScriptTokenCacheFormExtraData* Get(Script* script); 55 | static NiFixedString& GetName(); 56 | }; -------------------------------------------------------------------------------- /nvse/nvse/SmallObjectsAllocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "MemoryPool.h" 4 | #include "common/ICriticalSection.h" 5 | #include 6 | #include 7 | 8 | #if _DEBUG 9 | void Console_Print(const char*, ...); 10 | #endif 11 | 12 | namespace SmallObjectsAllocator 13 | { 14 | template 15 | class LockBasedAllocator 16 | { 17 | #if _DEBUG 18 | std::size_t count_ = 0; 19 | #else 20 | MemoryPool pool_; 21 | #endif 22 | ICriticalSection criticalSection_; 23 | 24 | void Free(T* ptr) 25 | { 26 | #if _DEBUG 27 | ::operator delete(ptr); 28 | #else 29 | pool_.deallocate(ptr); 30 | #endif 31 | } 32 | 33 | public: 34 | T* Allocate() 35 | { 36 | ScopedLock lock(criticalSection_); 37 | #if _DEBUG 38 | ++count_; 39 | if (count_ > C * 10) 40 | { 41 | Console_Print("Warning, possible memory leak"); 42 | } 43 | 44 | return static_cast(operator new(sizeof(T))); 45 | #else 46 | return pool_.allocate(); 47 | #endif 48 | } 49 | 50 | void Free(void* ptr) 51 | { 52 | 53 | ScopedLock lock(criticalSection_); 54 | Free(static_cast(ptr)); 55 | #if _DEBUG 56 | --count_; 57 | #endif 58 | } 59 | }; 60 | 61 | template 62 | class FastAllocator 63 | { 64 | #define TRACK_ALLOCATIONS 0 65 | #if _DEBUG 66 | std::size_t count_ = 0; 67 | 68 | struct MemLeakDebugInfo 69 | { 70 | T* t; 71 | std::vector stack; 72 | }; 73 | #if TRACK_ALLOCATIONS 74 | std::list allocatedBlocks_; 75 | #endif 76 | #endif 77 | using MemPool = MemoryPool; 78 | MemPool pool_; 79 | 80 | public: 81 | T* Allocate() 82 | { 83 | #if _DEBUG 84 | ++count_; 85 | if (count_ > C * 10) 86 | { 87 | Console_Print("Warning, possible memory leak"); 88 | } 89 | auto* alloc = static_cast(operator new(sizeof(T))); 90 | #if TRACK_ALLOCATIONS 91 | UInt32 trace[12] = { 0 }; 92 | CaptureStackBackTrace(0, 12, reinterpret_cast(trace), nullptr); 93 | std::vector vecTrace(trace, trace + 12); 94 | 95 | MemLeakDebugInfo info{ alloc, vecTrace }; 96 | allocatedBlocks_.push_back(info); 97 | #endif 98 | return alloc; 99 | #else 100 | return pool_.allocate(); 101 | #endif 102 | } 103 | 104 | void Free(void* ptr) 105 | { 106 | #if _DEBUG 107 | --count_; 108 | #if TRACK_ALLOCATIONS 109 | allocatedBlocks_.remove_if([ptr](auto& info) {return info.t == ptr; }); 110 | #endif 111 | ::operator delete(ptr); 112 | #else 113 | pool_.deallocate(static_cast(ptr)); 114 | #endif 115 | } 116 | }; 117 | } 118 | -------------------------------------------------------------------------------- /nvse/nvse/StackVariables.cpp: -------------------------------------------------------------------------------- 1 | #include "StackVariables.h" 2 | 3 | #if RUNTIME 4 | #include "ScriptTokens.h" 5 | 6 | // Useful so that the slow eventList->GetVariable doesn't have to be called again. 7 | // Returns false for an invalid variable, or if non-stack-variable couldn't be resolved. 8 | 9 | [[nodiscard]] 10 | bool VariableStorage::ResolveVariable(ScriptEventList* eventList, ScriptLocal*& out_resolvedLocal) const { 11 | if (!IsValid()) [[unlikely]] { 12 | return false; 13 | } 14 | if (m_varIdx == 0) [[unlikely]] { 15 | // stack variable index of 0 is invalid. 16 | return false; 17 | } 18 | 19 | out_resolvedLocal = eventList->GetVariable(m_varIdx); 20 | if (!out_resolvedLocal) [[unlikely]] { 21 | return false; 22 | } 23 | 24 | return true; 25 | } 26 | 27 | bool VariableStorage::AssignToArray(UInt32 arrID, ScriptEventList* eventList, ScriptLocal* resolvedLocal) 28 | { 29 | ScriptLocal* var = resolvedLocal ? resolvedLocal : eventList->GetVariable(m_varIdx); 30 | if (!var) [[unlikely]] { 31 | return false; 32 | } 33 | g_ArrayMap.AddReference(&var->data, arrID, eventList->m_script->GetModIndex()); 34 | AddToGarbageCollection(eventList, var, NVSEVarType::kVarType_Array); 35 | return true; 36 | } 37 | 38 | bool VariableStorage::AssignToString(const char* str, ScriptEventList* eventList, bool tempForLocal, ScriptLocal* resolvedLocal) 39 | { 40 | ScriptLocal* var = resolvedLocal ? resolvedLocal : eventList->GetVariable(m_varIdx); 41 | if (!var) [[unlikely]] { 42 | return false; 43 | } 44 | var->data = g_StringMap.Add(eventList->m_script->GetModIndex(), str, tempForLocal); 45 | AddToGarbageCollection(eventList, var, NVSEVarType::kVarType_String); 46 | return true; 47 | } 48 | 49 | double* VariableStorage::GetValuePtr(ScriptEventList* eventList, ScriptLocal* resolvedLocal) { 50 | ScriptLocal* var = resolvedLocal ? resolvedLocal : eventList->GetVariable(m_varIdx); 51 | if (!var) [[unlikely]] { 52 | return nullptr; 53 | } 54 | return &var->data; 55 | } 56 | 57 | std::string VariableStorage::GetVariableName(ScriptEventList* eventList, ScriptLocal* resolvedLocal) 58 | { 59 | ScriptLocal* var = resolvedLocal ? resolvedLocal : eventList->GetVariable(m_varIdx); 60 | if (!var) [[unlikely]] { 61 | return FormatString("", m_varIdx); 62 | } 63 | return std::string(::GetVariableName(var, eventList->m_script, eventList)); 64 | } 65 | 66 | VarCache *g_scriptVarCache[16] {}; 67 | thread_local int g_threadID = -1; 68 | std::atomic g_nextThreadID = 0; 69 | #endif 70 | -------------------------------------------------------------------------------- /nvse/nvse/StackVariables.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "GameAPI.h" 7 | #include "GameScript.h" 8 | 9 | #ifdef RUNTIME 10 | 11 | struct VarCache { 12 | std::mutex mt; 13 | std::unordered_map> varCache; 14 | 15 | void put(ScriptEventList* eventList, ScriptLocal* local) { 16 | varCache[eventList][local->id] = local; 17 | } 18 | 19 | ScriptLocal *get(ScriptEventList* eventList, UInt32 id) { 20 | auto entry = varCache[eventList]; 21 | 22 | if (const auto find = entry.find(id); find != entry.end()) { 23 | return find->second; 24 | } 25 | 26 | return nullptr; 27 | } 28 | 29 | void clear(ScriptEventList* eventList) { 30 | varCache[eventList] = {}; 31 | } 32 | }; 33 | 34 | extern VarCache* g_scriptVarCache[]; 35 | extern thread_local int g_threadID; 36 | extern std::atomic g_nextThreadID; 37 | 38 | // Utility struct 39 | struct Variable { 40 | ScriptLocal* var{}; 41 | Script::VariableType type = Script::eVarType_Invalid; 42 | 43 | [[nodiscard]] bool IsValid() const { 44 | return var != nullptr; 45 | } 46 | 47 | [[nodiscard]] Script::VariableType GetType() const { 48 | return type; 49 | } 50 | 51 | // Could check isStackVar, but we assume that was already checked. 52 | [[nodiscard]] ScriptLocal* GetScriptLocal() const 53 | { 54 | return var; 55 | } 56 | 57 | Variable() = default; 58 | Variable(ScriptLocal* _local, Script::VariableType _varType) : type(_varType) 59 | { 60 | var = _local; 61 | } 62 | }; 63 | #endif 64 | 65 | // Utility struct 66 | // More suited for long storage, as ScriptLocal pointers can become invalid when loading, according to Kormakur. 67 | struct VariableStorage { 68 | int m_varIdx = -1; 69 | Script::VariableType m_type = Script::eVarType_Invalid; 70 | 71 | [[nodiscard]] bool IsValid() const { return (m_varIdx != -1) && (m_type != Script::eVarType_Invalid); } 72 | [[nodiscard]] Script::VariableType GetType() const { return m_type; } 73 | 74 | // Useful so that the slow eventList->GetVariable doesn't have to be called again. 75 | // Returns false for an invalid variable, or if non-stack-variable couldn't be resolved. 76 | [[nodiscard]] bool ResolveVariable(ScriptEventList* eventList, ScriptLocal*& out_resolvedLocal) const; 77 | 78 | bool AssignToArray(UInt32 arrID, ScriptEventList* eventList, ScriptLocal* resolvedLocal = nullptr); 79 | bool AssignToString(const char* str, ScriptEventList* eventList, bool tempForLocal, ScriptLocal* resolvedLocal = nullptr); 80 | double* GetValuePtr(ScriptEventList* eventList, ScriptLocal* resolvedLocal = nullptr); 81 | std::string GetVariableName(ScriptEventList* eventList, ScriptLocal* resolvedLocal = nullptr); 82 | 83 | VariableStorage() = default; 84 | VariableStorage(UInt32 _varIdx, Script::VariableType _varType) 85 | : m_varIdx(_varIdx), m_type(_varType) 86 | {} 87 | }; 88 | 89 | using UserFunctionParam = VariableStorage; -------------------------------------------------------------------------------- /nvse/nvse/StackVector.h: -------------------------------------------------------------------------------- 1 | // Stack based vector - credits: https://stackify.dev/482135-stack-buffer-based-stl-allocator 2 | #pragma once 3 | 4 | template 5 | class bumping_memory_resource { 6 | public: 7 | char* _ptr; 8 | char buffer[Size]; 9 | 10 | explicit bumping_memory_resource() 11 | : _ptr(&buffer[0]) {} 12 | 13 | void* allocate(std::size_t size) noexcept { 14 | auto ret = _ptr; 15 | _ptr += size; 16 | return ret; 17 | } 18 | 19 | void deallocate(void*) noexcept {} 20 | }; 21 | 22 | template > 23 | class bumping_allocator { 24 | public: 25 | Resource* _res; 26 | 27 | using value_type = T; 28 | 29 | bumping_allocator() {} 30 | 31 | explicit bumping_allocator(Resource& res) 32 | : _res(&res) {} 33 | 34 | bumping_allocator(const bumping_allocator&) = default; 35 | template 36 | bumping_allocator(const bumping_allocator& other) 37 | : bumping_allocator(other.resource()) {} 38 | 39 | Resource& resource() const { return *_res; } 40 | 41 | T* allocate(std::size_t n) { return static_cast(_res->allocate(sizeof(T) * n)); } 42 | void deallocate(T* ptr, std::size_t) { _res->deallocate(ptr); } 43 | 44 | friend bool operator==(const bumping_allocator& lhs, const bumping_allocator& rhs) { 45 | return lhs._res == rhs._res; 46 | } 47 | 48 | friend bool operator!=(const bumping_allocator& lhs, const bumping_allocator& rhs) { 49 | return lhs._res != rhs._res; 50 | } 51 | }; 52 | 53 | template 54 | class StackVector 55 | { 56 | using InternalVector = std::vector>>; 57 | bumping_memory_resource resource_; 58 | bumping_allocator> allocator_; 59 | InternalVector internalVector_; 60 | public: 61 | StackVector() : allocator_(resource_), internalVector_(allocator_) 62 | { 63 | internalVector_.reserve(Size); 64 | } 65 | 66 | StackVector(const StackVector& other) : 67 | allocator_(resource_), 68 | internalVector_(other.internalVector_, allocator_) 69 | {} 70 | 71 | StackVector& operator=(const StackVector& other) 72 | { 73 | if (this == &other) 74 | return *this; 75 | resource_._ptr = resource_.buffer; 76 | internalVector_ = std::vector(other.internalVector_, allocator_); 77 | return *this; 78 | } 79 | 80 | InternalVector* operator->() { return &internalVector_; } 81 | const InternalVector* operator->() const { return &internalVector_; } 82 | 83 | InternalVector& operator*() { return internalVector_; } 84 | const InternalVector& operator*() const { return internalVector_; } 85 | }; 86 | 87 | template 88 | StackVector Filter(S& s, F&& f) 89 | { 90 | StackVector vec; 91 | for (auto& i : s) 92 | { 93 | if (f(i)) 94 | vec->emplace_back(&i); 95 | } 96 | return vec; 97 | } -------------------------------------------------------------------------------- /nvse/nvse/ThreadLocal.cpp: -------------------------------------------------------------------------------- 1 | #include "ThreadLocal.h" 2 | #include "nvse/SafeWrite.h" 3 | #include "FunctionScripts.h" 4 | #include "Loops.h" 5 | 6 | static const UInt32 kBackgroundLoaderThreadHookAddr = 0x0047CF3E; 7 | 8 | void __stdcall HandleThreadExit() 9 | { 10 | // when thread exits, free singleton objects in thread local storage 11 | 12 | ThreadLocalData* data = ThreadLocalData::TryGet(); 13 | if (data) 14 | { 15 | if (data->expressionEvaluator) 16 | _WARNING("Game thread exiting with non-empty ExpressionEvaluator stack"); 17 | 18 | delete data->userFunctionManager; 19 | delete data->loopManager; 20 | 21 | 22 | // free memory allocated for this thread's data 23 | delete data; 24 | } 25 | } 26 | 27 | static __declspec(naked) void BackgroundLoaderThreadHook(void) 28 | { 29 | __asm { 30 | pushad 31 | call HandleThreadExit 32 | popad 33 | 34 | // overwritten code 35 | retn 4 36 | } 37 | } 38 | 39 | ThreadLocalData::ThreadLocalData(): expressionEvaluator(NULL), userFunctionManager(NULL), loopManager(NULL) 40 | { 41 | // 42 | } 43 | 44 | ThreadLocalData& ThreadLocalData::Get() 45 | { 46 | ThreadLocalData* data = TryGet(); 47 | if (!data) 48 | { 49 | data = new ThreadLocalData(); 50 | const auto result = TlsSetValue(s_tlsIndex, data); 51 | ASSERT_STR(result, "TlsSetValue() failed in ThreadLocalData::Get()"); 52 | } 53 | 54 | return *data; 55 | } 56 | 57 | ThreadLocalData* ThreadLocalData::TryGet() 58 | { 59 | return static_cast(TlsGetValue(s_tlsIndex)); 60 | } 61 | 62 | void ThreadLocalData::Init() 63 | { 64 | s_tlsIndex = TlsAlloc(); 65 | ASSERT_STR(s_tlsIndex != 0xFFFFFFFF, "TlsAlloc() failed in ThreadLocalData::Init()"); 66 | 67 | // hook BackgroundLoaderThread threadProc retn 68 | // WriteRelJump(kBackgroundLoaderThreadHookAddr, (UInt32)&BackgroundLoaderThreadHook); 69 | } 70 | 71 | void ThreadLocalData::DeInit() 72 | { 73 | if (s_tlsIndex != 0xFFFFFFFF) { 74 | TlsFree(s_tlsIndex); 75 | s_tlsIndex = 0xFFFFFFFF; 76 | } 77 | } 78 | 79 | DWORD ThreadLocalData::s_tlsIndex = 0xFFFFFFFF; 80 | -------------------------------------------------------------------------------- /nvse/nvse/ThreadLocal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ScriptTokenCache.h" 4 | #include "common/ICriticalSection.h" 5 | 6 | class ExpressionEvaluator; 7 | class UserFunctionManager; 8 | class LoopManager; 9 | 10 | /* added v0020 to clean up the way we handle scripts executing in parallel */ 11 | 12 | struct ThreadLocalData 13 | { 14 | ExpressionEvaluator* expressionEvaluator; // evaluator at top of expression stack 15 | UserFunctionManager* userFunctionManager; // per-thread singleton 16 | LoopManager* loopManager; // per-thread singleton 17 | 18 | ThreadLocalData(); 19 | 20 | // get data for current thread, creating if it doesn't exist yet 21 | static ThreadLocalData& Get(); 22 | 23 | // get for current thread if data exists 24 | static ThreadLocalData* TryGet(); 25 | 26 | static void Init(); 27 | static void DeInit(); 28 | 29 | private: 30 | static DWORD s_tlsIndex; 31 | }; 32 | -------------------------------------------------------------------------------- /nvse/nvse/UnitTests.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if RUNTIME 4 | 5 | void ExecuteRuntimeUnitTests(); 6 | 7 | #endif -------------------------------------------------------------------------------- /nvse/nvse/commands_Algohol.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "nvse/CommandTable.h" 4 | #include "algohol/paramTypes.h" 5 | 6 | DEFINE_CMD_ALT(V3Length, v3len, returns length of given vector3, 0, 3, kParams_Vector3Floats); 7 | DEFINE_CMD_ALT(V3Normalize, v3norm, returns normalized vector3, 0, 6, kParams_Vector3Strings3Floats); 8 | // DEFINE_CMD_ALT(V3Dotproduct, v3dprod, returns dotproduct of two vectors, 0, 9, kParams_Vector6Floats); 9 | DEFINE_CMD_ALT(V3Crossproduct, v3xprod, returns crossproduct of two vectors, 0, 9, kParams_Vector3Strings6Floats); 10 | 11 | DEFINE_CMD_ALT(QFromEuler, qfrome, converts euler angles to quaternion. optional flag indicates if the angles came from an actor, 0, 8, kParams_QuatEuler4Strings3Floats1Int); 12 | DEFINE_CMD_ALT(QFromAxisAngle, qfromaa, converts axis-angle rotation to quaternion, 0, 8, kParams_QuatAxisAngle4Strings4Floats); 13 | DEFINE_CMD_ALT(QNormalize, qnorm, returns normalized quaternion, 0, 8, kParams_Quat4Strings4Floats); 14 | DEFINE_CMD_ALT(QMultQuatQuat, qmultq, multiplies two quaternions, 0, 12, kParams_Quat4Strings8Floats); 15 | DEFINE_CMD_ALT(QMultQuatVector3, qmultv3, multiplies vector3 by quaternion, 0, 10, kParams_VectorQuatVector3Strings7Floats); 16 | DEFINE_CMD_ALT(QInterpolate, qint, interpolates between two quaternions; default method is normalized linear interpolation. optional flag indicates spherical linear interpolation, 0, 17 | 14, kParams_Quat4Strings9Floats1Int); 18 | DEFINE_CMD_ALT(QToEuler, qtoe, converts quaternion to euler angles. optional flag indicates the output will be used for rotating an actor, 0, 8, kParams_EulerQuat3Strings4Floats1Int); 19 | -------------------------------------------------------------------------------- /nvse/nvse/exports.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | StartNVSE -------------------------------------------------------------------------------- /nvse/nvse/nvse_version.h: -------------------------------------------------------------------------------- 1 | #ifndef __NVSE_VERSION_H__ 2 | #define __NVSE_VERSION_H__ 3 | 4 | // these have to be macros so they can be used in the .rc 5 | #define ALPHA_MODE 0 6 | #define NVSE_VERSION_INTEGER 6 7 | #define NVSE_VERSION_INTEGER_MINOR 3 8 | #define NVSE_VERSION_INTEGER_BETA 11 9 | #define NVSE_VERSION_VERSTRING "0, 6, 3, 11" 10 | #define NVSE_VERSION_PADDEDSTRING "0006" 11 | 12 | // build numbers do not appear to follow the same format as with oblivion 13 | #define MAKE_NEW_VEGAS_VERSION_EX(major, minor, build, sub) (((major & 0xFF) << 24) | ((minor & 0xFF) << 16) | ((build & 0xFFF) << 4) | (sub & 0xF)) 14 | #define MAKE_NEW_VEGAS_VERSION(major, minor, build) MAKE_NEW_VEGAS_VERSION_EX(major, minor, build, 0) 15 | 16 | // assume the major version number is 1.x 17 | #define RUNTIME_VERSION_1_0_0_240 MAKE_NEW_VEGAS_VERSION(0, 0, 240) // 0x00000F00 18 | #define RUNTIME_VERSION_1_1_0_240 MAKE_NEW_VEGAS_VERSION(1, 0, 268) // 0x010010C0 19 | #define RUNTIME_VERSION_1_1_1_271 MAKE_NEW_VEGAS_VERSION(1, 1, 271) // 0x010110F0 20 | #define RUNTIME_VERSION_1_1_1_280 MAKE_NEW_VEGAS_VERSION(1, 1, 280) // 0x01011180 21 | #define RUNTIME_VERSION_1_2_0_285 MAKE_NEW_VEGAS_VERSION(2, 0, 285) // 0x020011D0 22 | #define RUNTIME_VERSION_1_2_0_314 MAKE_NEW_VEGAS_VERSION(2, 0, 314) // 0x020013A0 23 | #define RUNTIME_VERSION_1_2_0_352 MAKE_NEW_VEGAS_VERSION(2, 0, 352) // 0x02001600 24 | #define RUNTIME_VERSION_1_3_0_452 MAKE_NEW_VEGAS_VERSION(3, 0, 452) // 0x03001C40 25 | #define RUNTIME_VERSION_1_4_0_525 MAKE_NEW_VEGAS_VERSION(4, 0, 525) // 0x040020D0 26 | #define RUNTIME_VERSION_1_4_0_525ng MAKE_NEW_VEGAS_VERSION_EX(4, 0, 525, 1) // 0x040020D1 27 | 28 | #define CS_VERSION_1_1_0_262 MAKE_NEW_VEGAS_VERSION(1, 0, 262) // 0x01001060 29 | #define CS_VERSION_1_3_0_452 MAKE_NEW_VEGAS_VERSION(3, 0, 452) // 0x03001C40 30 | #define CS_VERSION_1_4_0_518 MAKE_NEW_VEGAS_VERSION(4, 0, 518) // 0x04002060 31 | 32 | #define PACKED_NVSE_VERSION MAKE_NEW_VEGAS_VERSION(NVSE_VERSION_INTEGER, NVSE_VERSION_INTEGER_MINOR, NVSE_VERSION_INTEGER_BETA) 33 | 34 | 35 | 36 | #endif /* __NVSE_VERSION_H__ */ 37 | -------------------------------------------------------------------------------- /nvse/nvse/nvse_version.rc: -------------------------------------------------------------------------------- 1 | #include "nvse_version.h" 2 | 3 | 1 VERSIONINFO 4 | FILEVERSION 0,NVSE_VERSION_INTEGER,NVSE_VERSION_INTEGER_MINOR,NVSE_VERSION_INTEGER_BETA 5 | PRODUCTVERSION 0,NVSE_VERSION_INTEGER,NVSE_VERSION_INTEGER_MINOR,NVSE_VERSION_INTEGER_BETA 6 | FILEFLAGSMASK 0x17L 7 | #ifdef _DEBUG 8 | FILEFLAGS 0x1L 9 | #else 10 | FILEFLAGS 0x0L 11 | #endif 12 | FILEOS 0x4L 13 | FILETYPE 0x1L 14 | FILESUBTYPE 0x0L 15 | BEGIN 16 | BLOCK "StringFileInfo" 17 | BEGIN 18 | BLOCK "040904b0" 19 | BEGIN 20 | VALUE "FileDescription", "A component of the New Vegas Script Extender" 21 | VALUE "FileVersion", NVSE_VERSION_VERSTRING 22 | VALUE "InternalName", "NVSE" 23 | VALUE "LegalCopyright", "Copyright (C) 2006-2011" 24 | VALUE "ProductName", "NVSE" 25 | VALUE "ProductVersion", NVSE_VERSION_VERSTRING 26 | END 27 | END 28 | BLOCK "VarFileInfo" 29 | BEGIN 30 | VALUE "Translation", 0x409, 1200 31 | END 32 | END 33 | -------------------------------------------------------------------------------- /nvse/nvse/prefix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "common/IPrefix.h" 4 | #include "nvse/nvse_version.h" 5 | #include "nvse/utility.h" 6 | #include "nvse/containers.h" 7 | -------------------------------------------------------------------------------- /nvse/nvse/rewrites.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/new_compiler/call_test.txt: -------------------------------------------------------------------------------- 1 | name CallTest; 2 | 3 | fn () { 4 | string testName = "'Call...' Commands"; 5 | print(("Started running xNVSE " + testName + " unit tests.")); 6 | 7 | ref TestUDF = CompileScript("../unit_tests/new_compiler/udfs/TestUDF.txt"); 8 | assert(IsFormValid(TestUDF)); 9 | 10 | // Simple testing value 11 | ref playerBaseForm = PlayerREF.GetBaseForm(); 12 | assert(IsFormValid(playerBaseForm)); 13 | 14 | // Test UDF calls 15 | ref result = call(TestUDF, PlayerREF.GetBaseForm()); 16 | assert(playerBaseForm == result); 17 | 18 | // Test lambda call 19 | ref rLambda = fn (ref rRef) { 20 | return rRef; 21 | }; 22 | result = call(rLambda, PlayerREF.GetBaseForm()); 23 | assert(playerBaseForm == result); 24 | 25 | print(("Finished running xNVSE " + testName + " unit tests.")); 26 | } -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/new_compiler/comments.txt: -------------------------------------------------------------------------------- 1 | name comments; 2 | 3 | fn () { 4 | string testName = "Comments"; 5 | print(("Started running xNVSE " + testName + " unit tests.")); 6 | 7 | string test = "/* */"; 8 | assert(test == "/* */"); 9 | assert(sv_length(test) == 5); 10 | 11 | test = "//"; 12 | assert(test == "//"); 13 | 14 | /* 15 | test = "2"; 16 | */ 17 | assert(test == "//"); 18 | 19 | // test = "2"; 20 | assert(test == "//"); 21 | 22 | /* */ test = "2"; /* test = "3"; */ // test = "4"; 23 | assert(test == "2"); 24 | 25 | /* // */ test = "3"/**//**//**/;//; 26 | assert(test == "3"); 27 | 28 | test = "blah"; 29 | assert(sv_length(/*test*/test) == 4); 30 | 31 | print(("Finished running xNVSE " + testName + " unit tests.")); 32 | } -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/new_compiler/disabled/in_operator_syntax.txt: -------------------------------------------------------------------------------- 1 | name inops; 2 | 3 | fn () { 4 | string testName = "In Operator"; 5 | print(("Started running xNVSE " + testName + " unit tests.")); 6 | 7 | assert(1 in [1,2]); 8 | assert(2 in [1,2]); 9 | assert(!(3 in [1,2])); 10 | assert(3 in [1,2,3]); 11 | 12 | int i = 0; 13 | array testArr = Ar_List(1,2,3); 14 | for ([array cur] in testArr) { 15 | if (*cur == 0) { 16 | assert(!(*cur in [1,2,3])); 17 | continue; 18 | } 19 | 20 | assert(*cur in [1,2,3]); 21 | } 22 | 23 | print(("Finished running xNVSE " + testName + " unit tests.")); 24 | } -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/new_compiler/for_loops.txt: -------------------------------------------------------------------------------- 1 | name ForLoops; 2 | 3 | fn () { 4 | string testName = "ForLoops"; 5 | print(("Started running xNVSE " + testName + " unit tests.")); 6 | 7 | //== Test ForEachAlt syntax 8 | 9 | //==== Test packed array looping 10 | array aList = [Player, Player, Player]; 11 | int iTest = 0; 12 | 13 | for ([int iKey, ref rValue] in aList) 14 | { 15 | assert(iKey == iTest); 16 | assert(rValue == Player); 17 | iTest++; 18 | } 19 | assert(iTest == (ar_size(aList))); 20 | 21 | iTest = 0; 22 | for ([int iKey, _] in aList) 23 | { 24 | assert(iKey == iTest); 25 | iTest++; 26 | } 27 | assert(iTest == (ar_size(aList))); 28 | 29 | iTest = 0; 30 | for ([int key, ref rValue] in aList) 31 | { 32 | assert(rValue == Player); 33 | iTest++; 34 | } 35 | assert(iTest == (ar_size(aList))); 36 | 37 | iTest = 0; 38 | for ([ref rValue] in aList) 39 | { 40 | assert(rValue == Player); 41 | iTest++; 42 | } 43 | assert(iTest == (ar_size(aList))); 44 | 45 | //==== Test map array looping 46 | 47 | array aMap = {"key1"::Player, "key2"::Player, "key3"::Player}; 48 | assert(TypeOf(aMap) == "StringMap"); 49 | 50 | string sBaseKeyStr = "key"; 51 | string sKeyStr; 52 | iTest = 0; 53 | ref rTest; 54 | for ([string sKey, ref rValue] in aMap) 55 | { 56 | iTest++; 57 | sKeyStr = sBaseKeyStr + $(iTest); 58 | assert(sKeyStr == sKey); 59 | assert(rValue == Player); 60 | rTest = rValue; 61 | } 62 | assert(iTest == (ar_size(aMap))); 63 | assert(sKeyStr == "key3"); 64 | assert(rTest == player); 65 | 66 | rTest = 0; 67 | iTest = 0; 68 | for ([_, ref rValue] in aMap) 69 | { 70 | iTest++; 71 | sKeyStr = sBaseKeyStr + $(iTest); 72 | assert(rValue == Player); 73 | rTest = rValue; 74 | } 75 | assert(iTest == (ar_size(aMap))); 76 | assert(rTest == player); 77 | assert(sKeyStr == "key3"); 78 | 79 | rTest = 0; 80 | iTest = 0; 81 | sKeyStr = ""; 82 | for ([string sKey] in aMap) 83 | { 84 | iTest++; 85 | sKeyStr = sBaseKeyStr + $(iTest); 86 | assert(sKeyStr == sKey); 87 | ref rValue = aMap[sKey]; 88 | assert(rValue == Player); 89 | rTest = rValue; 90 | } 91 | assert(iTest == (ar_size(aMap))); 92 | assert(rTest == player); 93 | assert(sKeyStr == "key3"); 94 | 95 | rTest = 0; 96 | iTest = 0; 97 | sKeyStr = ""; 98 | for ([string sKey] in aMap) 99 | { 100 | iTest++; 101 | sKeyStr = sBaseKeyStr + $(iTest); 102 | assert(sKeyStr == sKey); 103 | ref rValue = aMap[sKey]; 104 | assert(rValue == Player); 105 | rTest = rValue; 106 | } 107 | assert(iTest == (ar_size(aMap))); 108 | assert(rTest == player); 109 | assert(sKeyStr == "key3"); 110 | 111 | print(("Finished running xNVSE " + testName + " unit tests.")); 112 | 113 | } -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/new_compiler/foreachalt.txt: -------------------------------------------------------------------------------- 1 | name foreachalt; 2 | 3 | fn () { 4 | string testName = "ForEachAlt"; 5 | print(("Started running xNVSE ${testName} unit tests.")); 6 | 7 | array testArr = {1::"Hello", 2::"World"}; 8 | for ([int key, string val] in testArr) { 9 | if (key == 1) { 10 | assert(val == "Hello"); 11 | } else if (key == 2) { 12 | assert(val == "World"); 13 | } else { 14 | assert(false); 15 | } 16 | } 17 | 18 | print(("Finished running xNVSE ${testName} unit tests.")); 19 | } -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/new_compiler/misc.txt: -------------------------------------------------------------------------------- 1 | name miscexprs; 2 | 3 | fn () { 4 | string testName = "Misc."; 5 | print(("Started running xNVSE " + testName + " unit tests.")); 6 | 7 | // Just making sure some things compile that should 8 | ar_foreach(GetRefs(200), fn (array iter) -> print((*iter).GetName())); 9 | 10 | // Test in expressions 11 | array test = [1,2,3]; 12 | Assert(1 in test); 13 | Assert(2 in test); 14 | Assert(3 in test); 15 | Assert(4 not in test); 16 | 17 | test = {"Hello"::1, "World"::2}; 18 | Assert("Hello" in test); 19 | Assert("World" in test); 20 | Assert("Foobar" not in test); 21 | test["Foobar"] = 3; 22 | Assert("Foobar" in test); 23 | 24 | print(("Finished running xNVSE " + testName + " unit tests.")); 25 | } -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/new_compiler/stack_vars.txt: -------------------------------------------------------------------------------- 1 | name stackVars; 2 | 3 | fn () { 4 | print(("Started running xNVSE stack variable unit tests.")); 5 | 6 | // Test numeric types 7 | int i = 10; 8 | assert(i == 10); 9 | i = 20; 10 | assert(i == 20); 11 | 12 | for (int i = 0; i < 10; i++) { 13 | assert(i != 20); 14 | } 15 | 16 | assert(i == 20); 17 | 18 | // Test arrays 19 | array arr1 = [1,2,3,4]; 20 | assert(ar_size(arr1) == 4); 21 | arr1[0] = 10; 22 | assert(arr1[0] == 10); 23 | ar_append(arr1, 20); 24 | assert(ar_size(arr1) == 5); 25 | assert(arr1[4] == 20); 26 | i = 30; 27 | assert(i == 30); 28 | arr1[0] = i; 29 | assert(arr1[0] == 30); 30 | assert(arr1[0] == i); 31 | 32 | // Test references 33 | ref ref1 = player; 34 | assert(ref1 == player); 35 | ref1 = caps001; 36 | assert(ref1 == caps001); 37 | 38 | arr1 = [player, caps001]; 39 | assert(arr1[0] == player); 40 | assert(arr1[1] == caps001); 41 | 42 | // Test strings 43 | string str1 = "Hello"; 44 | assert(str1 == "Hello"); 45 | str1 = "World"; 46 | assert(str1 == "World"); 47 | str1 = "Hello World"; 48 | assert(str1 == "Hello World"); 49 | 50 | print(("Finished running xNVSE stack variable unit tests.")); 51 | } -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/new_compiler/ternary_operations.txt: -------------------------------------------------------------------------------- 1 | name ternary; 2 | 3 | fn () { 4 | string testName = "Ternary Operations"; 5 | print(("Started running xNVSE " + testName + " unit tests.")); 6 | 7 | int condition = false; 8 | int iTest = condition ? 1 : 2; 9 | assert(iTest == 2); 10 | 11 | condition = true; 12 | iTest = condition ? 1 : 2; 13 | assert(iTest == 1); 14 | 15 | // Make sure that ternary conditions / args do not get cached 16 | for (int i = 0; i < 2; i++) { 17 | condition = i % 2 == 0; 18 | if (i == 0) { 19 | assert(condition == true); 20 | } else { 21 | assert(condition == false); 22 | } 23 | 24 | assert((condition ? 0 : 1) == i); 25 | } 26 | 27 | print(("Finished running xNVSE " + testName + " unit tests.")); 28 | } 29 | -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/new_compiler/udfs/TestUDF.txt: -------------------------------------------------------------------------------- 1 | name TestUDF; 2 | 3 | fn (ref rRef) { 4 | return rRef; 5 | } -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/new_compiler/unary_operations.txt: -------------------------------------------------------------------------------- 1 | name unary; 2 | 3 | fn () { 4 | 5 | string testName = "Unary Operations"; 6 | print(("Started running xNVSE " + testName + " unit tests.")); 7 | 8 | // Increment/decrement by 1 9 | int i = 0; 10 | assert(i++ == 0); // incrementation should happen after the check occurs 11 | assert(i-- == 1); 12 | assert(i == 0); 13 | 14 | // Stringize/ Numericize 15 | string testStr = "123"; 16 | i = #testStr; 17 | assert(i == 123); 18 | testStr = "test"; 19 | testStr = $i; 20 | assert(testStr == "123"); 21 | 22 | // Box / Unbox 23 | array aTest = &1; 24 | assert(aTest == (ar_List(1))); 25 | i = *aTest; 26 | assert(i == 1); 27 | i = 2; // reset, just in case 28 | i = aTest[0]; // Subscript 29 | assert(i == 1); 30 | 31 | // Subscript for strings 32 | testStr = "123"; 33 | assert(testStr[0] == "1"); 34 | 35 | // Logical Not 36 | assert(!false); 37 | 38 | print(("Finished running xNVSE " + testName + " unit tests.")); 39 | } -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/old_compiler/CallAfterFrames.txt: -------------------------------------------------------------------------------- 1 | begin Function { } 2 | 3 | print "Started running xNVSE CallAfterFrames unit tests." 4 | 5 | int iCount = 0 6 | CallAfterFrames 2 ({} => assert (iCount += 1) == 2) 1 7 | CallAfterFrames 1 ({} => assert (iCount += 1) == 1) 1 8 | 9 | 10 | ref rFinalUDF = (begin Function{} 11 | assert (iCount += 1) == 3 12 | print "Finished running xNVSE CallAfterFrames unit tests." 13 | end) 14 | 15 | CallAfterFrames 3 rFinalUDF 1 16 | 17 | end -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/old_compiler/TestExpr.txt: -------------------------------------------------------------------------------- 1 | begin Function { } 2 | 3 | print "Started running xNVSE TestExpr unit tests." 4 | 5 | ref rOnHitUDF = ({ref rFirst, ref rSecond} => print "ran") 6 | 7 | Assert (TestExpr (SetEventHandlerAlt "OnHit" rOnHitUDF 0::"badFilter")) == 0 ; error should occur 8 | 9 | ; Test assignement inside TestExpr statement 10 | int iTest 11 | Assert (TestExpr (iTest := SetEventHandlerAlt "OnHit" rOnHitUDF 0::"badFilter")) == 0 12 | 13 | ; Test with boxing operator 14 | array_var aTest 15 | Assert (TestExpr (aTest := &(SetEventHandlerAlt "OnHit" rOnHitUDF 0::"badFilter"))) == 0 16 | 17 | Assert (Ar_Size (GetEventHandlers "OnHit" rOnHitUDF 1)) == 0 18 | 19 | ; Test array bounds-checking 20 | aTest = Ar_Null ;invalid array 21 | Assert (TestExpr (aTest[0])) == 0 ;invalid array index access 22 | 23 | aTest = ar_List 5 24 | Assert (TestExpr (aTest[0])) == 1 25 | 26 | aTest = ar_List (ar_list 5) (ar_List 3) 27 | Assert (TestExpr (aTest[0][0])) == 1 28 | Assert (TestExpr (aTest[1][0])) == 1 29 | Assert (TestExpr (aTest[0][1])) == 0 30 | Assert (TestExpr (aTest[1][1])) == 0 31 | 32 | 33 | ; Test division by 0 34 | Assert (TestExpr (1 / 0)) == 0 35 | Assert (TestExpr (1 / 2)) == 1 36 | 37 | 38 | ; Test unbox operator 39 | Assert (TestExpr (iTest = *(ar_list 1))) == 1 40 | Assert iTest == 1 41 | 42 | Assert (TestExpr (iTest = *(ar_list SunnyREF))) == 0 ;assigning ref to int 43 | Assert (TestExpr (iTest = *(ar_list (ar_List 1)))) == 0 44 | Assert (TestExpr (iTest = *(ar_list "test"))) == 0 45 | 46 | 47 | ; Test function call with an invalid reference 48 | ref rTest = 0 49 | Assert (TestExpr (rTest.GetAV Health)) == 0 50 | rTest = player 51 | Assert (TestExpr (rTest.GetAV Health)) == 1 52 | rTest = GSSunnySmiles ; baseform 53 | Assert (TestExpr (rTest.GetAV Health)) == 0 54 | 55 | ; Ensure variables don't get assigned to anything if expression failed. 56 | iTest = 0 57 | Assert (TestExpr iTest = (ar_list 1)[2]) == 0 58 | assert (iTest == 0) 59 | 60 | iTest = 5 61 | Assert (TestExpr iTest = (ar_list 1)[2]) == 0 62 | assert (iTest == 5) 63 | 64 | iTest = 10 65 | Assert (TestExpr (iTest = *(ar_list SunnyREF))) == 0 66 | assert (iTest == 10) 67 | 68 | 69 | print "Finished running xNVSE TestExpr unit tests." 70 | 71 | end -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/old_compiler/array_functions.txt: -------------------------------------------------------------------------------- 1 | begin Function { } 2 | print "Started running xNVSE Array Unit Tests." 3 | 4 | ; === Test array functions === 5 | array_var aVar = ar_list 1 2 3 4 6 | ar_Erase aVar 7 | Assert (ar_Size aVar) == 0 8 | 9 | aVar = ar_list 1 2 3 4 10 | Assert ((ar_Size aVar) == 4) 11 | 12 | ar_append aVar 5 13 | Assert ((ar_Size aVar) == 5) 14 | Assert (aVar == (Ar_List 1 2 3 4 5)) 15 | Assert ((aVar[0]) == 1) 16 | Assert ((aVar[4]) == 5) 17 | 18 | ar_erase avar 0:5 19 | Assert ((ar_Size aVar) == 0) 20 | Assert !(testexpr aVar[0]) 21 | Assert !(testexpr aVar[4]) 22 | 23 | aVar = ar_list 1 2 3 24 | ar_erase avar 0 25 | Assert (aVar == (ar_list 2 3)) 26 | 27 | ar_resize avar 1 28 | Assert (avar == (ar_list 2)) 29 | 30 | ar_insertRange avar 0 (ar_list 0 1) 31 | Assert (avar == (ar_list 0 1 2)) 32 | 33 | aVar = ar_list 1 2 2 3 3 3 4 4 4 4 34 | Assert ((Ar_Count aVar 1) == 1) 35 | Assert ((Ar_Count aVar 2) == 2) 36 | Assert ((Ar_Count aVar 3) == 3) 37 | Assert ((Ar_Count aVar 4) == 4) 38 | 39 | Assert ((ar_CountWhere aVar ({array_var aIter} => *aIter == 1)) == 1) 40 | Assert ((ar_CountWhere aVar ({array_var aIter} => *aIter == 2)) == 2) 41 | Assert ((ar_CountWhere aVar ({array_var aIter} => *aIter == 3)) == 3) 42 | Assert ((ar_CountWhere aVar ({array_var aIter} => *aIter == 4)) == 4) 43 | 44 | Assert ((ar_GetNth aVar 0) == 1) 45 | Assert ((ar_GetNth aVar 1) == 2) 46 | Assert ((ar_GetNth aVar 2) == 3) 47 | Assert ((ar_GetNth aVar 3) == 4) 48 | 49 | print "Finished running xNVSE Array Unit Tests." 50 | end -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/old_compiler/conversions_between_num_and_string.txt: -------------------------------------------------------------------------------- 1 | begin Function { } 2 | 3 | print "Started running xNVSE Num-String Conversion Unit Tests." 4 | 5 | ;== Num-To-HexString tests 6 | string_var sHexOld = NumToHex_OLD 42, 2 7 | string_var sHexNew = NumToHex 42, 2 8 | assert (sHexOld == sHexNew) 9 | 10 | ; Using default width of 8 11 | sHexOld = NumToHex_OLD 42 12 | sHexNew = NumToHex 42 13 | assert (sHexOld == sHexNew) 14 | assert (sHexOld == "0000002A") 15 | 16 | ;* Trying to go over max width of 8 17 | sHexOld = NumToHex_OLD 42, 9 18 | sHexNew = NumToHex 42, 9 19 | assert (sHexOld == sHexNew) 20 | assert (sv_length sHexOld == 8) 21 | 22 | ;* Trying to represent "2A" with just width 1 23 | ;* Will use minimum width to represent the number. 24 | sHexOld = NumToHex_OLD 42, 1 25 | sHexNew = NumToHex 42, 1 26 | assert (sHexOld == sHexNew) 27 | assert (sHexOld == "2A") 28 | assert (sv_length sHexOld == 2) 29 | 30 | sHexNew = NumToHex 42, 2, 1 31 | assert (sHexNew == "0x2A") 32 | 33 | sHexNew = NumToHex 42, 3, 1 34 | assert (sHexNew == "0x02A") 35 | 36 | ;== Num-To-Binary tests 37 | string_var sBinary = IntToBin 42 38 | assert (sBinary == "00000000000000000000000000101010") ;* Padded to 32 bits by default 39 | 40 | ;* Trying to represent "101010" with just 2 bits 41 | ;* Will use minimum width to represent the number. 42 | sBinary = IntToBin 42, 2 43 | assert (sBinary == "101010") 44 | 45 | sBinary = IntToBin 42, 10, 1 46 | assert (sBinary == "0b0000101010") 47 | 48 | sBinary = IntToBin 42, 6, 1 49 | assert (sBinary == "0b101010") 50 | 51 | 52 | print "Finished running xNVSE Num-String Conversion Unit Tests." 53 | 54 | end -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/old_compiler/let_macro.txt: -------------------------------------------------------------------------------- 1 | begin Function { } 2 | 3 | print "Starting xNVSE let macro unit tests." 4 | 5 | short iTest1 6 | iTest1 = 1 7 | assert (iTest1 == 1) 8 | 9 | long iTest2 10 | iTest2 = 2 11 | assert (iTest2 == 2) 12 | 13 | int iTest3 14 | iTest3 = 3 15 | assert (iTest3 == 3) 16 | 17 | 18 | ;== Test mid-script variable declaration + assignement with let macro 19 | 20 | short iTest4 = 4 21 | assert (iTest4 == 4) 22 | 23 | long iTest5 = 5 24 | assert (iTest5 == 5) 25 | 26 | int iTest6 = 6 27 | assert (iTest6 == 6) 28 | 29 | 30 | ;== Test having an inline expression and using array [] operator 31 | 32 | array_var aTest = ar_Init 5 0 ; create array with 5 0s 33 | aTest[(Rand 1, 2)] = 1 ; should generate 1 every time 34 | assert (aTest[1] == 1) 35 | 36 | ref rReturnAdd = ({ int iArg0, int iArg1 } => iArg0 + iArg1) 37 | aTest[(call rReturnAdd 1, 2)] = 1 38 | assert (aTest[3] == 1) 39 | 40 | ; Test for stringmaps 41 | array_var aTest2 := Ar_Map "Nemesis"::1, "Saviour"::2, "Bestie"::3 42 | int iTest7 = aTest2["Nemesis"] 43 | assert (iTest7 == 1) 44 | int iTest8 := aTest2["Saviour"] 45 | assert (iTest8 == 2) 46 | 47 | aTest2["Saviour"] = aTest2["Bestie"] 48 | assert (aTest2["Saviour"] == 3) 49 | 50 | ;== Test other operators for let macro (-=, +=, etc.) 51 | short iTest9 = 3 52 | iTest9 -= 1 53 | assert (iTest9 == 2) 54 | iTest9 += 2 55 | assert (iTest9 == 4) 56 | 57 | 58 | ;== Test multiple assignments in one line 59 | array_var aTest3 = ar_list 1, 2 60 | array_var aTest4 = ar_list 2, 3 61 | aTest3 = aTest4 = ar_Null 62 | assert (aTest3 == ar_Null) 63 | assert (aTest4 == ar_Null) 64 | 65 | aTest3 = ar_list 1, 2 66 | aTest4 = ar_list 2, 3 67 | aTest3 = aTest4 = (call (begin Function{} 68 | SetFunctionValue ar_Null 69 | end)) 70 | assert (aTest3 == ar_Null) 71 | assert (aTest4 == ar_Null) 72 | 73 | print "Finished xNVSE let macro unit tests." 74 | 75 | 76 | end -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/old_compiler/multi_arg_command_trailing_boundary.txt: -------------------------------------------------------------------------------- 1 | Begin Function {} 2 | 3 | print "Started running xNVSE Multi-arg command trailing comparison operator tests." 4 | 5 | let array_var testArr := Ar_List 2 6 | 7 | ; Prior state parse: if eval Ar_Find 1 (testArr != ar_BadNumericIndex) 8 | ; New state parse: if (eval Ar_Find 1 testArr) != ar_BadNumericIndex 9 | Assert Ar_Find 2 testArr != ar_BadNumericIndex 10 | 11 | ; Prior state parse: if eval Ar_Find 1 (testArr == ar_BadNumericIndex) 12 | ; New state parse: if (eval Ar_Find 1 testArr) == ar_BadNumericIndex 13 | Assert Ar_Find 1 testArr == ar_BadNumericIndex 14 | 15 | ; Prior state parse: if eval Ar_Find 4 (testArr == ar_BadNumericIndex) 16 | ; New state parse: if (eval Ar_Find 4 testArr) == ar_BadNumericIndex 17 | Assert Ar_Find 4 testArr || (1 == 1) 18 | 19 | ; Lambda test 20 | let ref rTestLambda := (Begin Function {int a1, string_var a2} 21 | SetFunctionValue 1 22 | End) 23 | 24 | ; Prior state parse: if Call rTestLambda 1 ("test" == 1) 25 | ; New state parse: If (Call rTestLambda 1 "test") == 1 26 | Assert Call rTestLambda 1 "test" == 1 27 | 28 | print "Finished running xNVSE Multi-arg command trailing comparison operator tests." 29 | 30 | End -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/old_compiler/multiple_variable_declarations_macro.txt: -------------------------------------------------------------------------------- 1 | begin Function { } 2 | ;== Test comma-separated variable declarations 3 | 4 | print "Starting xNVSE multiple variable declarations macro." 5 | 6 | short iTest1, iTest2, iTest3 7 | 8 | iTest1 = 1 9 | assert (iTest1 == 1) 10 | 11 | iTest2 = 2 12 | assert (iTest2 == 2) 13 | 14 | iTest3 = 3 15 | assert (iTest3 == 3) 16 | 17 | long iTest4, iTest5 18 | 19 | iTest4 = 4 20 | assert (iTest4 == 4) 21 | 22 | iTest5 = 5 23 | assert (iTest5 == 5) 24 | 25 | print "Finished xNVSE multiple variable declarations macro." 26 | 27 | end -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/old_compiler/short_and_long_param_types_in_UDF.txt: -------------------------------------------------------------------------------- 1 | begin Function { } 2 | 3 | print "Starting xNVSE UDF tests for short and long param types." 4 | 5 | int iRan = 0 6 | let ref rTestUDF = (begin function { short iTest1, long iTest2 } 7 | assert (iTest1 == 1) 8 | assert (iTest2 == 2) 9 | iRan = 1 10 | end) 11 | 12 | call rTestUDF 1, 2 13 | assert (iRan == 1) 14 | 15 | print "Finished xNVSE UDF tests for short and long param types." 16 | 17 | end -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/old_compiler/strings_and_parentheses.txt: -------------------------------------------------------------------------------- 1 | begin Function { } 2 | 3 | print "Started running xNVSE Parentheses & Strings unit tests." 4 | 5 | string_var myString = "test(" 6 | 7 | let myString := ")(test(" 8 | 9 | Assert (sv_Find ")(" myString) > -1 10 | 11 | Assert eval sv_Find ")(" myString > -1 12 | 13 | Assert sv_Find ")" myString > -1 14 | 15 | Assert ((sv_Find ")" myString > -1)) 16 | 17 | Assert eval sv_Find ")" myString > -1 18 | 19 | if eval sv_Find "(" myString > -1 20 | Assert 1 21 | else 22 | assert 0 23 | endif 24 | 25 | print "Finished running xNVSE Parentheses & Strings unit tests." 26 | 27 | end -------------------------------------------------------------------------------- /nvse/nvse/unit_tests/old_compiler/udf_functions.txt: -------------------------------------------------------------------------------- 1 | begin Function { } 2 | 3 | int iArg = 0 4 | 5 | 6 | ; === Test lambda and UDF functions === 7 | 8 | CallAfter 0 (begin function{ iArg, float fArg, string_var sArg, array_var aArg } 9 | Assert iArg == 10 10 | Assert fArg == 5.5 11 | Assert sArg == "Hello World" 12 | Assert aArg == (ar_list 1 5 10) 13 | end) 1 10 5.5 "Hello World" (ar_list 1 5 10) 14 | 15 | ref TestUdfScript = (begin function{ int iArg0, float fArg0, string_var sArg0, array_var aArg0 } 16 | Assert iArg0 == 2 17 | Assert fArg0 == 3.5 18 | Assert sArg0 == "Jingle Bells" 19 | Assert aArg0 == (ar_map "Key"::"Value") 20 | end) 21 | 22 | call TestUdfScript 2 3.5 "Jingle Bells" (ar_map "Key"::"Value") 23 | 24 | ref TestUdfScript2 = ({ int iArg0, int iArg1 } => iArg0 + iArg1) 25 | 26 | ; test Call on array element 27 | array_Var aVar = ar_list TestUdfScript2 28 | int iResult = call aVar[0] 5 5 29 | Assert iResult == 10 30 | 31 | ; test Call on function that returns script 32 | SetModLocalData "Func" TestUdfScript2 33 | int iResult2 = call(GetModLocalData "Func") 10 10 34 | Assert iResult2 == 20 35 | 36 | ; test Call on inline lambda 37 | int iResult3 = call ({ int iArg0 } => iArg0) 98 38 | Assert iResult3 == 98 39 | 40 | print "Finished running xNVSE UDF and Lambda Unit Tests." 41 | 42 | end -------------------------------------------------------------------------------- /nvse/nvse_loader/Inject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "loader_common/IdentifyEXE.h" 4 | 5 | bool DoInjectDLL(PROCESS_INFORMATION * info, const char * dllPath, ProcHookInfo * hookInfo); 6 | -------------------------------------------------------------------------------- /nvse/nvse_loader/Options.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class Options 5 | { 6 | public: 7 | Options(); 8 | ~Options(); 9 | 10 | bool Read(int argc, char ** argv); 11 | 12 | void PrintUsage(void); 13 | 14 | bool m_launchCS; 15 | 16 | bool m_setPriority; 17 | DWORD m_priority; 18 | 19 | bool m_optionsOnly; 20 | bool m_crcOnly; 21 | bool m_waitForClose; 22 | bool m_verbose; 23 | bool m_moduleInfo; 24 | bool m_skipLauncher; 25 | 26 | UInt32 m_fpsLimit; 27 | 28 | std::string m_altEXE; 29 | std::string m_altDLL; 30 | 31 | UInt32 m_appID; 32 | 33 | private: 34 | bool Verify(void); 35 | }; 36 | 37 | extern Options g_options; 38 | -------------------------------------------------------------------------------- /nvse/nvse_loader/nvse_loader.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xNVSE/NVSE/fd8ddd9d15e7f63a0144b80574229cf6badc05a7/nvse/nvse_loader/nvse_loader.ico -------------------------------------------------------------------------------- /nvse/nvse_loader/resources.rc: -------------------------------------------------------------------------------- 1 | #ifndef _resource_rc 2 | #define _resource_rc 3 | 4 | MAINICON ICON "nvse_loader.ico" 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /nvse/steam_loader/PluginPreload.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "loader_common/PluginChecker.h" 4 | 5 | typedef bool (*_NVSEPlugin_Preload)(); 6 | 7 | void PreloadPlugins() { 8 | char folderPath[MAX_PATH]; 9 | GetCurrentDirectory(MAX_PATH, folderPath); 10 | strcat_s(folderPath, "\\Data\\NVSE\\Plugins"); 11 | 12 | _MESSAGE("Preloading plugins from %s", folderPath); 13 | 14 | WIN32_FIND_DATA findData; 15 | HANDLE find = INVALID_HANDLE_VALUE; 16 | char searchPath[MAX_PATH]; 17 | sprintf_s(searchPath, "%s\\*.dll", folderPath); 18 | find = FindFirstFile(searchPath, &findData); 19 | 20 | if (find == INVALID_HANDLE_VALUE) { 21 | _ERROR("Failed to find any plugins!"); 22 | return; 23 | } 24 | 25 | do { 26 | if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 27 | continue; 28 | 29 | if (!IsNVSEPreloadPlugin(findData.cFileName, folderPath)) 30 | continue; 31 | 32 | // Load the plugin for real 33 | char pluginPath[MAX_PATH]; 34 | sprintf_s(pluginPath, "%s\\%s", folderPath, findData.cFileName); 35 | _DMESSAGE("Loading \"%s\"", pluginPath); 36 | HMODULE module = LoadLibrary(pluginPath); 37 | if (!module) { 38 | _DMESSAGE("Failed to load \"%s\"", findData.cFileName); 39 | continue; 40 | } 41 | 42 | _NVSEPlugin_Preload preload = (_NVSEPlugin_Preload)GetProcAddress(module, "NVSEPlugin_Preload"); 43 | if (!preload) { 44 | _DMESSAGE("Failed to get NVSEPlugin_Preload for \"%s\"", findData.cFileName); 45 | continue; 46 | } 47 | 48 | _MESSAGE("Preloading \"%s\"", findData.cFileName); 49 | preload(); 50 | 51 | } while (FindNextFile(find, &findData)); 52 | } -------------------------------------------------------------------------------- /nvse/steam_loader/steam_loader.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {501bec05-fcd9-4e27-a5d3-eae8cbc74daf} 6 | 7 | 8 | {efa8cf44-717b-4697-84c1-af05852c7cd1} 9 | 10 | 11 | 12 | 13 | nvse 14 | 15 | 16 | nvse 17 | 18 | 19 | hooks 20 | 21 | 22 | 23 | nvse 24 | 25 | 26 | nvse 27 | 28 | 29 | 30 | 31 | nvse 32 | 33 | 34 | nvse 35 | 36 | 37 | hooks 38 | 39 | 40 | nvse 41 | 42 | 43 | nvse 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /nvse_plugin_example/dllmain.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | BOOL WINAPI DllMain( 4 | HANDLE hDllHandle, 5 | DWORD dwReason, 6 | LPVOID lpreserved 7 | ) 8 | { 9 | return TRUE; 10 | } 11 | -------------------------------------------------------------------------------- /nvse_plugin_example/exports.def: -------------------------------------------------------------------------------- 1 | LIBRARY "nvse_plugin_example" 2 | EXPORTS 3 | NVSEPlugin_Query 4 | NVSEPlugin_Load 5 | -------------------------------------------------------------------------------- /nvse_plugin_example/fn_typed_functions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | DEFINE_COMMAND_PLUGIN(ExamplePlugin_ReturnForm, "Returns the form that was given.", false, kParams_OneForm) 4 | 5 | #if RUNTIME 6 | bool Cmd_ExamplePlugin_ReturnForm_Execute(COMMAND_ARGS) 7 | { 8 | *result = 0; 9 | TESForm* form; 10 | 11 | /* 12 | * We will return the form's refID as the result. 13 | * To this end, we have to cast "result" as a UInt32* register, 14 | * since the Ref datatype assumes that the data is UInt32. 15 | */ 16 | 17 | if (ExtractArgsEx(EXTRACT_ARGS_EX, &form)) 18 | *(UInt32*)result = form->refID; 19 | 20 | return true; 21 | } 22 | #endif 23 | 24 | 25 | DEFINE_COMMAND_PLUGIN(ExamplePlugin_ReturnString, "Returns the string that was given.", false, kParams_OneString) 26 | 27 | #if RUNTIME 28 | bool Cmd_ExamplePlugin_ReturnString_Execute(COMMAND_ARGS) 29 | { 30 | *result = 0; 31 | 32 | // Have to specify the expected size of the string and allocate that much space. 33 | char stringBuffer[0x80]; 34 | 35 | if (ExtractArgsEx(EXTRACT_ARGS_EX, &stringBuffer)) 36 | g_stringInterface->Assign(PASS_COMMAND_ARGS, stringBuffer); 37 | 38 | // Note that the Assign function handles setting "result" on its own. 39 | 40 | return true; 41 | } 42 | #endif 43 | 44 | // Define a parameter to interpret an int as an array, since a plugin cannot accept an array-type argument yet. 45 | static ParamInfo kParams_OneArray[1] = 46 | { 47 | { "array", kParamType_Integer, 0 }, 48 | }; 49 | 50 | // Shorthand aliases. 51 | #if RUNTIME 52 | using NVSEArrayVar = NVSEArrayVarInterface::Array; 53 | using NVSEArrayElement = NVSEArrayVarInterface::Element; 54 | #endif 55 | 56 | DEFINE_COMMAND_PLUGIN(ExamplePlugin_ReturnArray, "Returns the array that was given.", false, kParams_OneArray) 57 | 58 | #if RUNTIME 59 | bool Cmd_ExamplePlugin_ReturnArray_Execute(COMMAND_ARGS) 60 | { 61 | *result = 0; 62 | UInt32 arrID; 63 | 64 | if (ExtractArgsEx(EXTRACT_ARGS_EX, &arrID)) 65 | { 66 | NVSEArrayVar* srcArray = g_arrayInterface->LookupArrayByID(arrID); 67 | g_arrayInterface->AssignCommandResult(srcArray, result); 68 | } 69 | 70 | return true; 71 | } 72 | #endif -------------------------------------------------------------------------------- /nvse_plugin_example/nvse_plugin_example.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29025.244 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nvse_plugin_example", "nvse_plugin_example.vcxproj", "{AE7CFEE7-4058-4E3C-ADC2-AE7480EE2028}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common_vc9", "..\common\common_vc9.vcxproj", "{20C6411C-596F-4B85-BE4E-8BC91F59D8A6}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug GECK|Win32 = Debug GECK|Win32 13 | Debug|Win32 = Debug|Win32 14 | Release GECK|Win32 = Release GECK|Win32 15 | Release|Win32 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {AE7CFEE7-4058-4E3C-ADC2-AE7480EE2028}.Debug GECK|Win32.ActiveCfg = Debug GECK|Win32 19 | {AE7CFEE7-4058-4E3C-ADC2-AE7480EE2028}.Debug GECK|Win32.Build.0 = Debug GECK|Win32 20 | {AE7CFEE7-4058-4E3C-ADC2-AE7480EE2028}.Debug|Win32.ActiveCfg = Debug|Win32 21 | {AE7CFEE7-4058-4E3C-ADC2-AE7480EE2028}.Debug|Win32.Build.0 = Debug|Win32 22 | {AE7CFEE7-4058-4E3C-ADC2-AE7480EE2028}.Release GECK|Win32.ActiveCfg = Release GECK|Win32 23 | {AE7CFEE7-4058-4E3C-ADC2-AE7480EE2028}.Release GECK|Win32.Build.0 = Release GECK|Win32 24 | {AE7CFEE7-4058-4E3C-ADC2-AE7480EE2028}.Release|Win32.ActiveCfg = Release|Win32 25 | {AE7CFEE7-4058-4E3C-ADC2-AE7480EE2028}.Release|Win32.Build.0 = Release|Win32 26 | {20C6411C-596F-4B85-BE4E-8BC91F59D8A6}.Debug GECK|Win32.ActiveCfg = Debug GECK|Win32 27 | {20C6411C-596F-4B85-BE4E-8BC91F59D8A6}.Debug GECK|Win32.Build.0 = Debug GECK|Win32 28 | {20C6411C-596F-4B85-BE4E-8BC91F59D8A6}.Debug|Win32.ActiveCfg = Debug|Win32 29 | {20C6411C-596F-4B85-BE4E-8BC91F59D8A6}.Debug|Win32.Build.0 = Debug|Win32 30 | {20C6411C-596F-4B85-BE4E-8BC91F59D8A6}.Release GECK|Win32.ActiveCfg = Release GECK|Win32 31 | {20C6411C-596F-4B85-BE4E-8BC91F59D8A6}.Release GECK|Win32.Build.0 = Release GECK|Win32 32 | {20C6411C-596F-4B85-BE4E-8BC91F59D8A6}.Release|Win32.ActiveCfg = Release|Win32 33 | {20C6411C-596F-4B85-BE4E-8BC91F59D8A6}.Release|Win32.Build.0 = Release|Win32 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {71BF81C1-7B0B-49CB-92D7-5D7E4612E20C} 40 | EndGlobalSection 41 | EndGlobal 42 | --------------------------------------------------------------------------------