world初步
This commit is contained in:
+14
-31
@@ -21,39 +21,22 @@ enable_testing()
|
|||||||
|
|
||||||
add_executable(${PROJECT_NAME}
|
add_executable(${PROJECT_NAME}
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/def.h
|
|
||||||
src/def.cpp
|
|
||||||
src/interact/InteractManager.h
|
|
||||||
src/interact/InteractManager.cpp
|
|
||||||
src/render/Renderer.h
|
|
||||||
src/render/Renderer.cpp
|
|
||||||
src/game/Game.h
|
|
||||||
src/game/Game.cpp
|
|
||||||
src/ui/Window.h
|
|
||||||
src/ui/Window.cpp
|
|
||||||
src/ui/Hud.h
|
|
||||||
src/ui/Hud.cpp
|
|
||||||
src/utils/IText.h
|
|
||||||
src/utils/IText.cpp
|
|
||||||
src/utils/exception.h
|
|
||||||
src/utils/exception.cpp
|
|
||||||
src/utils/File.h
|
|
||||||
src/utils/File.cpp
|
|
||||||
src/render/TextureManager.h
|
|
||||||
src/render/TextureManager.cpp
|
|
||||||
|
|
||||||
src/includes.h
|
src/def.cpp
|
||||||
src/utils/Chars.h
|
src/utils/File.cpp
|
||||||
src/ui/xWindows.h
|
src/utils/exception.cpp
|
||||||
src/utils/TestCode.h
|
|
||||||
src/game/entity/Entity.h
|
src/interact/InteractManager.cpp
|
||||||
src/game/entity/Player.h
|
src/utils/IText.cpp
|
||||||
|
src/game/world/Location.cpp
|
||||||
|
src/render/Renderer.cpp
|
||||||
|
src/render/TextureManager.cpp
|
||||||
|
src/ui/Hud.cpp
|
||||||
|
src/ui/Window.cpp
|
||||||
|
|
||||||
|
src/game/Game.cpp
|
||||||
|
src/game/entity/Entity.cpp
|
||||||
src/game/entity/Player.cpp
|
src/game/entity/Player.cpp
|
||||||
src/game/entity/Damage.h
|
|
||||||
src/utils/math.h
|
|
||||||
src/game/world/World.h
|
|
||||||
src/game/world/Location.h
|
|
||||||
src/game/world/Block.h
|
|
||||||
)
|
)
|
||||||
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ Module:
|
|||||||
File(30%), including Log, Save, Config, Language
|
File(30%), including Log, Save, Config, Language
|
||||||
Translator(30%), with File
|
Translator(30%), with File
|
||||||
KeyBinding(20%)
|
KeyBinding(20%)
|
||||||
|
World, Entity(10%), including gc problem
|
||||||
|
|||||||
+22
-9
@@ -4,8 +4,10 @@
|
|||||||
|
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
|
|
||||||
#include "utils\Chars.h"
|
#include "utils\File.h"
|
||||||
#include "utils\exception.h"
|
#include "utils\exception.h"
|
||||||
|
#include "utils\Chars.h"
|
||||||
|
#include "utils\gc.h"
|
||||||
|
|
||||||
template<TypeName Base> template<NewCopyable T> requires std::is_base_of_v<Base, T> && TypeName<T>
|
template<TypeName Base> template<NewCopyable T> requires std::is_base_of_v<Base, T> && TypeName<T>
|
||||||
void ObjectHolder<Base>::set(const T& value) {
|
void ObjectHolder<Base>::set(const T& value) {
|
||||||
@@ -28,20 +30,31 @@ void ObjectHolder<Base>::set(T&& value) {
|
|||||||
void requireNonnull(const void* value) noexcept(false) { if (!value) throw NullPointerException(L"value is null"); }
|
void requireNonnull(const void* value) noexcept(false) { if (!value) throw NullPointerException(L"value is null"); }
|
||||||
void checkAllocation(const void* value) noexcept(false) { if (!value) throw BadAllocationException(L"bad allocation"); }
|
void checkAllocation(const void* value) noexcept(false) { if (!value) throw BadAllocationException(L"bad allocation"); }
|
||||||
|
|
||||||
void printAllocate(void* value, const size_t size, const String& msg) {
|
void $LimitedUse::printAllocate(void* value, const size_t size, const String& msg) {
|
||||||
const String str = L"alloc " + ptrtow(reinterpret_cast<QWORD>(value)) + L" " + std::to_wstring(size) + String(L"B ") + msg;
|
const String str = L"alloc " + ptrtow(reinterpret_cast<QWORD>(value)) + L" " + std::to_wstring(size) + String(L"B ") + msg;
|
||||||
Logger.log(str);
|
Logger.log(str);
|
||||||
#if __CARLBEKS_MEMORY__ > 2
|
|
||||||
MainLogFile << str << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void printDeallocate(void* value, const size_t size, const String& msg) {
|
void $LimitedUse::printDeallocate(void* value, const size_t size, const String& msg) {
|
||||||
const String str = L"dealloc " + ptrtow(reinterpret_cast<QWORD>(value)) + L" " + std::to_wstring(size) + String(L"B ") + msg;
|
const String str = L"dealloc " + ptrtow(reinterpret_cast<QWORD>(value)) + L" " + std::to_wstring(size) + String(L"B ") + msg;
|
||||||
Logger.log(str);
|
Logger.log(str);
|
||||||
#if __CARLBEKS_MEMORY__ > 2
|
|
||||||
MainLogFile << str << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void $LimitedUse::printDeallocateWarning(void* value, const String& msg) {
|
||||||
|
const String str = L"dealloc " + ptrtow(reinterpret_cast<QWORD>(value)) + L": " + msg;
|
||||||
|
Logger.error(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
String ptrtow(const QWORD value) { return qwtowb16(value, 16); }
|
String ptrtow(const QWORD value) { return qwtowb16(value, 16); }
|
||||||
|
|
||||||
|
namespace $LimitedUse {
|
||||||
|
Release::~Release() {
|
||||||
|
delete &gc;
|
||||||
|
Logger.put(L"--------- Last Check ---------\n");
|
||||||
|
for (const auto& [addr, info] : memoryManager.allocated) { Logger.print(L" using", addr, info.size, L"B", info.msg); }
|
||||||
|
delete &Logger;
|
||||||
|
delete &memoryManager;
|
||||||
|
std::wcout << L"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define __CARLBEKS_DEBUG__
|
#define __CARLBEKS_DEBUG__
|
||||||
#define __CARLBEKS_MEMORY__ 1
|
#define __CARLBEKS_MEMORY__ 3
|
||||||
|
|
||||||
#pragma warning(disable: 4819)
|
#pragma warning(disable: 4819)
|
||||||
|
|
||||||
@@ -29,10 +29,14 @@ using wchar = wchar_t;
|
|||||||
using QWORD = unsigned long long int;
|
using QWORD = unsigned long long int;
|
||||||
using String = std::wstring;
|
using String = std::wstring;
|
||||||
using Thread = std::thread;
|
using Thread = std::thread;
|
||||||
template<typename K, typename V, typename Cmp = std::less<K>, typename Alloc = std::allocator<std::pair<const K, V>>> using Map = std::map<K, V, Cmp, Alloc>;
|
template <typename K, typename V, typename Cmp = std::less<K>, typename Alloc = std::allocator<std::pair<const K, V>>>
|
||||||
template<typename T, typename Comparator, typename Allocator = std::allocator<T>> using Set = std::set<T, Comparator, Allocator>;
|
using Map = std::map<K, V, Cmp, Alloc>;
|
||||||
template<typename T, typename Allocator = std::allocator<T>> using List = std::list<T, Allocator>;
|
template <typename T, typename Comparator = std::less<T>, typename Allocator = std::allocator<T>>
|
||||||
template<typename F> using Function = std::function<F>;
|
using Set = std::set<T, Comparator, Allocator>;
|
||||||
|
template <typename T, typename Allocator = std::allocator<T>>
|
||||||
|
using List = std::list<T, Allocator>;
|
||||||
|
template <typename F>
|
||||||
|
using Function = std::function<F>;
|
||||||
|
|
||||||
#define Success() { return 0; }
|
#define Success() { return 0; }
|
||||||
#define Failed() { return 1; }
|
#define Failed() { return 1; }
|
||||||
@@ -65,61 +69,75 @@ template<typename F> using Function = std::function<F>;
|
|||||||
#pragma comment(lib, "Uxtheme.lib")
|
#pragma comment(lib, "Uxtheme.lib")
|
||||||
#pragma comment(lib, "winmm.lib")
|
#pragma comment(lib, "winmm.lib")
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
concept Copyable = requires(const T& t) { T(t); };
|
concept Copyable = requires(const T& t) { T(t); };
|
||||||
template<typename T>
|
template <typename T>
|
||||||
concept NewCopyable = requires(const T& t) { delete new T(t); };
|
concept NewCopyable = requires(const T& t) { delete new T(t); };
|
||||||
template<typename T>
|
template <typename T>
|
||||||
concept Moveable = requires(T&& t) { T(std::move(t)); };
|
concept Moveable = requires(T&& t) { T(std::move(t)); };
|
||||||
template<typename T>
|
template <typename T>
|
||||||
concept NewMoveable = requires(T&& t) { delete new T(std::move(t)); };
|
concept NewMoveable = requires(T&& t) { delete new T(std::move(t)); };
|
||||||
template<typename T>
|
template <typename T>
|
||||||
concept NonreferenceType = !std::is_reference_v<T>;
|
concept NonreferenceType = !std::is_reference_v<T>;
|
||||||
template<typename T>
|
template <typename T>
|
||||||
concept NonpointerType = !std::is_pointer_v<T>;
|
concept NonpointerType = !std::is_pointer_v<T>;
|
||||||
template<typename T>
|
template <typename T>
|
||||||
concept ReferenceType = std::is_reference_v<T>;
|
concept ReferenceType = std::is_reference_v<T>;
|
||||||
template<typename T>
|
template <typename T>
|
||||||
concept PointerType = std::is_pointer_v<T>;
|
concept PointerType = std::is_pointer_v<T>;
|
||||||
template<typename T>
|
template <typename T>
|
||||||
concept TypeName = NonreferenceType<T> && NonpointerType<T>;
|
concept TypeName = NonreferenceType<T> && NonpointerType<T>;
|
||||||
|
|
||||||
|
namespace $LimitedUse {
|
||||||
|
struct Release {
|
||||||
|
Release() = default;
|
||||||
|
|
||||||
|
~Release();
|
||||||
|
} inline gcRelease_LoggerRelease_memoryManagerRelease;
|
||||||
|
} // namespace $LimitedUse
|
||||||
|
|
||||||
struct MemoryManager {
|
struct MemoryManager {
|
||||||
struct MemoryInfo {
|
struct MemoryInfo {
|
||||||
const String msg;
|
const String msg;
|
||||||
std::size_t size;
|
std::size_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
Map<void*, MemoryInfo> allocated {};
|
Map<void*, MemoryInfo> allocated{};
|
||||||
|
|
||||||
constexpr MemoryManager() noexcept = default;
|
constexpr MemoryManager() noexcept = default;
|
||||||
} inline memoryManager;
|
} inline& [[carlbeks::releasedat("def.cpp")]] memoryManager = *new MemoryManager;
|
||||||
|
|
||||||
void requireNonnull(const void* value) noexcept(false);
|
void requireNonnull(const void* value) noexcept(false);
|
||||||
void checkAllocation(const void* value) noexcept(false);
|
void checkAllocation(const void* value) noexcept(false);
|
||||||
inline String ptrtow(QWORD value);
|
inline String ptrtow(QWORD value);
|
||||||
|
|
||||||
#if defined __CARLBEKS_DEBUG__ || defined __CARLBEKS_MEMORY__
|
#if defined __CARLBEKS_DEBUG__ || defined __CARLBEKS_MEMORY__
|
||||||
void printAllocate(void* value, std::size_t size, const String&);
|
namespace $LimitedUse {
|
||||||
void printDeallocate(void* value, std::size_t size, const String&);
|
void printAllocate(void* value, std::size_t size, const String&);
|
||||||
|
void printDeallocate(void* value, std::size_t size, const String&);
|
||||||
|
void printDeallocateWarning(void* value, const String& msg);
|
||||||
|
}
|
||||||
|
|
||||||
extern String atow(const char* chars);
|
extern String atow(const char* chars);
|
||||||
|
|
||||||
template<typename T> T* allocatedFor$(T* value, const String& msg = L"", std::size_t size = sizeof(T)) {
|
template <typename T>
|
||||||
|
T* allocatedFor$(T* value, const String& msg = L"", std::size_t size = sizeof(T)) {
|
||||||
requireNonnull(value);
|
requireNonnull(value);
|
||||||
const auto& k = memoryManager.allocated.emplace(value, MemoryManager::MemoryInfo{ L"[" + atow(typeid(T).name()) + L"] " + msg , size}).first;
|
const auto& k = memoryManager.allocated.emplace(value, MemoryManager::MemoryInfo{L"[" + atow(typeid(T).name()) + L"] " + msg, size}).first;
|
||||||
#if __CARLBEKS_MEMORY__ > 1
|
#if __CARLBEKS_MEMORY__ > 1
|
||||||
printAllocate(value, k->second.size, k->second.msg);
|
$LimitedUse::printAllocate(value, k->second.size, k->second.msg);
|
||||||
#endif
|
#endif
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> T* deallocating$(T* value) {
|
template <typename T>
|
||||||
|
T* deallocating$(T* value, const String& stack) {
|
||||||
#if __CARLBEKS_MEMORY__ > 1
|
#if __CARLBEKS_MEMORY__ > 1
|
||||||
const MemoryManager::MemoryInfo* info = nullptr;
|
const MemoryManager::MemoryInfo* info = nullptr;
|
||||||
if (memoryManager.allocated.contains(value)) info = &memoryManager.allocated.at(value);
|
if (memoryManager.allocated.contains(value)) info = &memoryManager.allocated.at(value);
|
||||||
printDeallocate(value, info ? info->size : 0, info ? info->msg : L"???");
|
$LimitedUse::printDeallocate(value, info ? info->size : 0, info ? info->msg : L"???");
|
||||||
#endif
|
#endif
|
||||||
if (value) memoryManager.allocated.erase(value);
|
if (value) { if (!memoryManager.allocated.erase(value)) $LimitedUse::printDeallocateWarning(value, L"value not recorded" + stack); }
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,13 +146,18 @@ template<typename T> T* deallocating$(T* value) {
|
|||||||
#else
|
#else
|
||||||
#define allocatedFor(val, ...) allocatedFor$(val, L"" __VA_OPT__(,) __VA_ARGS__)
|
#define allocatedFor(val, ...) allocatedFor$(val, L"" __VA_OPT__(,) __VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
|
#if __CARLBEKS_MEMORY__ > 2
|
||||||
|
#define deallocating(val) deallocating$(val, L"\n From " __FUNCSIG__ "\n At " __FILE__ ":" _STL_STRINGIZE(__LINE__))
|
||||||
|
#else
|
||||||
#define deallocating(val) deallocating$(val)
|
#define deallocating(val) deallocating$(val)
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#define allocatedFor(val, ...) val
|
#define allocatedFor(val, ...) val
|
||||||
#define deallocating(val) val
|
#define deallocating(val) val
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<TypeName Base> class ObjectHolder {
|
template <TypeName Base>
|
||||||
|
class ObjectHolder {
|
||||||
Base* value;
|
Base* value;
|
||||||
bool hasValue;
|
bool hasValue;
|
||||||
char padding[7]{};
|
char padding[7]{};
|
||||||
@@ -147,10 +170,10 @@ public:
|
|||||||
|
|
||||||
ObjectHolder(Base* value) : value(value), hasValue(false) {}
|
ObjectHolder(Base* value) : value(value), hasValue(false) {}
|
||||||
|
|
||||||
template<NewCopyable T> requires (std::is_base_of_v<Base, T> || std::is_same_v<Base, T>) && TypeName<T>
|
template <NewCopyable T> requires (std::is_base_of_v<Base, T> || std::is_same_v<Base, T>) && TypeName<T>
|
||||||
ObjectHolder(const T& value) : value(allocatedFor(new T(value))), hasValue(true) {}
|
ObjectHolder(const T& value) : value(allocatedFor(new T(value))), hasValue(true) {}
|
||||||
|
|
||||||
template<NewMoveable T> requires (std::is_base_of_v<Base, T> || std::is_same_v<Base, T>) && TypeName<T>
|
template <NewMoveable T> requires (std::is_base_of_v<Base, T> || std::is_same_v<Base, T>) && TypeName<T>
|
||||||
ObjectHolder(T&& value) : value(allocatedFor(new T(std::forward<T>(value)))), hasValue(true) {}
|
ObjectHolder(T&& value) : value(allocatedFor(new T(std::forward<T>(value)))), hasValue(true) {}
|
||||||
|
|
||||||
ObjectHolder(const ObjectHolder& other) noexcept: value(other.value), hasValue(false) {}
|
ObjectHolder(const ObjectHolder& other) noexcept: value(other.value), hasValue(false) {}
|
||||||
@@ -160,10 +183,10 @@ public:
|
|||||||
other.hasValue = false;
|
other.hasValue = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<NewCopyable T> requires std::is_base_of_v<Base, T> && TypeName<T>
|
template <NewCopyable T> requires std::is_base_of_v<Base, T> && TypeName<T>
|
||||||
void set(const T& value);
|
void set(const T& value);
|
||||||
|
|
||||||
template<NewMoveable T> requires std::is_base_of_v<Base, T> && TypeName<T>
|
template <NewMoveable T> requires std::is_base_of_v<Base, T> && TypeName<T>
|
||||||
void set(T&& value);
|
void set(T&& value);
|
||||||
|
|
||||||
~ObjectHolder() {
|
~ObjectHolder() {
|
||||||
@@ -207,14 +230,16 @@ public:
|
|||||||
bool operator!() const noexcept { return value == nullptr; }
|
bool operator!() const noexcept { return value == nullptr; }
|
||||||
[[nodiscard]] bool isManager() const noexcept { return hasValue; }
|
[[nodiscard]] bool isManager() const noexcept { return hasValue; }
|
||||||
|
|
||||||
template<typename T> ObjectHolder<T> referenceof(const T& other) {
|
template <typename T>
|
||||||
|
ObjectHolder<T> referenceof(const T& other) {
|
||||||
ObjectHolder ret{};
|
ObjectHolder ret{};
|
||||||
ret.value = &other;
|
ret.value = &other;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<TypeName Base> class SynchronizedHolder {
|
template <TypeName Base>
|
||||||
|
class SynchronizedHolder {
|
||||||
mutable Base* newValue = nullptr;
|
mutable Base* newValue = nullptr;
|
||||||
mutable Base* value = nullptr;
|
mutable Base* value = nullptr;
|
||||||
mutable bool isOk = false;
|
mutable bool isOk = false;
|
||||||
@@ -223,7 +248,8 @@ public:
|
|||||||
SynchronizedHolder() = default;
|
SynchronizedHolder() = default;
|
||||||
|
|
||||||
~SynchronizedHolder() {
|
~SynchronizedHolder() {
|
||||||
if (newValue == value) { if (value) delete deallocating(value); } else {
|
if (newValue == value) { if (value) delete deallocating(value); }
|
||||||
|
else {
|
||||||
if (newValue) delete deallocating(newValue);
|
if (newValue) delete deallocating(newValue);
|
||||||
if (value) delete deallocating(value);
|
if (value) delete deallocating(value);
|
||||||
}
|
}
|
||||||
@@ -232,14 +258,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<NewCopyable T> requires std::is_base_of_v<Base, T> && TypeName<T>
|
template <NewCopyable T> requires std::is_base_of_v<Base, T> && TypeName<T>
|
||||||
void setNew(const Base& other) noexcept {
|
void setNew(const Base& other) noexcept {
|
||||||
isOk = false;
|
isOk = false;
|
||||||
if (newValue && newValue != value) deleteNew();
|
if (newValue && newValue != value) deleteNew();
|
||||||
newValue = allocatedFor(new T(other));
|
newValue = allocatedFor(new T(other));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<NewMoveable T> requires std::is_base_of_v<Base, T> && TypeName<T>
|
template <NewMoveable T> requires std::is_base_of_v<Base, T> && TypeName<T>
|
||||||
void setNew(T&& val) noexcept {
|
void setNew(T&& val) noexcept {
|
||||||
isOk = false;
|
isOk = false;
|
||||||
if (newValue && newValue != value) deleteNew();
|
if (newValue && newValue != value) deleteNew();
|
||||||
|
|||||||
+38
-1
@@ -4,12 +4,15 @@
|
|||||||
|
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
|
|
||||||
|
#include "entity\Entity.h"
|
||||||
#include "world\World.h"
|
#include "world\World.h"
|
||||||
#include "..\ui\xWindows.h"
|
#include "..\ui\xWindows.h"
|
||||||
|
|
||||||
void Game::initialize() {
|
void Game::initialize() {
|
||||||
worldManager = allocatedFor(new WorldManager);
|
worldManager = allocatedFor(new WorldManager);
|
||||||
game.setWindow(StartWindow::create());
|
entityManager = allocatedFor(new EntityManager);
|
||||||
|
setWindow(StartWindow::create());
|
||||||
|
windows.onResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::Game() : caption{ allocatedFor(new CaptionWindow()) }, floatWindow{ allocatedFor(new FloatWindow()) } {
|
Game::Game() : caption{ allocatedFor(new CaptionWindow()) }, floatWindow{ allocatedFor(new FloatWindow()) } {
|
||||||
@@ -20,8 +23,42 @@ Game::Game() : caption{ allocatedFor(new CaptionWindow()) }, floatWindow{ alloca
|
|||||||
Game::~Game() {
|
Game::~Game() {
|
||||||
setWindow(nullptr);
|
setWindow(nullptr);
|
||||||
delete deallocating(floatWindow);
|
delete deallocating(floatWindow);
|
||||||
|
gc.pack();
|
||||||
|
gc.collect();
|
||||||
delete deallocating(caption);
|
delete deallocating(caption);
|
||||||
|
gc.pack();
|
||||||
|
gc.collect();
|
||||||
delete deallocating(worldManager);
|
delete deallocating(worldManager);
|
||||||
|
gc.pack();
|
||||||
|
gc.collect();
|
||||||
|
delete deallocating(entityManager);
|
||||||
|
gc.pack();
|
||||||
|
gc.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::render(const double tickDelta) const noexcept {
|
||||||
|
if (renderer.checkResizing()) return;
|
||||||
|
renderer.gameStartRender();
|
||||||
|
if (worldManager->current) worldManager->current->render(tickDelta);
|
||||||
|
caption->render(tickDelta);
|
||||||
|
hud.render(tickDelta);
|
||||||
|
windows.render(tickDelta);
|
||||||
|
floatWindow->render(tickDelta);
|
||||||
|
renderer.gameEndRender();
|
||||||
|
gc.pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Game::tick() noexcept {
|
||||||
|
++currentTick;
|
||||||
|
if (worldManager->current) worldManager->current->tick();
|
||||||
|
floatWindow->clear();
|
||||||
|
floatWindow->tick();
|
||||||
|
caption->tick();
|
||||||
|
hud.tick();
|
||||||
|
windows.tick();
|
||||||
|
floatWindow->update();
|
||||||
|
tasks.runAll();
|
||||||
|
gc.collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Game game = Game();
|
inline Game game = Game();
|
||||||
|
|||||||
+7
-26
@@ -10,6 +10,7 @@
|
|||||||
#include "../ui/Window.h"
|
#include "../ui/Window.h"
|
||||||
|
|
||||||
class [[carlbeks::predecl, carlbeks::defineat("World.h")]] WorldManager;
|
class [[carlbeks::predecl, carlbeks::defineat("World.h")]] WorldManager;
|
||||||
|
class [[carlbeks::predecl, carlbeks::defineat("Entity.h")]] EntityManager;
|
||||||
|
|
||||||
class Game final /* : public IRenderable, public ITickable */ {
|
class Game final /* : public IRenderable, public ITickable */ {
|
||||||
friend void gameThread();
|
friend void gameThread();
|
||||||
@@ -23,24 +24,17 @@ public:
|
|||||||
TaskScheduler tasks; // 8
|
TaskScheduler tasks; // 8
|
||||||
std::minstd_rand random;
|
std::minstd_rand random;
|
||||||
WorldManager* worldManager = nullptr;
|
WorldManager* worldManager = nullptr;
|
||||||
|
EntityManager* entityManager = nullptr;
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
Game();
|
Game();
|
||||||
~Game();
|
~Game();
|
||||||
|
|
||||||
[[nodiscard]] QWORD getTick() const noexcept { return currentTick; }
|
|
||||||
int closeWindow(Window* const window) noexcept { return windows.pop(window); }
|
int closeWindow(Window* const window) noexcept { return windows.pop(window); }
|
||||||
|
[[nodiscard]] FloatWindow& getFloatWindow() const noexcept { return *floatWindow; }
|
||||||
void render() const noexcept {
|
[[nodiscard]] QWORD getTick() const noexcept { return currentTick; }
|
||||||
if (renderer.checkResizing()) return;
|
void tick() noexcept;
|
||||||
renderer.gameStartRender();
|
void render(double tickDelta) const noexcept;
|
||||||
caption->render();
|
|
||||||
hud.render();
|
|
||||||
windows.render();
|
|
||||||
floatWindow->render();
|
|
||||||
renderer.gameEndRender();
|
|
||||||
gc.pack();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 所有窗口都提交给Game保管,在适当时刻自动删除。
|
* 所有窗口都提交给Game保管,在适当时刻自动删除。
|
||||||
@@ -59,25 +53,12 @@ public:
|
|||||||
Success();
|
Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] FloatWindow& getFloatWindow() const noexcept { return *floatWindow; }
|
|
||||||
|
|
||||||
[[nodiscard]] Window* getWindow() const noexcept {
|
[[nodiscard]] Window* getWindow() const noexcept {
|
||||||
if (auto *const back = windows.back()) return dynamic_cast<Window*>(back);
|
if (auto* const back = windows.back()) return dynamic_cast<Window*>(back);
|
||||||
Logger.error(L"Game::getWindow returns nullptr");
|
Logger.error(L"Game::getWindow returns nullptr");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tick() noexcept {
|
|
||||||
++currentTick;
|
|
||||||
floatWindow->clear();
|
|
||||||
floatWindow->tick();
|
|
||||||
caption->tick();
|
|
||||||
hud.tick();
|
|
||||||
windows.tick();
|
|
||||||
floatWindow->update();
|
|
||||||
tasks.runAll();
|
|
||||||
gc.collect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void handleResize() {
|
void handleResize() {
|
||||||
caption->onResize();
|
caption->onResize();
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//
|
||||||
|
// Created by EmsiaetKadosh on 25-3-22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Entity.h"
|
||||||
+52
-23
@@ -5,11 +5,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "..\..\utils\math.h"
|
#include "..\..\utils\math.h"
|
||||||
|
#include "..\..\render\Renderer.h"
|
||||||
#include "..\world\Location.h"
|
#include "..\world\Location.h"
|
||||||
#include "Damage.h"
|
#include "Damage.h"
|
||||||
|
|
||||||
class Entity;
|
class Entity;
|
||||||
class World;
|
class [[carlbeks::predecl, carlbeks::defineat("World.h")]] World;
|
||||||
|
class EntityManager;
|
||||||
|
|
||||||
|
using EntityID = QWORD;
|
||||||
|
|
||||||
interface IDamageable {
|
interface IDamageable {
|
||||||
protected:
|
protected:
|
||||||
@@ -22,40 +26,65 @@ public:
|
|||||||
virtual void onDeath() = 0;
|
virtual void onDeath() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IMoveable {
|
|
||||||
protected:
|
|
||||||
double maxSpeed = 1.0;
|
|
||||||
Vector2D velocity;
|
|
||||||
|
|
||||||
virtual ~IMoveable() = default;
|
|
||||||
public:
|
|
||||||
void setVelocity(const Vector2D& velocity) { this->velocity = velocity; }
|
|
||||||
[[nodiscard]] Vector2D getVelocity() const { return this->velocity; }
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IArtificialIntelligent {
|
interface IArtificialIntelligent {
|
||||||
protected:
|
protected:
|
||||||
virtual ~IArtificialIntelligent() = default;
|
virtual ~IArtificialIntelligent() = default;
|
||||||
virtual void aiProcess() {}
|
virtual void aiProcess() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Entity {
|
class Entity : public IRenderable, public ITickable {
|
||||||
friend class World;
|
friend class World;
|
||||||
Location location;
|
friend class EntityManager;
|
||||||
QWORD id = 0;
|
EntityID idEntity = 0;
|
||||||
|
World* world = nullptr;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Entity(const Location& location) : location(location) {}
|
Location location;
|
||||||
Entity(Location&& location) : location(std::move(location)) {}
|
Vector2D velocity;
|
||||||
virtual ~Entity() = default;
|
double maxSpeed = 1.0;
|
||||||
|
|
||||||
|
Entity(const Vector2D& location) : location(location) {}
|
||||||
|
~Entity() override = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void tick() {}
|
virtual void onRemove() = 0;
|
||||||
virtual void onRemove() {}
|
virtual void onEnterWorld(World* world, WorldTransportReason reason) {}
|
||||||
|
virtual void onExitWorld(World* world, WorldTransportReason reason) {}
|
||||||
|
|
||||||
|
void setVelocity(const Vector2D& velocity) noexcept { this->velocity = velocity; }
|
||||||
|
[[nodiscard]] const Location& getLocation() const noexcept { return this->location; }
|
||||||
|
[[nodiscard]] const Location& getLocation(const double tickDelta) const noexcept { return Location(this->location.getPosition() + this->velocity * tickDelta, this->location.getWorld()); }
|
||||||
|
[[nodiscard]] Vector2D getVelocity() const noexcept { return this->velocity; }
|
||||||
|
[[nodiscard]] double getMaxSpeed() const noexcept { return this->maxSpeed; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Enemy : public Entity, public IDamageable, public IMoveable, public IArtificialIntelligent {
|
class Enemy : public Entity, public IDamageable, public IArtificialIntelligent {
|
||||||
protected:
|
protected:
|
||||||
Enemy(const Location& location) : Entity(location) {}
|
Enemy(const Vector2D& location) : Entity(location) {}
|
||||||
Enemy(Location&& location) : Entity(std::move(location)) {}
|
};
|
||||||
|
|
||||||
|
class EntityManager {
|
||||||
|
friend class Game;
|
||||||
|
EntityID nextID = 0;
|
||||||
|
Map<EntityID, Entity*> entities;
|
||||||
|
EntityManager() = default;
|
||||||
|
~EntityManager() { for (auto& [id, entity] : entities) { entity->onRemove(); } }
|
||||||
|
|
||||||
|
public:
|
||||||
|
int addEntity(Entity* entity) {
|
||||||
|
if (!entity) Failed();
|
||||||
|
if (entity->idEntity) Failed();
|
||||||
|
entity->idEntity = ++nextID;
|
||||||
|
entities.emplace(entity->idEntity, entity);
|
||||||
|
Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
int removeEntity(Entity* entity) {
|
||||||
|
if (!entity) Failed();
|
||||||
|
if (entity->idEntity) Failed();
|
||||||
|
if (entity->getLocation().getWorld()) Failed(); // 确保必须已经从其他世界移除
|
||||||
|
entities.erase(entity->idEntity);
|
||||||
|
entity->onRemove();
|
||||||
|
Success();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,8 +6,7 @@
|
|||||||
|
|
||||||
#include "Entity.h"
|
#include "Entity.h"
|
||||||
|
|
||||||
class Player : public Entity, public IMoveable, public IDamageable {
|
class Player : public Entity, public IDamageable {
|
||||||
public:
|
public:
|
||||||
Player(const Location& location) : Entity(location) {}
|
Player(const Vector2D& location) : Entity(location) {}
|
||||||
Player(Location&& location) : Entity(std::move(location)) {}
|
|
||||||
};
|
};
|
||||||
|
|||||||
+33
-2
@@ -4,9 +4,40 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "..\..\def.h"
|
||||||
|
#include "..\..\utils\gc.h"
|
||||||
#include "Location.h"
|
#include "Location.h"
|
||||||
|
|
||||||
class Block {
|
class [[carlbeks::predecl, carlbeks::defineat("World.h")]] World;
|
||||||
public:
|
|
||||||
|
|
||||||
|
class Block : public IRenderable, public ITickable {
|
||||||
|
friend class Garbage<Block>;
|
||||||
|
friend class World;
|
||||||
|
World* world = nullptr;
|
||||||
|
BlockLocation location;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Block(const BlockLocation& location) : location(location) { this->location.setWorld(0); }
|
||||||
|
[[nodiscard]] const BlockLocation& getLocation() const { return location; }
|
||||||
|
virtual void onEnterWorld(World* world, WorldTransportReason reason) {}
|
||||||
|
virtual void onExitWorld(World* world, WorldTransportReason reason) {}
|
||||||
|
virtual void onRemove() { gc.submit<Block>(this); }
|
||||||
|
/**
|
||||||
|
* 渲染方块影。方块影会覆盖所有的方块。
|
||||||
|
*/
|
||||||
|
virtual void renderShadow() const noexcept {}
|
||||||
|
/**
|
||||||
|
* 渲染方块本体。渲染范围不应当超过方块占据的范围。
|
||||||
|
*/
|
||||||
|
void render(double tickDelta) const noexcept override = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PureBarrierBlock final : public Block {
|
||||||
|
PureBarrierBlock(const BlockLocation& location) : Block(location) {}
|
||||||
|
~PureBarrierBlock() override {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void render(double tickDelta) const noexcept override { renderer.fillWorldBlock(getLocation(), 0xffeeeeee); }
|
||||||
|
void tick() noexcept override {}
|
||||||
|
static PureBarrierBlock* create(const BlockLocation& location) { return allocatedFor(new PureBarrierBlock(location)); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
//
|
||||||
|
// Created by EmsiaetKadosh on 25-3-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Location.h"
|
||||||
|
|
||||||
|
inline const WorldTransportReason WorldTransportReason::Shutdown = *manager.create(L"game shutdown", true, true);
|
||||||
|
inline const WorldTransportReason WorldTransportReason::InitialGeneration = *manager.create(L"initial generation", true, true);
|
||||||
|
inline const WorldTransportReason WorldTransportReason::WorldCollapse = *manager.create(L"world collapse", true, true);
|
||||||
|
inline const WorldTransportReason WorldTransportReason::BlockBreak = *manager.create(L"block break", true, false);
|
||||||
|
inline const WorldTransportReason WorldTransportReason::BlockReplace = *manager.create(L"block replace", true, false);
|
||||||
|
inline const WorldTransportReason WorldTransportReason::EntityTeleport = *manager.create(L"entity teleport", false, true);
|
||||||
+118
-17
@@ -9,34 +9,135 @@
|
|||||||
using WorldID = QWORD;
|
using WorldID = QWORD;
|
||||||
class Location;
|
class Location;
|
||||||
class BlockLocation;
|
class BlockLocation;
|
||||||
|
class [[carlbeks::predecl, carlbeks::defineat("World.h")]] World;
|
||||||
|
|
||||||
class Location {
|
/**
|
||||||
|
* 当一个方块/实体被移入/移出世界时,需要有一个理由。
|
||||||
|
* 如果方块移出时附带内置的Shutdown理由,那么方块在移出时会被立刻自动submit至gc。
|
||||||
|
* Shutdown理由的含义是,世界管理器下的所有世界内的所有方块,都会被依次附带Shutdown理由移出世界。
|
||||||
|
* 此过程中不可以进行其他的方块WorldTransport行为(因为正在遍历方块),也不需要手动清除其他的关联方块。
|
||||||
|
* 禁止在处理附带Shutdown理由的移出世界事件时提交自身给gc。但是方块自身的其他垃圾可能需要手动清理。
|
||||||
|
*
|
||||||
|
* 该类视同enum类。元素只允许引用访问,不允许复制、移动。
|
||||||
|
*/
|
||||||
|
class WorldTransportReason final {
|
||||||
|
friend class World;
|
||||||
|
struct LessReason;
|
||||||
|
|
||||||
|
class Reason final {
|
||||||
|
friend struct LessReason;
|
||||||
|
friend class WorldTransportReason;
|
||||||
|
const String description;
|
||||||
|
const bool isBlockReason, isEntityReason;
|
||||||
|
~Reason() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Reason(const String& description, const bool isBlockReason, const bool isEntityReason) : description(description), isBlockReason(isBlockReason), isEntityReason(isEntityReason) {}
|
||||||
|
Reason(String&& description, const bool isBlockReason, const bool isEntityReason) : description(std::move(description)), isBlockReason(isBlockReason), isEntityReason(isEntityReason) {}
|
||||||
|
Reason(const Reason&) = delete;
|
||||||
|
Reason(Reason&&) = delete;
|
||||||
|
Reason& operator=(const Reason&) = delete;
|
||||||
|
Reason& operator=(Reason&&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LessReason {
|
||||||
|
using is_transparent = String;
|
||||||
|
[[nodiscard]] bool operator()(const Reason* const lhs, const Reason* const rhs) const { return lhs->description < rhs->description; }
|
||||||
|
[[nodiscard]] bool operator()(const String& str, const Reason* const rhs) const { return str < rhs->description; }
|
||||||
|
[[nodiscard]] bool operator()(const Reason* const lhs, const String& str) const { return lhs->description < str; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Manager {
|
||||||
|
Set<Reason*, LessReason> reasons;
|
||||||
|
~Manager() { for (Reason* r : reasons) delete deallocating(r); }
|
||||||
|
|
||||||
|
Reason* create(const String& description, const bool isBlockReason, const bool isEntityReason) {
|
||||||
|
if (const Set<Reason*, LessReason>::const_iterator iter = reasons.find(description); iter != reasons.end()) return iter.operator*();
|
||||||
|
Reason* r = allocatedFor(new Reason(description, isBlockReason, isEntityReason));
|
||||||
|
reasons.emplace(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Reason* create(String&& description, const bool isBlockReason, const bool isEntityReason) {
|
||||||
|
if (const Set<Reason*, LessReason>::const_iterator iter = reasons.find(description); iter != reasons.end()) return iter.operator*();
|
||||||
|
Reason* r = allocatedFor(new Reason(std::move(description), isBlockReason, isEntityReason));
|
||||||
|
reasons.emplace(r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
} inline static manager;
|
||||||
|
|
||||||
|
static const WorldTransportReason Shutdown;
|
||||||
|
const Reason* reason;
|
||||||
|
WorldTransportReason(const Reason& reason) : reason(&reason) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const WorldTransportReason InitialGeneration;
|
||||||
|
static const WorldTransportReason WorldCollapse;
|
||||||
|
static const WorldTransportReason BlockBreak;
|
||||||
|
static const WorldTransportReason BlockReplace;
|
||||||
|
static const WorldTransportReason EntityTeleport;
|
||||||
|
|
||||||
|
WorldTransportReason() = delete;
|
||||||
|
WorldTransportReason(const WorldTransportReason&) = default;
|
||||||
|
WorldTransportReason(WorldTransportReason&&) = default;
|
||||||
|
WorldTransportReason& operator=(const WorldTransportReason&) = default;
|
||||||
|
WorldTransportReason& operator=(WorldTransportReason&&) = default;
|
||||||
|
~WorldTransportReason() = default;
|
||||||
|
[[nodiscard]] bool operator==(const WorldTransportReason& other) const noexcept { return reason == other.reason; }
|
||||||
|
[[nodiscard]] bool operator!=(const WorldTransportReason& other) const noexcept { return reason != other.reason; }
|
||||||
|
[[nodiscard]] bool isBlockReason() const noexcept { return reason->isBlockReason; }
|
||||||
|
[[nodiscard]] bool isEntityReason() const noexcept { return reason->isEntityReason; }
|
||||||
|
|
||||||
|
static WorldTransportReason registerReason(const String& description, const bool isBlockReason, const bool isEntityReason) { return *manager.create(description, isBlockReason, isEntityReason); }
|
||||||
|
static WorldTransportReason registerReason(String&& description, const bool isBlockReason, const bool isEntityReason) { return *manager.create(std::move(description), isBlockReason, isEntityReason); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class [[carlbeks::TriviallyCopyable]] Location {
|
||||||
Vector2D position;
|
Vector2D position;
|
||||||
WorldID idWorld;
|
WorldID idWorld;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Location(const Vector2D& position, const WorldID idWorld) : position(position), idWorld(idWorld) {}
|
Location(const Vector2D& position) noexcept : position(position), idWorld(0) {}
|
||||||
Location(Vector2D&& position, const WorldID idWorld) : position(position), idWorld(idWorld) {}
|
Location(const Vector2D& position, const WorldID idWorld) noexcept : position(position), idWorld(idWorld) {}
|
||||||
[[nodiscard]] Vector2D getPosition() const { return position; }
|
Location(const Location& other) noexcept = default;
|
||||||
[[nodiscard]] WorldID getWorld() const { return idWorld; }
|
Location(Location&& other) noexcept = default;
|
||||||
[[nodiscard]] double getX() const { return position.getX(); }
|
[[nodiscard]] Vector2D getPosition() const noexcept { return position; }
|
||||||
[[nodiscard]] double getY() const { return position.getY(); }
|
[[nodiscard]] WorldID getWorld() const noexcept { return idWorld; }
|
||||||
[[nodiscard]] BlockLocation getBlockLocation() const;
|
[[nodiscard]] double getX() const noexcept { return position.getX(); }
|
||||||
|
[[nodiscard]] double getY() const noexcept { return position.getY(); }
|
||||||
|
[[nodiscard]] BlockLocation getBlockLocation() const noexcept;
|
||||||
|
|
||||||
|
void setPosition(const Vector2D& vector) noexcept { position = vector; }
|
||||||
|
void setWorld(const WorldID idWorld) noexcept { this->idWorld = idWorld; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class BlockLocation {
|
class [[carlbeks::TriviallyCopyable]] BlockLocation {
|
||||||
long long x, y;
|
long long x, y;
|
||||||
WorldID idWorld;
|
WorldID idWorld;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BlockLocation(const long long x, const long long y, const WorldID idWorld) : x(x), y(y), idWorld(idWorld) {}
|
BlockLocation(const long long x, const long long y) noexcept : x(x), y(y), idWorld(0) {}
|
||||||
BlockLocation(const Vector2D& position, const WorldID idWorld) : x(static_cast<long long>(std::floor(position.getX()))), y(static_cast<long long>(std::floor(position.getY()))), idWorld(idWorld) {}
|
BlockLocation(const Vector2D& position) noexcept : x(static_cast<long long>(position.getX())), y(static_cast<long long>(position.getY())), idWorld(0) {}
|
||||||
[[nodiscard]] Vector2D getPosition() const { return Vector2D(static_cast<double>(x), static_cast<double>(y)); }
|
BlockLocation(const long long x, const long long y, const WorldID idWorld) noexcept : x(x), y(y), idWorld(idWorld) {}
|
||||||
[[nodiscard]] WorldID getWorld() const { return idWorld; }
|
BlockLocation(const Vector2D& position, const WorldID idWorld) noexcept : x(static_cast<long long>(std::floor(position.getX()))), y(static_cast<long long>(std::floor(position.getY()))), idWorld(idWorld) {}
|
||||||
[[nodiscard]] long long getX() const { return x; }
|
BlockLocation(const BlockLocation& other) noexcept = default;
|
||||||
[[nodiscard]] long long getY() const { return y; }
|
BlockLocation(BlockLocation&& other) noexcept = default;
|
||||||
[[nodiscard]] Location toLocation() const { return Location({ static_cast<double>(x), static_cast<double>(y) }, idWorld); }
|
[[nodiscard]] Vector2D getPosition() const noexcept { return Vector2D(static_cast<double>(x), static_cast<double>(y)); }
|
||||||
|
[[nodiscard]] WorldID getWorld() const noexcept { return idWorld; }
|
||||||
|
[[nodiscard]] long long getX() const noexcept { return x; }
|
||||||
|
[[nodiscard]] long long getY() const noexcept { return y; }
|
||||||
|
[[nodiscard]] Location toLocation() const noexcept { return Location({ static_cast<double>(x), static_cast<double>(y) }, idWorld); }
|
||||||
|
|
||||||
|
void setPosition(const long long x, const long long y) noexcept { this->x = x, this->y = y; }
|
||||||
|
void setWorld(const WorldID idWorld) noexcept { this->idWorld = idWorld; }
|
||||||
|
|
||||||
|
struct Less {
|
||||||
|
bool operator()(const BlockLocation& lhs, const BlockLocation& rhs) const noexcept;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
inline BlockLocation Location::getBlockLocation() const { return BlockLocation(position, idWorld); }
|
inline bool BlockLocation::Less::operator()(const BlockLocation& lhs, const BlockLocation& rhs) const noexcept { return lhs.y < rhs.y || (lhs.y == rhs.y && lhs.x < rhs.x); }
|
||||||
|
|
||||||
|
|
||||||
|
inline BlockLocation Location::getBlockLocation() const noexcept { return BlockLocation(position, idWorld); }
|
||||||
|
|
||||||
|
|||||||
+154
-13
@@ -6,34 +6,175 @@
|
|||||||
|
|
||||||
#include "..\..\def.h"
|
#include "..\..\def.h"
|
||||||
#include "..\entity\Entity.h"
|
#include "..\entity\Entity.h"
|
||||||
|
#include "Block.h"
|
||||||
|
|
||||||
class World {
|
class World;
|
||||||
QWORD idEntity = 0;
|
class WorldManager;
|
||||||
|
|
||||||
|
class World : public IRenderable, public ITickable {
|
||||||
|
friend class WorldManager;
|
||||||
|
friend class Garbage<World>;
|
||||||
|
WorldID idWorld;
|
||||||
Map<QWORD, Entity*> entities;
|
Map<QWORD, Entity*> entities;
|
||||||
|
Map<BlockLocation, Block*, BlockLocation::Less> blocks;
|
||||||
using IterEntity = Map<QWORD, Entity*>::const_iterator;
|
using IterEntity = Map<QWORD, Entity*>::const_iterator;
|
||||||
|
using IterBlock = Map<BlockLocation, Block*, BlockLocation::Less>::const_iterator;
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
World() = default;
|
World() = default;
|
||||||
|
|
||||||
int addEntity(Entity* entity) {
|
~World() override {
|
||||||
|
Logger.debug(L"~World() called");
|
||||||
|
for (auto& [location, block] : blocks) {
|
||||||
|
block->onExitWorld(this, WorldTransportReason::Shutdown);
|
||||||
|
block->location.setWorld(0);
|
||||||
|
block->world = nullptr;
|
||||||
|
block->onRemove();
|
||||||
|
}
|
||||||
|
for (auto& [id, entity] : entities) {
|
||||||
|
entity->onExitWorld(this, WorldTransportReason::Shutdown);
|
||||||
|
entity->location.setWorld(0);
|
||||||
|
entity->world = nullptr;
|
||||||
|
// entity->onRemove() 交给EntityManager调用
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void render(const double tickDelta) const noexcept override {
|
||||||
|
for (const auto& [location, block] : blocks) block->render(tickDelta);
|
||||||
|
for (const auto& [id, entity] : entities) entity->render(tickDelta);
|
||||||
|
for (const auto& [location, block] : blocks) block->renderShadow();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int addEntity(Entity* entity, const WorldTransportReason reason) {
|
||||||
if (!entity) Failed();
|
if (!entity) Failed();
|
||||||
if (entity->id) Failed();
|
if (!entity->idEntity) Failed();
|
||||||
entities.emplace(++idEntity, entity);
|
if (entity->location.getWorld()) Failed();
|
||||||
|
if (entity->world) Failed();
|
||||||
|
if (!reason.isEntityReason()) Failed();
|
||||||
|
entity->onEnterWorld(this, reason);
|
||||||
|
entity->location.setWorld(idWorld);
|
||||||
|
entity->world = this;
|
||||||
|
entities.emplace(entity->idEntity, entity);
|
||||||
Success();
|
Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
int removeEntity(Entity* entity) {
|
virtual int removeEntity(Entity* entity, const WorldTransportReason reason) {
|
||||||
if (!entity) Failed();
|
if (!entity) Failed();
|
||||||
if (!entity->id) Failed();
|
if (!entity->idEntity) Failed();
|
||||||
const IterEntity iter = entities.find(entity->id);
|
if (!entities.erase(entity->idEntity)) Failed();
|
||||||
if (iter != entities.end()) Failed();
|
if (!reason.isEntityReason()) Failed();
|
||||||
entities.erase(iter);
|
entity->onExitWorld(this, reason);
|
||||||
entity->onRemove();
|
entity->location.setWorld(0);
|
||||||
entity->id = 0;
|
entity->world = nullptr;
|
||||||
Success();
|
Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual int addBlock(Block* block, const WorldTransportReason reason) {
|
||||||
|
if (!block) Failed();
|
||||||
|
if (block->getLocation().getWorld()) Failed();
|
||||||
|
if (block->world) Failed();
|
||||||
|
if (blocks.contains(block->getLocation())) Failed();
|
||||||
|
if (!reason.isBlockReason()) Failed();
|
||||||
|
blocks.emplace(block->getLocation(), block);
|
||||||
|
block->onEnterWorld(this, reason);
|
||||||
|
block->location.setWorld(idWorld);
|
||||||
|
block->world = this;
|
||||||
|
Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int removeBlock(Block* block, const WorldTransportReason reason) {
|
||||||
|
if (!block) Failed();
|
||||||
|
if (block->getLocation().getWorld() != idWorld) Failed();
|
||||||
|
if (!blocks.erase(block->getLocation())) Failed();
|
||||||
|
if (!reason.isBlockReason()) Failed();
|
||||||
|
block->onExitWorld(this, reason);
|
||||||
|
block->location.setWorld(0);
|
||||||
|
block->world = nullptr;
|
||||||
|
Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int removeBlockAt(const BlockLocation& location, const WorldTransportReason reason) {
|
||||||
|
if (!reason.isBlockReason()) Failed();
|
||||||
|
if (location.getWorld() != idWorld) Failed();
|
||||||
|
const IterBlock it = blocks.find(location);
|
||||||
|
if (it == blocks.cend()) Failed();
|
||||||
|
Block* block = it->second;
|
||||||
|
blocks.erase(it);
|
||||||
|
block->onExitWorld(this, reason);
|
||||||
|
block->location.setWorld(0);
|
||||||
|
block->world = nullptr;
|
||||||
|
Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void onRemove() {
|
||||||
|
// Entity不需要再此处删除,交给EntityManager管理
|
||||||
|
for (auto& [id, entity] : entities) {
|
||||||
|
entity->onExitWorld(this, WorldTransportReason::WorldCollapse);
|
||||||
|
entity->location.setWorld(0);
|
||||||
|
entity->world = nullptr;
|
||||||
|
}
|
||||||
|
for (auto& [location, block] : blocks) {
|
||||||
|
block->onExitWorld(this, WorldTransportReason::WorldCollapse);
|
||||||
|
block->location.setWorld(0);
|
||||||
|
block->world = nullptr;
|
||||||
|
block->onRemove();
|
||||||
|
}
|
||||||
|
gc.submit<World>(this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class WorldManager {
|
class WorldManager {
|
||||||
|
friend class Game;
|
||||||
|
WorldID nextID = 0;
|
||||||
|
Map<WorldID, World*> worlds;
|
||||||
|
World* current = nullptr;
|
||||||
|
WorldManager() = default;
|
||||||
|
~WorldManager() {
|
||||||
|
Logger.debug(L"~WorldManager() called");
|
||||||
|
for (auto& [id, world] : worlds) world->onRemove();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
int addWorld(World* world) {
|
||||||
|
if (!world) Failed();
|
||||||
|
if (world->idWorld) Failed();
|
||||||
|
world->idWorld = ++nextID;
|
||||||
|
worlds.emplace(world->idWorld, world);
|
||||||
|
Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
int removeWorld(World* world) {
|
||||||
|
if (!world) Failed();
|
||||||
|
if (!world->idWorld) Failed();
|
||||||
|
world->idWorld = 0;
|
||||||
|
worlds.erase(world->idWorld);
|
||||||
|
world->onRemove();
|
||||||
|
Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
int setWorld(World* world) {
|
||||||
|
if (!world) Failed();
|
||||||
|
if (world->idWorld) Failed();
|
||||||
|
current = world;
|
||||||
|
Success();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class StartWorld final : public World {
|
||||||
|
StartWorld() = default;
|
||||||
|
~StartWorld() override { Logger.debug(L"~StartWorld() called"); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
void tick() noexcept override {}
|
||||||
|
|
||||||
|
static StartWorld* create() {
|
||||||
|
StartWorld* world = allocatedFor(new StartWorld);
|
||||||
|
world->addBlock(PureBarrierBlock::create(BlockLocation(0, 0)), WorldTransportReason::InitialGeneration);
|
||||||
|
world->addBlock(PureBarrierBlock::create(BlockLocation(1, 0)), WorldTransportReason::InitialGeneration);
|
||||||
|
world->addBlock(PureBarrierBlock::create(BlockLocation(2, 0)), WorldTransportReason::InitialGeneration);
|
||||||
|
world->addBlock(PureBarrierBlock::create(BlockLocation(3, 0)), WorldTransportReason::InitialGeneration);
|
||||||
|
world->addBlock(PureBarrierBlock::create(BlockLocation(4, 0)), WorldTransportReason::InitialGeneration);
|
||||||
|
return world;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,10 +16,8 @@ inline HRESULT RemoveDefaultCaption(const HWND hWnd, const MARGINS* p) noexcept
|
|||||||
|
|
||||||
inline bool ShowConsoleIO() noexcept {
|
inline bool ShowConsoleIO() noexcept {
|
||||||
AllocConsole();
|
AllocConsole();
|
||||||
FILE* pCout;
|
freopen("CONOUT$", "w", stdout);
|
||||||
freopen_s(&pCout, "CONOUT$", "w", stdout);
|
freopen("CONOUT$", "r+", stdin);
|
||||||
FILE* pCin;
|
|
||||||
freopen_s(&pCin, "CONOUT$", "r+", stdin);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -8,20 +8,21 @@
|
|||||||
|
|
||||||
// Any include
|
// Any include
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
#include "utils\math.h"
|
#include "utils\math.h" // required by Location.h
|
||||||
#include "utils\File.h"
|
#include "utils\File.h"
|
||||||
#include "utils\exception.h"
|
#include "utils\exception.h"
|
||||||
|
#include "utils\Chars.h"
|
||||||
|
|
||||||
// utils serialized
|
// utils serialized
|
||||||
#include "utils\gc.h"
|
#include "utils\gc.h" // required by utils.h
|
||||||
#include "utils\utils.h"
|
#include "utils\utils.h" // required by Task.h
|
||||||
#include "hbp.h"
|
|
||||||
#include "utils\Chars.h"
|
|
||||||
#include "utils\Task.h"
|
#include "utils\Task.h"
|
||||||
|
#include "hbp.h"
|
||||||
|
|
||||||
// game basic
|
// game basic
|
||||||
#include "interact\InteractManager.h"
|
#include "interact\InteractManager.h"
|
||||||
#include "utils\IText.h"
|
#include "utils\IText.h"
|
||||||
|
#include "game\world\Location.h" // required by Renderer.h
|
||||||
#include "render\Renderer.h"
|
#include "render\Renderer.h"
|
||||||
#include "game\Animation.h"
|
#include "game\Animation.h"
|
||||||
#include "render\TextureManager.h"
|
#include "render\TextureManager.h"
|
||||||
@@ -33,7 +34,7 @@
|
|||||||
|
|
||||||
// game extension
|
// game extension
|
||||||
#include "ui\xWindows.h"
|
#include "ui\xWindows.h"
|
||||||
#include "game\world\Location.h"
|
|
||||||
#include "game\entity\Entity.h"
|
#include "game\entity\Entity.h"
|
||||||
|
#include "game\world\Block.h"
|
||||||
#include "game\world\World.h"
|
#include "game\world\World.h"
|
||||||
#include "game\entity\Player.h"
|
#include "game\entity\Player.h"
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ class InteractSettings {
|
|||||||
int marginWidth = 40;
|
int marginWidth = 40;
|
||||||
int fontHeight = 96;
|
int fontHeight = 96;
|
||||||
int floatWindowMargin = 16;
|
int floatWindowMargin = 16;
|
||||||
|
double mapScale = 32.0; // 1格表现为32像素
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Constants {
|
struct Constants {
|
||||||
@@ -215,12 +216,15 @@ class InteractSettings {
|
|||||||
*/
|
*/
|
||||||
double uiScale = 1;
|
double uiScale = 1;
|
||||||
double screenScale = 1;
|
double screenScale = 1;
|
||||||
|
double smoothCamera = 0.5; // 相机平滑度。为0,始终瞬时设置相机的位置;为1,相机不动。
|
||||||
|
long long msPerTick = 50;
|
||||||
|
long long msPerRender = 16;
|
||||||
unsigned int floatWindowBackground = 0xdd000000;
|
unsigned int floatWindowBackground = 0xdd000000;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Options options;
|
Options options; // 用户设置值
|
||||||
Options actual;
|
Options actual; // 适应Scale后的实际值
|
||||||
Constants constants;
|
Constants constants;
|
||||||
|
|
||||||
InteractSettings& setUiScale(const double scale) noexcept {
|
InteractSettings& setUiScale(const double scale) noexcept {
|
||||||
|
|||||||
+279
-16
@@ -1,6 +1,271 @@
|
|||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
#include "utils/TestCode.h"
|
#include "utils\TestCode.h"
|
||||||
|
|
||||||
|
long __stdcall UnhandledExceptionHandler(PEXCEPTION_POINTERS exception) {
|
||||||
|
isRunning = false;
|
||||||
|
Logger.error(L"Unhandled exception handler called");
|
||||||
|
const auto ContextRecord = exception->ContextRecord;
|
||||||
|
const auto ExceptionRecord = exception->ExceptionRecord;
|
||||||
|
Logger.print(
|
||||||
|
std::hex,
|
||||||
|
L"Register parameter home addresses:"
|
||||||
|
L"\n P1Home", ContextRecord->P1Home,
|
||||||
|
L"\n P2Home", ContextRecord->P2Home,
|
||||||
|
L"\n P3Home", ContextRecord->P3Home,
|
||||||
|
L"\n P4Home", ContextRecord->P4Home,
|
||||||
|
L"\n P5Home", ContextRecord->P5Home,
|
||||||
|
L"\n P6Home", ContextRecord->P6Home);
|
||||||
|
Logger.print(
|
||||||
|
L"Control Flags:"
|
||||||
|
L"\n ContextFlags", ContextRecord->ContextFlags,
|
||||||
|
L"\n MxCsr", ContextRecord->MxCsr);
|
||||||
|
Logger.print(
|
||||||
|
L"Segment Registers and processor flags:"
|
||||||
|
L"\n SegCs", ContextRecord->SegCs,
|
||||||
|
L"\n SegDs", ContextRecord->SegDs,
|
||||||
|
L"\n SegEs", ContextRecord->SegEs,
|
||||||
|
L"\n SegFs", ContextRecord->SegFs,
|
||||||
|
L"\n SegGs", ContextRecord->SegGs,
|
||||||
|
L"\n SegSs", ContextRecord->SegSs,
|
||||||
|
L"\n EFlags", ContextRecord->EFlags);
|
||||||
|
Logger.print(
|
||||||
|
L"Debug registers:"
|
||||||
|
L"\n Dr0", ContextRecord->Dr0,
|
||||||
|
L"\n Dr1", ContextRecord->Dr1,
|
||||||
|
L"\n Dr2", ContextRecord->Dr2,
|
||||||
|
L"\n Dr3", ContextRecord->Dr3,
|
||||||
|
L"\n Dr6", ContextRecord->Dr6,
|
||||||
|
L"\n Dr7", ContextRecord->Dr7);
|
||||||
|
Logger.print(
|
||||||
|
L"Integer registers:"
|
||||||
|
L"\n Rax", ContextRecord->Rax,
|
||||||
|
L"\n Rcx", ContextRecord->Rcx,
|
||||||
|
L"\n Rdx", ContextRecord->Rdx,
|
||||||
|
L"\n Rbx", ContextRecord->Rbx,
|
||||||
|
L"\n Rsp", ContextRecord->Rsp,
|
||||||
|
L"\n Rbp", ContextRecord->Rbp,
|
||||||
|
L"\n Rsi", ContextRecord->Rsi,
|
||||||
|
L"\n Rdi", ContextRecord->Rdi,
|
||||||
|
L"\n R8", ContextRecord->R8,
|
||||||
|
L"\n R9", ContextRecord->R9,
|
||||||
|
L"\n R10", ContextRecord->R10,
|
||||||
|
L"\n R11", ContextRecord->R11,
|
||||||
|
L"\n R12", ContextRecord->R12,
|
||||||
|
L"\n R13", ContextRecord->R13,
|
||||||
|
L"\n R14", ContextRecord->R14,
|
||||||
|
L"\n R15", ContextRecord->R15);
|
||||||
|
Logger.print(
|
||||||
|
L"Program Counter:"
|
||||||
|
L"\n Rip", ContextRecord->Rip);
|
||||||
|
Logger.print(
|
||||||
|
L"Floating point state:"
|
||||||
|
L"\n XMM_SAVE_AREA32:"
|
||||||
|
L"\n ControlWord", ContextRecord->FltSave.ControlWord,
|
||||||
|
L"\n StatusWord", ContextRecord->FltSave.StatusWord,
|
||||||
|
L"\n TagWord", ContextRecord->FltSave.TagWord,
|
||||||
|
L"\n Reserved1", ContextRecord->FltSave.Reserved1,
|
||||||
|
L"\n ErrorOpcode", ContextRecord->FltSave.ErrorOpcode,
|
||||||
|
L"\n ErrorOffset", ContextRecord->FltSave.ErrorOffset,
|
||||||
|
L"\n ErrorSelector", ContextRecord->FltSave.ErrorSelector,
|
||||||
|
L"\n Reserved2", ContextRecord->FltSave.Reserved2,
|
||||||
|
L"\n DataOffset", ContextRecord->FltSave.DataOffset,
|
||||||
|
L"\n DataSelector", ContextRecord->FltSave.DataSelector,
|
||||||
|
L"\n Reserved3", ContextRecord->FltSave.Reserved3,
|
||||||
|
L"\n MxCsr", ContextRecord->FltSave.MxCsr,
|
||||||
|
L"\n MxCsr_Mask", ContextRecord->FltSave.MxCsr_Mask);
|
||||||
|
Logger.print(
|
||||||
|
L"\n FloatRegisters[0]",
|
||||||
|
ContextRecord->FltSave.FloatRegisters[0].High,
|
||||||
|
ContextRecord->FltSave.FloatRegisters[0].Low,
|
||||||
|
L"\n FloatRegisters[1]",
|
||||||
|
ContextRecord->FltSave.FloatRegisters[1].High,
|
||||||
|
ContextRecord->FltSave.FloatRegisters[1].Low,
|
||||||
|
L"\n FloatRegisters[2]",
|
||||||
|
ContextRecord->FltSave.FloatRegisters[2].High,
|
||||||
|
ContextRecord->FltSave.FloatRegisters[2].Low,
|
||||||
|
L"\n FloatRegisters[3]",
|
||||||
|
ContextRecord->FltSave.FloatRegisters[3].High,
|
||||||
|
ContextRecord->FltSave.FloatRegisters[3].Low,
|
||||||
|
L"\n FloatRegisters[4]",
|
||||||
|
ContextRecord->FltSave.FloatRegisters[4].High,
|
||||||
|
ContextRecord->FltSave.FloatRegisters[4].Low,
|
||||||
|
L"\n FloatRegisters[5]",
|
||||||
|
ContextRecord->FltSave.FloatRegisters[5].High,
|
||||||
|
ContextRecord->FltSave.FloatRegisters[5].Low,
|
||||||
|
L"\n FloatRegisters[6]",
|
||||||
|
ContextRecord->FltSave.FloatRegisters[6].High,
|
||||||
|
ContextRecord->FltSave.FloatRegisters[6].Low,
|
||||||
|
L"\n FloatRegisters[7]",
|
||||||
|
ContextRecord->FltSave.FloatRegisters[7].High,
|
||||||
|
ContextRecord->FltSave.FloatRegisters[7].Low);
|
||||||
|
Logger.print(
|
||||||
|
L"\n XmmRegisters[]"
|
||||||
|
L"\n Xmm0",
|
||||||
|
ContextRecord->Xmm0.High,
|
||||||
|
ContextRecord->Xmm0.Low,
|
||||||
|
L"\n Xmm1",
|
||||||
|
ContextRecord->Xmm1.High,
|
||||||
|
ContextRecord->Xmm1.Low,
|
||||||
|
L"\n Xmm2",
|
||||||
|
ContextRecord->Xmm2.High,
|
||||||
|
ContextRecord->Xmm2.Low,
|
||||||
|
L"\n Xmm3",
|
||||||
|
ContextRecord->Xmm3.High,
|
||||||
|
ContextRecord->Xmm3.Low,
|
||||||
|
L"\n Xmm4",
|
||||||
|
ContextRecord->Xmm4.High,
|
||||||
|
ContextRecord->Xmm4.Low,
|
||||||
|
L"\n Xmm5",
|
||||||
|
ContextRecord->Xmm5.High,
|
||||||
|
ContextRecord->Xmm5.Low,
|
||||||
|
L"\n Xmm6",
|
||||||
|
ContextRecord->Xmm6.High,
|
||||||
|
ContextRecord->Xmm6.Low,
|
||||||
|
L"\n Xmm7",
|
||||||
|
ContextRecord->Xmm7.High,
|
||||||
|
ContextRecord->Xmm7.Low,
|
||||||
|
L"\n Xmm8",
|
||||||
|
ContextRecord->Xmm8.High,
|
||||||
|
ContextRecord->Xmm8.Low,
|
||||||
|
L"\n Xmm9",
|
||||||
|
ContextRecord->Xmm9.High,
|
||||||
|
ContextRecord->Xmm9.Low,
|
||||||
|
L"\n Xmm10",
|
||||||
|
ContextRecord->Xmm10.High,
|
||||||
|
ContextRecord->Xmm10.Low,
|
||||||
|
L"\n Xmm11",
|
||||||
|
ContextRecord->Xmm11.High,
|
||||||
|
ContextRecord->Xmm11.Low,
|
||||||
|
L"\n Xmm12",
|
||||||
|
ContextRecord->Xmm12.High,
|
||||||
|
ContextRecord->Xmm12.Low,
|
||||||
|
L"\n Xmm13",
|
||||||
|
ContextRecord->Xmm13.High,
|
||||||
|
ContextRecord->Xmm13.Low,
|
||||||
|
L"\n Xmm14",
|
||||||
|
ContextRecord->Xmm14.High,
|
||||||
|
ContextRecord->Xmm14.Low,
|
||||||
|
L"\n Xmm15",
|
||||||
|
ContextRecord->Xmm15.High,
|
||||||
|
ContextRecord->Xmm15.Low);
|
||||||
|
|
||||||
|
Logger.print(
|
||||||
|
"\nVectorRegister"
|
||||||
|
L"\n 0",
|
||||||
|
ContextRecord->VectorRegister[0].High,
|
||||||
|
ContextRecord->VectorRegister[0].Low,
|
||||||
|
"\n 1",
|
||||||
|
ContextRecord->VectorRegister[1].High,
|
||||||
|
ContextRecord->VectorRegister[1].Low,
|
||||||
|
L"\n 2",
|
||||||
|
ContextRecord->VectorRegister[2].High,
|
||||||
|
ContextRecord->VectorRegister[2].Low,
|
||||||
|
L"\n 3",
|
||||||
|
ContextRecord->VectorRegister[3].High,
|
||||||
|
ContextRecord->VectorRegister[3].Low,
|
||||||
|
L"\n 4",
|
||||||
|
ContextRecord->VectorRegister[4].High,
|
||||||
|
ContextRecord->VectorRegister[4].Low,
|
||||||
|
L"\n 5",
|
||||||
|
ContextRecord->VectorRegister[5].High,
|
||||||
|
ContextRecord->VectorRegister[5].Low,
|
||||||
|
L"\n 6",
|
||||||
|
ContextRecord->VectorRegister[6].High,
|
||||||
|
ContextRecord->VectorRegister[6].Low,
|
||||||
|
L"\n 7",
|
||||||
|
ContextRecord->VectorRegister[7].High,
|
||||||
|
ContextRecord->VectorRegister[7].Low,
|
||||||
|
L"\n 8",
|
||||||
|
ContextRecord->VectorRegister[8].High,
|
||||||
|
ContextRecord->VectorRegister[8].Low,
|
||||||
|
L"\n 9",
|
||||||
|
ContextRecord->VectorRegister[9].High,
|
||||||
|
ContextRecord->VectorRegister[9].Low,
|
||||||
|
L"\n 10",
|
||||||
|
ContextRecord->VectorRegister[10].High,
|
||||||
|
ContextRecord->VectorRegister[10].Low,
|
||||||
|
L"\n 11",
|
||||||
|
ContextRecord->VectorRegister[11].High,
|
||||||
|
ContextRecord->VectorRegister[11].Low,
|
||||||
|
L"\n 12",
|
||||||
|
ContextRecord->VectorRegister[12].High,
|
||||||
|
ContextRecord->VectorRegister[12].Low,
|
||||||
|
L"\n 13",
|
||||||
|
ContextRecord->VectorRegister[13].High,
|
||||||
|
ContextRecord->VectorRegister[13].Low,
|
||||||
|
L"\n 14",
|
||||||
|
ContextRecord->VectorRegister[14].High,
|
||||||
|
ContextRecord->VectorRegister[14].Low,
|
||||||
|
L"\n 15",
|
||||||
|
ContextRecord->VectorRegister[15].High,
|
||||||
|
ContextRecord->VectorRegister[15].Low,
|
||||||
|
L"\n 16",
|
||||||
|
ContextRecord->VectorRegister[16].High,
|
||||||
|
ContextRecord->VectorRegister[16].Low,
|
||||||
|
L"\n 17",
|
||||||
|
ContextRecord->VectorRegister[17].High,
|
||||||
|
ContextRecord->VectorRegister[17].Low,
|
||||||
|
L"\n 18",
|
||||||
|
ContextRecord->VectorRegister[18].High,
|
||||||
|
ContextRecord->VectorRegister[18].Low,
|
||||||
|
L"\n 19",
|
||||||
|
ContextRecord->VectorRegister[19].High,
|
||||||
|
ContextRecord->VectorRegister[19].Low,
|
||||||
|
L"\n 20",
|
||||||
|
ContextRecord->VectorRegister[20].High,
|
||||||
|
ContextRecord->VectorRegister[20].Low,
|
||||||
|
L"\n 21",
|
||||||
|
ContextRecord->VectorRegister[21].High,
|
||||||
|
ContextRecord->VectorRegister[21].Low,
|
||||||
|
L"\n 22",
|
||||||
|
ContextRecord->VectorRegister[22].High,
|
||||||
|
ContextRecord->VectorRegister[22].Low,
|
||||||
|
L"\n 23",
|
||||||
|
ContextRecord->VectorRegister[23].High,
|
||||||
|
ContextRecord->VectorRegister[23].Low,
|
||||||
|
L"\n 24",
|
||||||
|
ContextRecord->VectorRegister[24].High,
|
||||||
|
ContextRecord->VectorRegister[24].Low,
|
||||||
|
L"\n 25",
|
||||||
|
ContextRecord->VectorRegister[25].High,
|
||||||
|
ContextRecord->VectorRegister[25].Low,
|
||||||
|
L"\n VectorControl", ContextRecord->VectorControl);
|
||||||
|
Logger.print(
|
||||||
|
L"\nSpecial debug control registers:"
|
||||||
|
L"\n DebugControl", ContextRecord->DebugControl,
|
||||||
|
L"\n LastBranchToRip", ContextRecord->LastBranchToRip,
|
||||||
|
L"\n LastBranchFromRip", ContextRecord->LastBranchFromRip,
|
||||||
|
L"\n LastExceptionToRip", ContextRecord->LastExceptionToRip,
|
||||||
|
L"\n LastExceptionFromRip", ContextRecord->LastExceptionFromRip
|
||||||
|
);
|
||||||
|
|
||||||
|
Logger.print(
|
||||||
|
L"\nExceptionRecord:"
|
||||||
|
L"\n ExceptionCode", ExceptionRecord->ExceptionCode,
|
||||||
|
L"\n ExceptionFlags", ExceptionRecord->ExceptionFlags,
|
||||||
|
L"\n ExceptionAddress", ExceptionRecord->ExceptionAddress,
|
||||||
|
L"\n NumberParameters", ExceptionRecord->NumberParameters,
|
||||||
|
L"\n ExceptionInformation",
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[0],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[1],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[2],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[3],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[4],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[5],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[6],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[7],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[8],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[9],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[10],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[11],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[12],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[13],
|
||||||
|
L"\n ", ExceptionRecord->ExceptionInformation[14]
|
||||||
|
);
|
||||||
|
|
||||||
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
|
}
|
||||||
|
|
||||||
LRESULT __stdcall WndProc(const HWND hwnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) {
|
LRESULT __stdcall WndProc(const HWND hwnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam) {
|
||||||
switch (uMsg) {
|
switch (uMsg) {
|
||||||
@@ -199,14 +464,16 @@ LRESULT __stdcall HookProc(const int code, const WPARAM wParam, const LPARAM lPa
|
|||||||
return CallNextHookEx(nullptr, code, wParam, lParam);
|
return CallNextHookEx(nullptr, code, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using Time = std::chrono::time_point<std::chrono::system_clock>;
|
||||||
|
Time lastTick = std::chrono::system_clock::now();
|
||||||
|
|
||||||
void gameThread() {
|
void gameThread() {
|
||||||
try {
|
try {
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
using Time = time_point<system_clock>;
|
using Time = time_point<system_clock>;
|
||||||
Time lastTick = system_clock::now();
|
|
||||||
while (isRunning) {
|
while (isRunning) {
|
||||||
const Time thisTime = system_clock::now();
|
const Time thisTime = system_clock::now();
|
||||||
if (thisTime - lastTick < milliseconds(45)) {
|
if (thisTime - lastTick < milliseconds(interactSettings.constants.msPerTick)) {
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -229,11 +496,11 @@ void renderThread() {
|
|||||||
Time lastRender = system_clock::now();
|
Time lastRender = system_clock::now();
|
||||||
while (isRunning) {
|
while (isRunning) {
|
||||||
const Time thisTime = system_clock::now();
|
const Time thisTime = system_clock::now();
|
||||||
if (thisTime - lastRender < milliseconds(12)) {
|
if (thisTime - lastRender < milliseconds(interactSettings.constants.msPerRender)) {
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
game.render();
|
game.render(nRange(static_cast<double>((thisTime - lastTick).count()) / interactSettings.constants.msPerRender, 0.0, 1.0));
|
||||||
lastRender = thisTime;
|
lastRender = thisTime;
|
||||||
}
|
}
|
||||||
} catch (const Exception& e) { Logger.log(L"Render thread exception: " + e.getMessage()); }
|
} catch (const Exception& e) { Logger.log(L"Render thread exception: " + e.getMessage()); }
|
||||||
@@ -246,6 +513,7 @@ void renderThread() {
|
|||||||
int __stdcall wWinMain(const HINSTANCE hInstance, const HINSTANCE, [[maybe_unused]] const LPWSTR lpCmdLine, [[maybe_unused]] const int nShowCmd) {
|
int __stdcall wWinMain(const HINSTANCE hInstance, const HINSTANCE, [[maybe_unused]] const LPWSTR lpCmdLine, [[maybe_unused]] const int nShowCmd) {
|
||||||
Logger.info(L"wWinMain started");
|
Logger.info(L"wWinMain started");
|
||||||
SetConsoleOutputCP(65001);
|
SetConsoleOutputCP(65001);
|
||||||
|
SetUnhandledExceptionFilter(UnhandledExceptionFilter);
|
||||||
translator.initialize();
|
translator.initialize();
|
||||||
Logger.info(L"--------Program Start--------");
|
Logger.info(L"--------Program Start--------");
|
||||||
for (const auto& [addr, info] : memoryManager.allocated) { Logger.print(L" using", addr, info.size, L"B", info.msg); }
|
for (const auto& [addr, info] : memoryManager.allocated) { Logger.print(L" using", addr, info.size, L"B", info.msg); }
|
||||||
@@ -295,6 +563,9 @@ int __stdcall wWinMain(const HINSTANCE hInstance, const HINSTANCE, [[maybe_unuse
|
|||||||
{
|
{
|
||||||
game.initialize();
|
game.initialize();
|
||||||
interactManager.initialize();
|
interactManager.initialize();
|
||||||
|
World* w = StartWorld::create();
|
||||||
|
game.worldManager->addWorld(w);
|
||||||
|
game.worldManager->setWorld(w);
|
||||||
GameThread = Thread(gameThread);
|
GameThread = Thread(gameThread);
|
||||||
RenderThread = Thread(renderThread);
|
RenderThread = Thread(renderThread);
|
||||||
}
|
}
|
||||||
@@ -315,16 +586,8 @@ int __stdcall wWinMain(const HINSTANCE hInstance, const HINSTANCE, [[maybe_unuse
|
|||||||
Logger.info(L"------- Program End --------");
|
Logger.info(L"------- Program End --------");
|
||||||
for (const auto& [addr, info] : memoryManager.allocated) { Logger.print(L" using", addr, info.size, L"B", info.msg); }
|
for (const auto& [addr, info] : memoryManager.allocated) { Logger.print(L" using", addr, info.size, L"B", info.msg); }
|
||||||
_wsystem(L"pause");
|
_wsystem(L"pause");
|
||||||
|
{
|
||||||
|
fontManager.finalize(); // 似乎GDI有终止自动回收,所以此代码需要提前
|
||||||
|
}
|
||||||
return static_cast<int>(msg.wParam);
|
return static_cast<int>(msg.wParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Release {
|
|
||||||
Release() = default;
|
|
||||||
|
|
||||||
~Release() {
|
|
||||||
delete &gc;
|
|
||||||
Logger.put(L"--------- Last Check ---------\n");
|
|
||||||
for (const auto& [addr, info] : memoryManager.allocated) { Logger.print(L" using", addr, info.size, L"B", info.msg); }
|
|
||||||
delete &Logger;
|
|
||||||
}
|
|
||||||
} NEVER_REFERENCED_release;
|
|
||||||
|
|||||||
+75
-15
@@ -5,8 +5,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "..\def.h"
|
#include "..\def.h"
|
||||||
|
#include "..\utils\math.h"
|
||||||
#include "..\utils\exception.h"
|
#include "..\utils\exception.h"
|
||||||
#include "..\utils\Task.h"
|
#include "..\utils\Task.h"
|
||||||
|
#include "..\interact\InteractManager.h"
|
||||||
|
#include "..\game\world\Location.h"
|
||||||
|
|
||||||
class Game;
|
class Game;
|
||||||
|
|
||||||
@@ -17,7 +20,7 @@ enum class UILocation : char { LEFT_TOP, LEFT, LEFT_BOTTOM, TOP, CENTER, BOTTOM,
|
|||||||
|
|
||||||
interface IRenderable {
|
interface IRenderable {
|
||||||
virtual ~IRenderable() = default;
|
virtual ~IRenderable() = default;
|
||||||
virtual void render() const noexcept = 0;
|
virtual void render(double tickDelta) const noexcept = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ITickable {
|
interface ITickable {
|
||||||
@@ -39,16 +42,36 @@ inline static constexpr Color TextColor = {
|
|||||||
.clicked = 0xff000000
|
.clicked = 0xff000000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class [[carlbeks::predecl, carlbeks::defineat("Entity.h")]] Entity;
|
||||||
|
|
||||||
|
class Camera {
|
||||||
|
Vector2D position; // 当前位置
|
||||||
|
Vector2D velocity; // 移动速度,如果设置了平滑Camera
|
||||||
|
Vector2D targetPosition; // Camera需要移动到的位置
|
||||||
|
Entity* targeting = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setTargetEntity(Entity* target) noexcept { targeting = target; }
|
||||||
|
[[nodiscard]] double getCurrentX() const noexcept { return position.getX(); }
|
||||||
|
[[nodiscard]] double getCurrentY() const noexcept { return position.getY(); }
|
||||||
|
[[nodiscard]] double getTargetX() const noexcept { return targetPosition.getX(); }
|
||||||
|
[[nodiscard]] double getTargetY() const noexcept { return targetPosition.getY(); }
|
||||||
|
[[nodiscard]] Vector2D getCurrentPosition() const noexcept { return position; }
|
||||||
|
[[nodiscard]] Vector2D getVelocity() const noexcept { return velocity; }
|
||||||
|
[[nodiscard]] Vector2D getTargetPosition() const noexcept { return targetPosition; }
|
||||||
|
};
|
||||||
|
|
||||||
class Renderer final : public ITickable {
|
class Renderer final : public ITickable {
|
||||||
friend class Game;
|
friend class Game;
|
||||||
friend class Font;
|
friend class Font;
|
||||||
mutable List<HGDIOBJ> failed;
|
|
||||||
inline static BLENDFUNCTION blendFunction = {
|
inline static BLENDFUNCTION blendFunction = {
|
||||||
.BlendOp = AC_SRC_OVER, // Only
|
.BlendOp = AC_SRC_OVER, // Only
|
||||||
.BlendFlags = 0, // Must 0
|
.BlendFlags = 0, // Must 0
|
||||||
.SourceConstantAlpha = 255, // 预乘
|
.SourceConstantAlpha = 255, // 预乘
|
||||||
.AlphaFormat = 0, // Not AC_SRC_ALPHA
|
.AlphaFormat = 0, // Not AC_SRC_ALPHA
|
||||||
};
|
};
|
||||||
|
mutable List<HGDIOBJ> failed;
|
||||||
|
mutable Camera camera;
|
||||||
HDC MainDC = nullptr; // 8
|
HDC MainDC = nullptr; // 8
|
||||||
HDC resizeCopyDC = nullptr; // 8
|
HDC resizeCopyDC = nullptr; // 8
|
||||||
HBITMAP resizeCopyBitmap = nullptr; // 8
|
HBITMAP resizeCopyBitmap = nullptr; // 8
|
||||||
@@ -72,7 +95,8 @@ class Renderer final : public ITickable {
|
|||||||
public:
|
public:
|
||||||
byte windowSize = 0; // 1, Windows: SIZE_***
|
byte windowSize = 0; // 1, Windows: SIZE_***
|
||||||
byte reserved[5]{};
|
byte reserved[5]{};
|
||||||
Task resizeReloadBitmap{ [this](Task& task) {
|
Task resizeReloadBitmap{
|
||||||
|
[this](Task& task) {
|
||||||
Logger.info(L"Scheduled task: resize reload bitmap " + std::to_wstring(windowWidth) + L" * " + std::to_wstring(windowHeight));
|
Logger.info(L"Scheduled task: resize reload bitmap " + std::to_wstring(windowWidth) + L" * " + std::to_wstring(windowHeight));
|
||||||
if (!canvasBitmap) {
|
if (!canvasBitmap) {
|
||||||
canvasBitmap = CreateCompatibleBitmap(MainDC, windowWidth, windowHeight);
|
canvasBitmap = CreateCompatibleBitmap(MainDC, windowWidth, windowHeight);
|
||||||
@@ -87,7 +111,8 @@ public:
|
|||||||
Logger.info(L"Successfully reload bitmap " + ptrtow(reinterpret_cast<QWORD>(canvasBitmap)) + L" " + ptrtow(reinterpret_cast<QWORD>(assistBitmap)));
|
Logger.info(L"Successfully reload bitmap " + ptrtow(reinterpret_cast<QWORD>(canvasBitmap)) + L" " + ptrtow(reinterpret_cast<QWORD>(assistBitmap)));
|
||||||
this->resizeEnd();
|
this->resizeEnd();
|
||||||
}
|
}
|
||||||
} };
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void gameStartRender() noexcept;
|
void gameStartRender() noexcept;
|
||||||
@@ -118,20 +143,16 @@ public:
|
|||||||
[[nodiscard]] int getSyncHeight() const noexcept { return syncHeight; }
|
[[nodiscard]] int getSyncHeight() const noexcept { return syncHeight; }
|
||||||
[[nodiscard]] bool checkResizing() const noexcept { return isResizing; }
|
[[nodiscard]] bool checkResizing() const noexcept { return isResizing; }
|
||||||
void tick() noexcept override {}
|
void tick() noexcept override {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @attention 会忽略A透明度值
|
* @attention 会忽略A透明度值
|
||||||
* @param argb ARGB式颜色
|
* @param argb ARGB式颜色
|
||||||
* @return int BGR式颜色
|
* @return int BGR式颜色
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] static unsigned int changeColorFormat(const unsigned int argb) { return argb << 16 & 0xff0000 | argb & 0xff00 | argb >> 16 & 0xff; }
|
[[nodiscard]] static unsigned int changeColorFormat(const unsigned int argb) { return argb << 16 & 0xff0000 | argb & 0xff00 | argb >> 16 & 0xff; }
|
||||||
|
|
||||||
void assertRendering() const noexcept(false) { if (!isRendering) throw InvalidOperationException(L"Operation should be done while rendering"); }
|
void assertRendering() const noexcept(false) { if (!isRendering) throw InvalidOperationException(L"Operation should be done while rendering"); }
|
||||||
|
|
||||||
void assertRenderThread() const noexcept(false) { if (std::this_thread::get_id() != renderThread) throw InvalidOperationException(L"Operation should be done in render thread"); }
|
void assertRenderThread() const noexcept(false) { if (std::this_thread::get_id() != renderThread) throw InvalidOperationException(L"Operation should be done in render thread"); }
|
||||||
|
Camera& getCamera() const noexcept { return camera; }
|
||||||
void resizeStart() noexcept { isResizing = true; }
|
void resizeStart() noexcept { isResizing = true; }
|
||||||
|
|
||||||
void resizeShow() const noexcept { StretchBlt(MainDC, 0, 0, syncWidth, syncHeight, resizeCopyDC, 0, 0, resizeCopyWidth, resizeCopyHeight, SRCCOPY); }
|
void resizeShow() const noexcept { StretchBlt(MainDC, 0, 0, syncWidth, syncHeight, resizeCopyDC, 0, 0, resizeCopyWidth, resizeCopyHeight, SRCCOPY); }
|
||||||
|
|
||||||
void resizeEnd() noexcept {
|
void resizeEnd() noexcept {
|
||||||
@@ -143,9 +164,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void deleteObject(HGDIOBJ obj) const noexcept {
|
void deleteObject(HGDIOBJ obj) const noexcept {
|
||||||
for (List<HGDIOBJ>::const_iterator iter = failed.cbegin(); iter != failed.cend(); ++iter)
|
List<HGDIOBJ> tempList;
|
||||||
if (!DeleteObject(*iter)) Logger.error(L"DeleteObject failed again. Deleting: " + std::to_wstring(reinterpret_cast<QWORD>(*iter)));
|
tempList.swap(failed);
|
||||||
else failed.erase(iter);
|
for (List<HGDIOBJ>::const_iterator iter = tempList.cbegin(); iter != tempList.cend(); ++iter)
|
||||||
|
if (!DeleteObject(*iter)) {
|
||||||
|
Logger.error(L"DeleteObject failed again. Deleting: " + std::to_wstring(reinterpret_cast<QWORD>(*iter)));
|
||||||
|
failed.push_back(*iter);
|
||||||
|
}
|
||||||
if (obj && !DeleteObject(obj)) {
|
if (obj && !DeleteObject(obj)) {
|
||||||
failed.push_back(obj);
|
failed.push_back(obj);
|
||||||
Logger.error(L"DeleteObject failed. Deleting: " + std::to_wstring(reinterpret_cast<QWORD>(obj)));
|
Logger.error(L"DeleteObject failed. Deleting: " + std::to_wstring(reinterpret_cast<QWORD>(obj)));
|
||||||
@@ -166,7 +191,8 @@ public:
|
|||||||
const HBRUSH clr = CreateSolidBrush(changeColorFormat(color));
|
const HBRUSH clr = CreateSolidBrush(changeColorFormat(color));
|
||||||
FillRect(canvasDC, &rect, clr);
|
FillRect(canvasDC, &rect, clr);
|
||||||
deleteObject(clr);
|
deleteObject(clr);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
const RECT rect{
|
const RECT rect{
|
||||||
.left = 0,
|
.left = 0,
|
||||||
.top = 0,
|
.top = 0,
|
||||||
@@ -185,10 +211,12 @@ public:
|
|||||||
assertRendering();
|
assertRendering();
|
||||||
//assertRenderThread();
|
//assertRenderThread();
|
||||||
if ((color & 0xff000000) == 0) return;
|
if ((color & 0xff000000) == 0) return;
|
||||||
if ((color & 0xff000000) == 0xff000000) { const HBRUSH clr = CreateSolidBrush(changeColorFormat(color));
|
if ((color & 0xff000000) == 0xff000000) {
|
||||||
|
const HBRUSH clr = CreateSolidBrush(changeColorFormat(color));
|
||||||
FillRect(canvasDC, rect, clr);
|
FillRect(canvasDC, rect, clr);
|
||||||
deleteObject(clr);
|
deleteObject(clr);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
const RECT r{
|
const RECT r{
|
||||||
.left = 0,
|
.left = 0,
|
||||||
.top = 0,
|
.top = 0,
|
||||||
@@ -202,6 +230,38 @@ public:
|
|||||||
if (!AlphaBlend(canvasDC, rect->left, rect->top, r.right, r.bottom, assistDC, 0, 0, r.right, r.bottom, blendFunction)) Logger.error(L"AlphaBlend failed");
|
if (!AlphaBlend(canvasDC, rect->left, rect->top, r.right, r.bottom, assistDC, 0, 0, r.right, r.bottom, blendFunction)) Logger.error(L"AlphaBlend failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fillWorld(const Vector2D& from, const Vector2D& to, const unsigned int color) const {
|
||||||
|
RECT rect{};
|
||||||
|
Vector2D vector = (from - camera.getCurrentPosition()) * interactSettings.actual.mapScale;
|
||||||
|
rect.left = static_cast<long>(vector.getX());
|
||||||
|
if (rect.left >= windowWidth) return;
|
||||||
|
rect.top = static_cast<long>(vector.getY());
|
||||||
|
if (rect.top >= windowHeight) return;
|
||||||
|
vector = (to - camera.getCurrentPosition()) * interactSettings.actual.mapScale;
|
||||||
|
rect.right = static_cast<long>(vector.getX());
|
||||||
|
if (rect.right < 0) return;
|
||||||
|
rect.bottom = static_cast<long>(vector.getY());
|
||||||
|
if (rect.bottom < 0) return;
|
||||||
|
fill(&rect, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillWorld(const Vector2D& from, const double blockWidth, const double blockHeight, const unsigned int color) const {
|
||||||
|
RECT rect{};
|
||||||
|
Vector2D vector = (from - camera.getCurrentPosition()) * interactSettings.actual.mapScale;
|
||||||
|
rect.left = static_cast<long>(vector.getX());
|
||||||
|
if (rect.left >= windowWidth) return;
|
||||||
|
rect.top = static_cast<long>(vector.getY());
|
||||||
|
if (rect.top >= windowHeight) return;
|
||||||
|
vector += Vector2D(blockWidth, blockHeight).multiply(interactSettings.actual.mapScale);
|
||||||
|
rect.right = static_cast<long>(vector.getX());
|
||||||
|
if (rect.right < 0) return;
|
||||||
|
rect.bottom = static_cast<long>(vector.getY());
|
||||||
|
if (rect.bottom < 0) return;
|
||||||
|
fill(&rect, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillWorldBlock(const BlockLocation& from, const unsigned int color) const { fillWorld(from.getPosition(), 1, 1, color); }
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Renderer renderer;
|
extern Renderer renderer;
|
||||||
|
|||||||
+1
-1
@@ -4,5 +4,5 @@
|
|||||||
|
|
||||||
#include "Hud.h"
|
#include "Hud.h"
|
||||||
|
|
||||||
void Hud::render() const noexcept {}
|
void Hud::render(double tickDelta) const noexcept {}
|
||||||
void Hud::tick() noexcept {}
|
void Hud::tick() noexcept {}
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
class Hud final : public IRenderable, public ITickable {
|
class Hud final : public IRenderable, public ITickable {
|
||||||
public:
|
public:
|
||||||
void render() const noexcept override;
|
void render(double tickDelta) const noexcept override;
|
||||||
void tick() noexcept override;
|
void tick() noexcept override;
|
||||||
void onResize() noexcept {}
|
void onResize() noexcept {}
|
||||||
};
|
};
|
||||||
|
|||||||
+9
-9
@@ -13,7 +13,7 @@ int Window::pop() noexcept {
|
|||||||
Success();
|
Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::render() const noexcept { for (const Widget* widget : widgets) widget->render(); }
|
void Window::render(const double tickDelta) const noexcept { for (const Widget* widget : widgets) widget->render(tickDelta); }
|
||||||
void Window::tick() noexcept { for (Widget* widget : widgets) widget->tick(); }
|
void Window::tick() noexcept { for (Widget* widget : widgets) widget->tick(); }
|
||||||
void Window::onResize() { for (Widget* widget : widgets) widget->onResize(); }
|
void Window::onResize() { for (Widget* widget : widgets) widget->onResize(); }
|
||||||
|
|
||||||
@@ -58,13 +58,13 @@ CaptionWindow::CaptionWindow() {
|
|||||||
close->foregroundColor.inactive = 0xff000000;
|
close->foregroundColor.inactive = 0xff000000;
|
||||||
close->foregroundColor.clicked = 0xff000000;
|
close->foregroundColor.clicked = 0xff000000;
|
||||||
|
|
||||||
Widget* maxRestore = widgets.emplace_back(Button(-interactSettings.actual.captionHeight, 0, interactSettings.actual.captionHeight, interactSettings.actual.captionHeight, UILocation::RIGHT_TOP, IsZoomed(MainWindowHandle) ? L"\\f\1🗗"_literal : L"\\f\1🗖"_literal ));
|
Widget* maxRestore = widgets.emplace_back(Button(-interactSettings.actual.captionHeight, 0, interactSettings.actual.captionHeight, interactSettings.actual.captionHeight, UILocation::RIGHT_TOP, IsZoomed(MainWindowHandle) ? L"\\f\1🗗"_literal : L"\\f\1🗖"_literal));
|
||||||
maxRestore->mouseClick = [](Widget&, MouseButtonCode) {};
|
maxRestore->mouseClick = [](Widget&, MouseButtonCode) {};
|
||||||
maxRestore->mouseClick = [](Widget& self, MouseButtonCode) {
|
maxRestore->mouseClick = [](Widget& self, MouseButtonCode) {
|
||||||
if ((self.unused[1] = static_cast<char>(IsZoomed(MainWindowHandle)))) ShowWindow(MainWindowHandle, SW_RESTORE);
|
if ((self.unused[1] = static_cast<char>(IsZoomed(MainWindowHandle)))) ShowWindow(MainWindowHandle, SW_RESTORE);
|
||||||
else ShowWindow(MainWindowHandle, SW_MAXIMIZE);
|
else ShowWindow(MainWindowHandle, SW_MAXIMIZE);
|
||||||
};
|
};
|
||||||
maxRestore->onTick = [](const Widget& self, MouseButtonCode) { if (self.containsMouse()) game.getFloatWindow().push(self.unused[1] ? TranslatableText(L"hbp.caption.maximize").getRenderableString() : TranslatableText(L"hbp.caption.restore").getRenderableString() ); };
|
maxRestore->onTick = [](const Widget& self, MouseButtonCode) { if (self.containsMouse()) game.getFloatWindow().push(self.unused[1] ? TranslatableText(L"hbp.caption.maximize").getRenderableString() : TranslatableText(L"hbp.caption.restore").getRenderableString()); };
|
||||||
maxRestore->absolute();
|
maxRestore->absolute();
|
||||||
maxRestore->unused[1] = static_cast<char>(IsZoomed(MainWindowHandle));
|
maxRestore->unused[1] = static_cast<char>(IsZoomed(MainWindowHandle));
|
||||||
maxRestore->backgroundColor.hover = 0xffcccccc;
|
maxRestore->backgroundColor.hover = 0xffcccccc;
|
||||||
@@ -111,9 +111,9 @@ CaptionWindow::CaptionWindow() {
|
|||||||
bool CaptionWindow::onOpen() { throw InvalidOperationException(L"Should not open CaptionWindow"); }
|
bool CaptionWindow::onOpen() { throw InvalidOperationException(L"Should not open CaptionWindow"); }
|
||||||
void CaptionWindow::onClose() { throw InvalidOperationException(L"Should not close CaptionWindow"); }
|
void CaptionWindow::onClose() { throw InvalidOperationException(L"Should not close CaptionWindow"); }
|
||||||
|
|
||||||
void CaptionWindow::render() const noexcept {
|
void CaptionWindow::render(const double tickDelta) const noexcept {
|
||||||
renderer.fill(0, 0, renderer.getWidth(), interactSettings.actual.captionHeight, 0xff666666);
|
renderer.fill(0, 0, renderer.getWidth(), interactSettings.actual.captionHeight, 0xff666666);
|
||||||
for (const Widget* widget : widgets) widget->render();
|
for (const Widget* widget : widgets) widget->render(tickDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CaptionWindow::onResize() {
|
void CaptionWindow::onResize() {
|
||||||
@@ -137,7 +137,7 @@ void CaptionWindow::onResize() {
|
|||||||
Window::onResize();
|
Window::onResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FloatWindow::render() const noexcept {
|
void FloatWindow::render(double tickDelta) const noexcept {
|
||||||
if (not interactManager.isInWindow()) {
|
if (not interactManager.isInWindow()) {
|
||||||
strings.async();
|
strings.async();
|
||||||
return;
|
return;
|
||||||
@@ -180,7 +180,7 @@ unsigned int Widget::colorSelector(const Color& clr) const {
|
|||||||
return clr.hover;
|
return clr.hover;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::render() const noexcept { renderer.fill(left, top, width, height, colorSelector(backgroundColor)); }
|
void Widget::render(double tickDelta) const noexcept { renderer.fill(left, top, width, height, colorSelector(backgroundColor)); }
|
||||||
|
|
||||||
void Widget::onResize() {
|
void Widget::onResize() {
|
||||||
if (isAbsoluteLocation) {
|
if (isAbsoluteLocation) {
|
||||||
@@ -268,8 +268,8 @@ void Widget::onResize() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Button::render() const noexcept {
|
void Button::render(const double tickDelta) const noexcept {
|
||||||
Widget::render();
|
Widget::render(tickDelta);
|
||||||
if (name) fontManager.getDefault().drawCenter(name->getRenderableString(), left, top, width, height, colorSelector(foregroundColor));
|
if (name) fontManager.getDefault().drawCenter(name->getRenderableString(), left, top, width, height, colorSelector(foregroundColor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -65,7 +65,7 @@ public:
|
|||||||
Widget(const double x, const double y, const double w, const double h, const UILocation location) : x(x), y(y), w(w), h(h), location(location) {}
|
Widget(const double x, const double y, const double w, const double h, const UILocation location) : x(x), y(y), w(w), h(h), location(location) {}
|
||||||
|
|
||||||
unsigned int colorSelector(const Color& clr) const;
|
unsigned int colorSelector(const Color& clr) const;
|
||||||
void render() const noexcept override;
|
void render(double tickDelta) const noexcept override;
|
||||||
|
|
||||||
Widget& alignLocation(const UILocation loc) noexcept {
|
Widget& alignLocation(const UILocation loc) noexcept {
|
||||||
location = loc;
|
location = loc;
|
||||||
@@ -155,7 +155,7 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
int pop() noexcept override;
|
int pop() noexcept override;
|
||||||
void render() const noexcept override;
|
void render(double tickDelta) const noexcept override;
|
||||||
void tick() noexcept override;
|
void tick() noexcept override;
|
||||||
/**
|
/**
|
||||||
* 在Game.setWindow()时,本窗口开启时调用。
|
* 在Game.setWindow()时,本窗口开启时调用。
|
||||||
@@ -176,7 +176,7 @@ public:
|
|||||||
|
|
||||||
class WindowManager final : public AnywhereEditableList<Window, WindowManager>, public IRenderable, public ITickable {
|
class WindowManager final : public AnywhereEditableList<Window, WindowManager>, public IRenderable, public ITickable {
|
||||||
public:
|
public:
|
||||||
void render() const noexcept override { for (const Window& i : *this) i.render(); }
|
void render(const double tickDelta) const noexcept override { for (const Window& i : *this) i.render(tickDelta); }
|
||||||
void tick() noexcept override { for (Window& i : *this) i.tick(); }
|
void tick() noexcept override { for (Window& i : *this) i.tick(); }
|
||||||
int pop(Window* value) noexcept override;
|
int pop(Window* value) noexcept override;
|
||||||
void clear() noexcept;
|
void clear() noexcept;
|
||||||
@@ -188,7 +188,7 @@ public:
|
|||||||
CaptionWindow();
|
CaptionWindow();
|
||||||
bool onOpen() override;
|
bool onOpen() override;
|
||||||
void onClose() override;
|
void onClose() override;
|
||||||
void render() const noexcept override;
|
void render(double tickDelta) const noexcept override;
|
||||||
void onResize() override;
|
void onResize() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -209,7 +209,7 @@ public:
|
|||||||
|
|
||||||
void push(const ObjectHolder<RenderableString>& string) const { if (strings.ptrNew()) strings.getNew().push_back(string); }
|
void push(const ObjectHolder<RenderableString>& string) const { if (strings.ptrNew()) strings.getNew().push_back(string); }
|
||||||
void push(ObjectHolder<RenderableString>&& string) const { if (strings.ptrNew()) strings.getNew().push_back(std::move(string)); }
|
void push(ObjectHolder<RenderableString>&& string) const { if (strings.ptrNew()) strings.getNew().push_back(std::move(string)); }
|
||||||
void render() const noexcept override;
|
void render(double tickDelta) const noexcept override;
|
||||||
void tick() noexcept override {}
|
void tick() noexcept override {}
|
||||||
bool onOpen() override { return true; }
|
bool onOpen() override { return true; }
|
||||||
void onClose() override {}
|
void onClose() override {}
|
||||||
@@ -222,7 +222,7 @@ public:
|
|||||||
Animation animation = Animation().features(Animation::AS_CUBIC).setDuration(20);
|
Animation animation = Animation().features(Animation::AS_CUBIC).setDuration(20);
|
||||||
Button(const double x, const double y, const double w, const double h, const UILocation location, const ObjectHolder<IText>& text) : Widget(x, y, w, h, location), name(text) {}
|
Button(const double x, const double y, const double w, const double h, const UILocation location, const ObjectHolder<IText>& text) : Widget(x, y, w, h, location), name(text) {}
|
||||||
Button(const double x, const double y, const double w, const double h, const UILocation location, ObjectHolder<IText>&& text) : Widget(x, y, w, h, location), name(std::move(text)) {}
|
Button(const double x, const double y, const double w, const double h, const UILocation location, ObjectHolder<IText>&& text) : Widget(x, y, w, h, location), name(std::move(text)) {}
|
||||||
void render() const noexcept override;
|
void render(double tickDelta) const noexcept override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -240,13 +240,13 @@ private:
|
|||||||
public:
|
public:
|
||||||
~ConfirmWindow() override = default; // 不需要delete,析构时Window会自动delete
|
~ConfirmWindow() override = default; // 不需要delete,析构时Window会自动delete
|
||||||
|
|
||||||
void render() const noexcept override {
|
void render(const double tickDelta) const noexcept override {
|
||||||
int w, h;
|
int w, h;
|
||||||
w = renderer.getWidth(), h = renderer.getHeight();
|
w = renderer.getWidth(), h = renderer.getHeight();
|
||||||
w >>= 2, h >>= 2;
|
w >>= 2, h >>= 2;
|
||||||
renderer.fill(w, h, w + w, h + h, 0xcc222222);
|
renderer.fill(w, h, w + w, h + h, 0xcc222222);
|
||||||
fontManager.getDefault().drawCenter(text->getRenderableString(), w, h, w + w, h + (h >> 1), 0xffeeeeee);
|
fontManager.getDefault().drawCenter(text->getRenderableString(), w, h, w + w, h + (h >> 1), 0xffeeeeee);
|
||||||
for (const ObjectHolder<Widget>& widget : widgets) widget->render();
|
for (const ObjectHolder<Widget>& widget : widgets) widget->render(tickDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfirmWindow& requireConfirm(const Function<void(Button&)>& func = {});
|
ConfirmWindow& requireConfirm(const Function<void(Button&)>& func = {});
|
||||||
|
|||||||
+2
-2
@@ -34,8 +34,8 @@ public:
|
|||||||
static StartWindow* create() noexcept { return allocatedFor(new StartWindow()); }
|
static StartWindow* create() noexcept { return allocatedFor(new StartWindow()); }
|
||||||
void onClose() override { pop(); }
|
void onClose() override { pop(); }
|
||||||
|
|
||||||
void render() const noexcept override {
|
void render(const double tickDelta) const noexcept override {
|
||||||
fontManager.getDefault().drawCenter(title.getRenderableString(), 0, 0, renderer.getWidth(), renderer.getHeight());
|
fontManager.getDefault().drawCenter(title.getRenderableString(), 0, 0, renderer.getWidth(), renderer.getHeight());
|
||||||
Window::render();
|
Window::render(tickDelta);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+15
-8
@@ -146,19 +146,22 @@ public:
|
|||||||
if (config.idFont == idFont || config.idFont != 0) {
|
if (config.idFont == idFont || config.idFont != 0) {
|
||||||
font = false;
|
font = false;
|
||||||
++flags;
|
++flags;
|
||||||
} else config.idFont = idFont;
|
}
|
||||||
|
else config.idFont = idFont;
|
||||||
}
|
}
|
||||||
if (clr) {
|
if (clr) {
|
||||||
if (config.color == color || config.color != 0xffffffff) {
|
if (config.color == color || config.color != 0xffffffff) {
|
||||||
clr = false;
|
clr = false;
|
||||||
++flags;
|
++flags;
|
||||||
} else config.color = color;
|
}
|
||||||
|
else config.color = color;
|
||||||
}
|
}
|
||||||
if (bg) {
|
if (bg) {
|
||||||
if (config.background == background || config.background != 0xffffffff) {
|
if (config.background == background || config.background != 0xffffffff) {
|
||||||
bg = false;
|
bg = false;
|
||||||
++flags;
|
++flags;
|
||||||
} else config.background = background;
|
}
|
||||||
|
else config.background = background;
|
||||||
}
|
}
|
||||||
configs.push_back(std::move(config));
|
configs.push_back(std::move(config));
|
||||||
++iterator;
|
++iterator;
|
||||||
@@ -374,14 +377,17 @@ private:
|
|||||||
const FontID id;
|
const FontID id;
|
||||||
bool adaptAllSize = false;
|
bool adaptAllSize = false;
|
||||||
|
|
||||||
Font(const FontID id, const String& name, const double heightModifier, const double yOffset, const long escapement, const long orientation, const bool adaptAllSize) : name{ name }, yOffset(yOffset), heightModifier(heightModifier), height(static_cast<long>(interactSettings.actual.fontHeight * heightModifier)), escapement(escapement), orientation(orientation), yOffsetPx(static_cast<long>(yOffset * height)), id(id), adaptAllSize(adaptAllSize) {}
|
Font(const FontID id, const String& name, const double heightModifier, const double yOffset, const long escapement, const long orientation, const bool adaptAllSize) : name{name}, yOffset(yOffset), heightModifier(heightModifier), height(static_cast<long>(interactSettings.actual.fontHeight * heightModifier)), escapement(escapement), orientation(orientation), yOffsetPx(static_cast<long>(yOffset * height)), id(id), adaptAllSize(adaptAllSize) {}
|
||||||
|
|
||||||
Font(const FontID id, String&& name, const double heightModifier, const double yOffset, const long escapement, const long orientation, const bool adaptAllSize) : name{ std::move(name) }, yOffset(yOffset), heightModifier(heightModifier), height(static_cast<long>(interactSettings.actual.fontHeight * heightModifier)), escapement(escapement), orientation(orientation), yOffsetPx(static_cast<long>(yOffset * height)), id(id), adaptAllSize(adaptAllSize) {}
|
Font(const FontID id, String&& name, const double heightModifier, const double yOffset, const long escapement, const long orientation, const bool adaptAllSize) : name{std::move(name)}, yOffset(yOffset), heightModifier(heightModifier), height(static_cast<long>(interactSettings.actual.fontHeight * heightModifier)), escapement(escapement), orientation(orientation), yOffsetPx(static_cast<long>(yOffset * height)), id(id), adaptAllSize(adaptAllSize) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Font(const Font&) = default;
|
Font(const Font&) = default;
|
||||||
Font(Font&&) = default;
|
Font(Font&&) = default;
|
||||||
~Font() { clear(); }
|
~Font() {
|
||||||
|
// 此处Font的回收已经到结束阶段,GDI应该已经收回了资源,不能在手动释放了
|
||||||
|
if (fonts.size()) Logger.warn(L"Font is not successfully cleared when ~Font() called: " + name);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HFONT tryCreate(const RenderableString::StringConfig& config) const {
|
HFONT tryCreate(const RenderableString::StringConfig& config) const {
|
||||||
@@ -447,6 +453,8 @@ public:
|
|||||||
newFont(L"", 1.0, -0.05);
|
newFont(L"", 1.0, -0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void finalize() { for (auto& [id, font] : fonts) font.clear(); }
|
||||||
|
|
||||||
[[nodiscard]] const Font& get(const FontID id) const noexcept {
|
[[nodiscard]] const Font& get(const FontID id) const noexcept {
|
||||||
const IterFonts iter = fonts.find(id);
|
const IterFonts iter = fonts.find(id);
|
||||||
if (iter == fonts.cend()) return *defaultFont;
|
if (iter == fonts.cend()) return *defaultFont;
|
||||||
@@ -543,7 +551,7 @@ void languageMakeChinese(Language&);
|
|||||||
class Translator {
|
class Translator {
|
||||||
Map<String, Language> langMap{};
|
Map<String, Language> langMap{};
|
||||||
List<Language*> langList{};
|
List<Language*> langList{};
|
||||||
TranslatedText nullText{ L"\\#FF""EE0000<translator-null>" };
|
TranslatedText nullText{L"\\#FF""EE0000<translator-null>"};
|
||||||
String lang = L"zh-cn";
|
String lang = L"zh-cn";
|
||||||
LangID idLangMax = 0;
|
LangID idLangMax = 0;
|
||||||
int langConfig = 1;
|
int langConfig = 1;
|
||||||
@@ -583,7 +591,6 @@ public:
|
|||||||
void loadLang();
|
void loadLang();
|
||||||
|
|
||||||
[[nodiscard]] const TranslatedText* getText(const String& id) const noexcept {
|
[[nodiscard]] const TranslatedText* getText(const String& id) const noexcept {
|
||||||
Logger.debug(L"getText called");
|
|
||||||
for (const Language* language : langList) {
|
for (const Language* language : langList) {
|
||||||
const Language::IterText iterator = language->translateTable.find(id);
|
const Language::IterText iterator = language->translateTable.find(id);
|
||||||
if (iterator != language->translateTable.cend()) return &iterator->second;
|
if (iterator != language->translateTable.cend()) return &iterator->second;
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ public:
|
|||||||
|
|
||||||
template<typename T, typename... Ts> requires requires(T t, Ts... ts) {
|
template<typename T, typename... Ts> requires requires(T t, Ts... ts) {
|
||||||
std::wcout << t;
|
std::wcout << t;
|
||||||
std::wcout << (ts, ...);
|
(std::wcout << ... << std::forward<Ts>(ts));
|
||||||
}
|
}
|
||||||
PublicLogger& print(T&& msg, Ts&&... other) noexcept {
|
PublicLogger& print(T&& msg, Ts&&... other) noexcept {
|
||||||
std::wstringstream stream = {};
|
std::wstringstream stream = {};
|
||||||
@@ -194,5 +194,5 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
[[carlbeks::releasedat("main.cpp")]] inline PublicLogger& Logger = *new PublicLogger(L"Main");
|
[[carlbeks::releasedat("def.cpp")]] inline PublicLogger& Logger = *new PublicLogger(L"Main");
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -76,7 +76,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 只能在gameThread调用 */
|
/** 只能在gameThread调用 */
|
||||||
template <TypeName T>
|
template<TypeName T>
|
||||||
void submit(T* ptr) noexcept(false) {
|
void submit(T* ptr) noexcept(false) {
|
||||||
IGarbage* newedGarbage = allocatedFor(new Garbage<T>(ptr));
|
IGarbage* newedGarbage = allocatedFor(new Garbage<T>(ptr));
|
||||||
builtinSubmit(newedGarbage);
|
builtinSubmit(newedGarbage);
|
||||||
@@ -147,4 +147,4 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline GarbageCollector& [[carlbeks::releasedat("main.cpp")]] gc = *new GarbageCollector();
|
inline GarbageCollector& [[carlbeks::releasedat("def.cpp")]] gc = *new GarbageCollector();
|
||||||
|
|||||||
+42
-65
@@ -5,11 +5,27 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "..\warnings.h"
|
#include "..\warnings.h"
|
||||||
|
#include "..\def.h"
|
||||||
|
|
||||||
class Vector3D;
|
template <typename T>
|
||||||
class Vector2D;
|
const T& nRange(const T& val, const T& min, const T& max) { return val < min ? min : val > max ? max : val; }
|
||||||
|
|
||||||
class Vector3D {
|
template <typename T>
|
||||||
|
const T& nMin(const T& a, const T& b) { return a < b ? a : b; }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const T& nMin(const T& val0, const T& val1, const T& vals...) { return nMin(nMin(val0, val1), nMin(vals...)); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const T& nMax(const T& a, const T& b) { return a > b ? a : b; }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const T& nMax(const T& val0, const T& val1, const T& vals...) { return nMax(nMin(val0, val1), nMax(vals...)); }
|
||||||
|
|
||||||
|
class [[carlbeks::TriviallyCopyable]] Vector3D;
|
||||||
|
class [[carlbeks::TriviallyCopyable]] Vector2D;
|
||||||
|
|
||||||
|
class [[carlbeks::TriviallyCopyable]] Vector3D {
|
||||||
double x, y, z;
|
double x, y, z;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -30,39 +46,13 @@ public:
|
|||||||
[[nodiscard]] Vector3D operator*(const double scalar) const noexcept { return Vector3D(x * scalar, y * scalar, z * scalar); }
|
[[nodiscard]] Vector3D operator*(const double scalar) const noexcept { return Vector3D(x * scalar, y * scalar, z * scalar); }
|
||||||
[[nodiscard]] Vector3D operator/(const double scalar) const noexcept { return Vector3D(x / scalar, y / scalar, z / scalar); }
|
[[nodiscard]] Vector3D operator/(const double scalar) const noexcept { return Vector3D(x / scalar, y / scalar, z / scalar); }
|
||||||
[[nodiscard]] double operator*(const Vector3D& other) const noexcept { return x * other.x + y * other.y + z * other.z; }
|
[[nodiscard]] double operator*(const Vector3D& other) const noexcept { return x * other.x + y * other.y + z * other.z; }
|
||||||
|
Vector3D& operator+=(const Vector3D& other) noexcept { return x += other.x, y += other.y, z += other.z, *this; }
|
||||||
Vector3D& operator+=(const Vector3D& other) noexcept {
|
Vector3D& operator-=(const Vector3D& other) noexcept { return x -= other.x, y -= other.y, z -= other.z, *this; }
|
||||||
x += other.x;
|
Vector3D& operator*=(const double scalar) noexcept { return x *= scalar, y *= scalar, z *= scalar, *this; }
|
||||||
y += other.y;
|
Vector3D& operator/=(const double scalar) noexcept { return x /= scalar, y /= scalar, z /= scalar, *this; }
|
||||||
z += other.z;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3D& operator-=(const Vector3D& other) noexcept {
|
|
||||||
x -= other.x;
|
|
||||||
y -= other.y;
|
|
||||||
z -= other.z;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3D& operator*=(const double scalar) noexcept {
|
|
||||||
x *= scalar;
|
|
||||||
y *= scalar;
|
|
||||||
z *= scalar;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3D& operator/=(const double scalar) noexcept {
|
|
||||||
x /= scalar;
|
|
||||||
y /= scalar;
|
|
||||||
z /= scalar;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Vector3D operator-() const noexcept { return Vector3D(-x, -y, -z); }
|
[[nodiscard]] Vector3D operator-() const noexcept { return Vector3D(-x, -y, -z); }
|
||||||
bool operator==(const Vector3D& other) const noexcept { return x == other.x && y == other.y && z == other.z; }
|
bool operator==(const Vector3D& other) const noexcept { return x == other.x && y == other.y && z == other.z; }
|
||||||
bool operator!=(const Vector3D& other) const noexcept { return x != other.x || y != other.y || z != other.z; }
|
bool operator!=(const Vector3D& other) const noexcept { return x != other.x || y != other.y || z != other.z; }
|
||||||
|
|
||||||
[[nodiscard]] double length() const noexcept { return std::sqrt(x * x + y * y + z * z); }
|
[[nodiscard]] double length() const noexcept { return std::sqrt(x * x + y * y + z * z); }
|
||||||
|
|
||||||
[[nodiscard]] Vector3D getNormalized() const noexcept {
|
[[nodiscard]] Vector3D getNormalized() const noexcept {
|
||||||
@@ -74,17 +64,21 @@ public:
|
|||||||
Vector3D& normalize() noexcept {
|
Vector3D& normalize() noexcept {
|
||||||
if (x == 0 && y == 0 && z == 0) return *this;
|
if (x == 0 && y == 0 && z == 0) return *this;
|
||||||
const double length = this->length();
|
const double length = this->length();
|
||||||
x /= length;
|
x /= length, y /= length, z /= length;
|
||||||
y /= length;
|
|
||||||
z /= length;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3D& add(const Vector3D& other) noexcept { return x += other.x, y += other.y, z += other.z, *this; }
|
||||||
|
Vector3D& add(const double x, const double y, const double z) noexcept { return this->x += x, this->y += y, this->z += z, *this; }
|
||||||
|
Vector3D& subtract(const Vector3D& other) noexcept { return x -= other.x, y -= other.y, z -= other.z, *this; }
|
||||||
|
Vector3D& subtract(const double x, const double y, const double z) noexcept { return this->x -= x, this->y -= y, this->z -= z, *this; }
|
||||||
|
Vector3D& multiply(const double value) noexcept { return this->x *= value, this->y *= value, this->z *= value, *this; }
|
||||||
|
Vector3D& divide(const double value) noexcept { return this->x /= value, this->y /= value, this->z /= value, *this; }
|
||||||
[[nodiscard]] double dot(const Vector3D& other) const noexcept { return x * other.x + y * other.y + z * other.z; }
|
[[nodiscard]] double dot(const Vector3D& other) const noexcept { return x * other.x + y * other.y + z * other.z; }
|
||||||
[[nodiscard]] Vector3D cross(const Vector3D& other) const noexcept { return Vector3D(y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x); }
|
[[nodiscard]] Vector3D cross(const Vector3D& other) const noexcept { return Vector3D(y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Vector2D {
|
class [[carlbeks::TriviallyCopyable]] Vector2D {
|
||||||
double x, y;
|
double x, y;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -104,35 +98,13 @@ public:
|
|||||||
[[nodiscard]] Vector2D operator*(const double scalar) const noexcept { return Vector2D(x * scalar, y * scalar); }
|
[[nodiscard]] Vector2D operator*(const double scalar) const noexcept { return Vector2D(x * scalar, y * scalar); }
|
||||||
[[nodiscard]] Vector2D operator/(const double scalar) const noexcept { return Vector2D(x / scalar, y / scalar); }
|
[[nodiscard]] Vector2D operator/(const double scalar) const noexcept { return Vector2D(x / scalar, y / scalar); }
|
||||||
[[nodiscard]] double operator*(const Vector2D& other) const noexcept { return x * other.x + y * other.y; }
|
[[nodiscard]] double operator*(const Vector2D& other) const noexcept { return x * other.x + y * other.y; }
|
||||||
|
Vector2D& operator+=(const Vector2D& other) noexcept { return x += other.x, y += other.y, *this; }
|
||||||
Vector2D& operator+=(const Vector2D& other) noexcept {
|
Vector2D& operator-=(const Vector2D& other) noexcept { return x -= other.x, y -= other.y, *this; }
|
||||||
x += other.x;
|
Vector2D& operator*=(const double scalar) noexcept { return x *= scalar, y *= scalar, *this; }
|
||||||
y += other.y;
|
Vector2D& operator/=(const double scalar) noexcept { return x /= scalar, y /= scalar, *this; }
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2D& operator-=(const Vector2D& other) noexcept {
|
|
||||||
x -= other.x;
|
|
||||||
y -= other.y;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2D& operator*=(const double scalar) noexcept {
|
|
||||||
x *= scalar;
|
|
||||||
y *= scalar;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2D& operator/=(const double scalar) noexcept {
|
|
||||||
x /= scalar;
|
|
||||||
y /= scalar;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Vector2D operator-() const noexcept { return Vector2D(-x, -y); }
|
[[nodiscard]] Vector2D operator-() const noexcept { return Vector2D(-x, -y); }
|
||||||
bool operator==(const Vector2D& other) const noexcept { return x == other.x && y == other.y; }
|
bool operator==(const Vector2D& other) const noexcept { return x == other.x && y == other.y; }
|
||||||
bool operator!=(const Vector2D& other) const noexcept { return x != other.x || y != other.y; }
|
bool operator!=(const Vector2D& other) const noexcept { return x != other.x || y != other.y; }
|
||||||
|
|
||||||
[[nodiscard]] double length() const noexcept { return std::sqrt(x * x + y * y); }
|
[[nodiscard]] double length() const noexcept { return std::sqrt(x * x + y * y); }
|
||||||
|
|
||||||
[[nodiscard]] Vector2D getNormalized() const noexcept {
|
[[nodiscard]] Vector2D getNormalized() const noexcept {
|
||||||
@@ -144,11 +116,16 @@ public:
|
|||||||
Vector2D& normalize() noexcept {
|
Vector2D& normalize() noexcept {
|
||||||
if (x == 0 && y == 0) return *this;
|
if (x == 0 && y == 0) return *this;
|
||||||
const double length = this->length();
|
const double length = this->length();
|
||||||
x /= length;
|
x /= length, y /= length;
|
||||||
y /= length;
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2D& add(const Vector2D& other) noexcept { return x += other.x, y += other.y, *this; }
|
||||||
|
Vector2D& add(const double x, const double y) noexcept { return this->x += x, this->y += y, *this; }
|
||||||
|
Vector2D& subtract(const Vector2D& other) noexcept { return x -= other.x, y -= other.y, *this; }
|
||||||
|
Vector2D& subtract(const double x, const double y) noexcept { return this->x -= x, this->y -= y, *this; }
|
||||||
|
Vector2D& multiply(const double value) noexcept { return this->x *= value, this->y *= value, *this; }
|
||||||
|
Vector2D& divide(const double value) noexcept { return this->x /= value, this->y /= value, *this; }
|
||||||
[[nodiscard]] double dot(const Vector2D& other) const noexcept { return x * other.x + y * other.y; }
|
[[nodiscard]] double dot(const Vector2D& other) const noexcept { return x * other.x + y * other.y; }
|
||||||
[[nodiscard]] Vector3D cross(const Vector2D& other) const noexcept { return Vector3D(0, 0, x * other.y - y * other.x); }
|
[[nodiscard]] Vector3D cross(const Vector2D& other) const noexcept { return Vector3D(0, 0, x * other.y - y * other.x); }
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user