Browse Source

added hot code reloading

vlod 3 years ago
parent
commit
a3a2916d30

+ 76 - 7
Pika/core/pikaRuntime/dllLoader/dllLoader.cpp

@@ -1,5 +1,6 @@
 #include "dllLoader.h"
 #include "dllLoader.h"
 #include "pikaConfig.h"
 #include "pikaConfig.h"
+#include <assert/assert.h>
 
 
 #ifdef PIKA_DEVELOPMENT
 #ifdef PIKA_DEVELOPMENT
 
 
@@ -10,25 +11,49 @@
 	#include <Windows.h>
 	#include <Windows.h>
 	
 	
 	
 	
-	static HMODULE dllHand;
+
+	static FILETIME getLastWriteFile(const char *name)
+	{
+		FILETIME time = {};
+
+		WIN32_FILE_ATTRIBUTE_DATA Data = {};
+		if (GetFileAttributesEx(name, GetFileExInfoStandard, &Data))
+		{
+			time = Data.ftLastWriteTime;
+		}
+		else
+		{
+			PIKA_PERMA_ASSERT(0, "Couldn't get file time");
+		}
+
+		return(time);
+	}
 
 
 	//todo error reporting with strings
 	//todo error reporting with strings
 	bool pika::DllLoader::loadDll(std::filesystem::path path)
 	bool pika::DllLoader::loadDll(std::filesystem::path path)
 	{
 	{
-		path /= "pikaGameplay.dll";
+		p = path;
+
+		std::filesystem::path originalDll = path / "pikaGameplay.dll";
+		std::filesystem::path copyDll = path / "pikaGameplayCopy.dll";
+
+		filetime = getLastWriteFile(originalDll.string().c_str());
+
 
 
-		dllHand = LoadLibraryA(path.string().c_str());
+		std::filesystem::copy(originalDll, copyDll, std::filesystem::copy_options::overwrite_existing);
+
+		dllHand = LoadLibraryA(copyDll.string().c_str());
 
 
 		if (!dllHand) { return false; }
 		if (!dllHand) { return false; }
 
 
 		gameplayStart_ = (gameplayStart_t *)GetProcAddress(dllHand, "gameplayStart");
 		gameplayStart_ = (gameplayStart_t *)GetProcAddress(dllHand, "gameplayStart");
-		gameplayUpdate_ = (gameplayUpdate_t *)GetProcAddress(dllHand, "gameplayUpdate");
+		gameplayReload_ = (gameplayReload_t *)GetProcAddress(dllHand, "gameplayReload");
 		getContainersInfo_ = (getContainersInfo_t *)GetProcAddress(dllHand, "getContainersInfo");
 		getContainersInfo_ = (getContainersInfo_t *)GetProcAddress(dllHand, "getContainersInfo");
 		constructContainer_ = (constructContainer_t *)GetProcAddress(dllHand, "constructContainer");
 		constructContainer_ = (constructContainer_t *)GetProcAddress(dllHand, "constructContainer");
 		destructContainer_ = (destructContainer_t *)GetProcAddress(dllHand, "destructContainer");
 		destructContainer_ = (destructContainer_t *)GetProcAddress(dllHand, "destructContainer");
 
 
 		if (!gameplayStart_) { return false; }
 		if (!gameplayStart_) { return false; }
-		if (!gameplayUpdate_) { return false; }
+		if (!gameplayReload_) { return false; }
 		if (!getContainersInfo_) { return false; }
 		if (!getContainersInfo_) { return false; }
 		if (!constructContainer_) { return false; }
 		if (!constructContainer_) { return false; }
 		if (!destructContainer_) { return false; }
 		if (!destructContainer_) { return false; }
@@ -36,6 +61,40 @@
 		return	true;
 		return	true;
 	}
 	}
 	
 	
+	void pika::DllLoader::unloadDll()
+	{
+		FreeLibrary(dllHand);
+	}
+
+	bool pika::DllLoader::reloadDll()
+	{
+		std::filesystem::path originalDll = p / "pikaGameplay.dll";
+		std::filesystem::path copyDll = p / "pikaGameplayCopy.dll";
+
+		FILETIME newFiletime = getLastWriteFile(originalDll.string().c_str());
+
+		if (CompareFileTime(&filetime, &newFiletime) != 0)
+		{
+
+			unloadDll();
+			
+			HANDLE fileCheck;
+			while ((fileCheck = CreateFile(originalDll.string().c_str(),
+				GENERIC_READ | GENERIC_WRITE, NULL, NULL,
+				OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
+			{
+				//Wait till the dll can be oppened. It is possible that the compiler still keeps it busy.
+			}
+			CloseHandle(fileCheck);
+			
+			//try to load
+			while (!loadDll(p)) {};
+
+			return true;
+		}
+
+		return false;
+	}
 	
 	
 	#else
 	#else
 	#error "pika load dll works only on windows."
 	#error "pika load dll works only on windows."
@@ -50,7 +109,7 @@
 	{
 	{
 		
 		
 		gameplayStart_ = gameplayStart;
 		gameplayStart_ = gameplayStart;
-		gameplayUpdate_ = gameplayUpdate;
+		gameplayReload_ = gameplayReload;
 		getContainersInfo_ = getContainersInfo;
 		getContainersInfo_ = getContainersInfo;
 		constructContainer_ = constructContainer;
 		constructContainer_ = constructContainer;
 		destructContainer_ = destructContainer;
 		destructContainer_ = destructContainer;
@@ -58,7 +117,15 @@
 		return	true;
 		return	true;
 	}
 	}
 
 
-	
+	bool pika::DllLoader::reloadDll()
+	{
+		return false;
+	}
+
+	void pika::DllLoader::unloadDll()
+	{
+	}
+
 
 
 #endif
 #endif
 
 
@@ -66,3 +133,5 @@
 	{
 	{
 		constructContainer_(&c.pointer, &c.arena, name);
 		constructContainer_(&c.pointer, &c.arena, name);
 	}
 	}
+
+	

+ 17 - 5
Pika/core/pikaRuntime/dllLoader/dllLoader.h

@@ -13,9 +13,9 @@
 typedef GAMEPLAYSTART(gameplayStart_t);
 typedef GAMEPLAYSTART(gameplayStart_t);
 #undef GAMEPLAYSTART
 #undef GAMEPLAYSTART
 
 
-#define GAMEPLAYUPDATE(x) void x(pika::PikaContext pikaContext)
-typedef GAMEPLAYUPDATE(gameplayUpdate_t);
-#undef GAMEPLAYUPDATE
+#define GAMEPLAYRELOAD(x) void x(pika::PikaContext pikaContext)
+typedef GAMEPLAYRELOAD(gameplayReload_t);
+#undef GAMEPLAYRELOAD
 
 
 #define GETCONTAINERSINFO(x) void x(std::vector<ContainerInformation> &info)
 #define GETCONTAINERSINFO(x) void x(std::vector<ContainerInformation> &info)
 typedef GETCONTAINERSINFO(getContainersInfo_t);
 typedef GETCONTAINERSINFO(getContainersInfo_t);
@@ -30,7 +30,10 @@ typedef CONSTRUCTCONTAINER(constructContainer_t);
 typedef DESTRUCTCONTAINER(destructContainer_t);
 typedef DESTRUCTCONTAINER(destructContainer_t);
 #undef DESTRUCTCONTAINER
 #undef DESTRUCTCONTAINER
 
 
-
+//todo remove windows include 
+#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
 
 
 namespace pika
 namespace pika
 {
 {
@@ -39,14 +42,23 @@ namespace pika
 struct DllLoader
 struct DllLoader
 {
 {
 	gameplayStart_t *gameplayStart_ = {};
 	gameplayStart_t *gameplayStart_ = {};
-	gameplayUpdate_t *gameplayUpdate_ = {};
+	gameplayReload_t *gameplayReload_ = {};
 	getContainersInfo_t *getContainersInfo_ = {};
 	getContainersInfo_t *getContainersInfo_ = {};
 	constructContainer_t *constructContainer_ = {};
 	constructContainer_t *constructContainer_ = {};
 	destructContainer_t *destructContainer_ = {};
 	destructContainer_t *destructContainer_ = {};
 
 
+	std::filesystem::path p = {};
+	FILETIME filetime = {};
+	HMODULE dllHand = {};
+
 	bool loadDll(std::filesystem::path path);
 	bool loadDll(std::filesystem::path path);
 	void constructRuntimeContainer(RuntimeContainer &c, const char *name);
 	void constructRuntimeContainer(RuntimeContainer &c, const char *name);
 
 
+	void unloadDll();
+
+	//will check if the dll reloaded and reload it
+	bool reloadDll();
+
 };
 };
 
 
 
 

+ 6 - 3
Pika/core/pikaRuntime/pikaMain.cpp

@@ -45,9 +45,6 @@ int main()
 
 
 
 
 
 
-
-
-
 	RuntimeContainer container;
 	RuntimeContainer container;
 	container.arena.allocateStaticMemory(loadedContainers[0]);
 	container.arena.allocateStaticMemory(loadedContainers[0]);
 
 
@@ -57,6 +54,12 @@ int main()
 	while (!window.shouldClose())
 	while (!window.shouldClose())
 	{
 	{
 
 
+		if (dllLoader.reloadDll())
+		{
+			dllLoader.gameplayReload_(window.context);
+		}
+
+
 		glClear(GL_COLOR_BUFFER_BIT);
 		glClear(GL_COLOR_BUFFER_BIT);
 
 
 		pika::imguiStartFrame(window.context);
 		pika::imguiStartFrame(window.context);

+ 21 - 0
Pika/core/pikaRuntime/windowSystemm/input.h

@@ -0,0 +1,21 @@
+#pragma once
+#include <cstdint>
+
+namespace pika
+{
+
+	struct Button
+	{
+		float timer = 0;
+		std::uint32_t flags = 0;
+
+
+
+
+	};
+
+
+
+
+
+};

+ 10 - 3
Pika/gameplay/dll/dllMain.cpp

@@ -51,9 +51,16 @@ PIKA_API void gameplayStart(pika::PikaContext pikaContext)
 #pragma endregion
 #pragma endregion
 }
 }
 
 
-//todo: can remove
-PIKA_API void gameplayUpdate(pika::PikaContext pikaContext)
+
+//this won't be ever called in production so we can remove the code
+PIKA_API void gameplayReload(pika::PikaContext pikaContext)
 {
 {
-	
+#ifdef PIKA_DEVELOPMENT	
+
+	PIKA_PERMA_ASSERT(gladLoadGL(), "Problem initializing glad from dll");
+	pika::setImguiContext(pikaContext);
 
 
+	gl2d::init();
+
+#endif
 }
 }

+ 1 - 1
Pika/gameplay/dll/dllMain.h

@@ -9,7 +9,7 @@
 #include <pikaAllocator/memoryArena.h>	
 #include <pikaAllocator/memoryArena.h>	
 
 
 PIKA_API void gameplayStart(pika::PikaContext pikaContext);
 PIKA_API void gameplayStart(pika::PikaContext pikaContext);
-PIKA_API void gameplayUpdate(pika::PikaContext pikaContext);
+PIKA_API void gameplayReload(pika::PikaContext pikaContext);
 PIKA_API void getContainersInfo(std::vector<ContainerInformation> &info);
 PIKA_API void getContainersInfo(std::vector<ContainerInformation> &info);
 PIKA_API void constructContainer(Container **c, pika::memory::MemoryArena *arena, const char *name);
 PIKA_API void constructContainer(Container **c, pika::memory::MemoryArena *arena, const char *name);
 PIKA_API void destructContainer(Container **c, pika::memory::MemoryArena *arena);
 PIKA_API void destructContainer(Container **c, pika::memory::MemoryArena *arena);