world初步
This commit is contained in:
+14
-31
@@ -21,39 +21,22 @@ enable_testing()
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
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/utils/Chars.h
|
||||
src/ui/xWindows.h
|
||||
src/utils/TestCode.h
|
||||
src/game/entity/Entity.h
|
||||
src/game/entity/Player.h
|
||||
src/def.cpp
|
||||
src/utils/File.cpp
|
||||
src/utils/exception.cpp
|
||||
|
||||
src/interact/InteractManager.cpp
|
||||
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/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_VERSION ${PROJECT_VERSION})
|
||||
|
||||
@@ -2,3 +2,4 @@ Module:
|
||||
File(30%), including Log, Save, Config, Language
|
||||
Translator(30%), with File
|
||||
KeyBinding(20%)
|
||||
World, Entity(10%), including gc problem
|
||||
|
||||
+22
-9
@@ -4,8 +4,10 @@
|
||||
|
||||
#include "def.h"
|
||||
|
||||
#include "utils\Chars.h"
|
||||
#include "utils\File.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>
|
||||
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 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;
|
||||
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;
|
||||
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); }
|
||||
|
||||
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
|
||||
|
||||
#define __CARLBEKS_DEBUG__
|
||||
#define __CARLBEKS_MEMORY__ 1
|
||||
#define __CARLBEKS_MEMORY__ 3
|
||||
|
||||
#pragma warning(disable: 4819)
|
||||
|
||||
@@ -29,10 +29,14 @@ using wchar = wchar_t;
|
||||
using QWORD = unsigned long long int;
|
||||
using String = std::wstring;
|
||||
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 T, typename Comparator, typename Allocator = std::allocator<T>> 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>;
|
||||
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 T, typename Comparator = std::less<T>, typename Allocator = std::allocator<T>>
|
||||
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 Failed() { return 1; }
|
||||
@@ -84,6 +88,14 @@ concept PointerType = std::is_pointer_v<T>;
|
||||
template <typename T>
|
||||
concept TypeName = NonreferenceType<T> && NonpointerType<T>;
|
||||
|
||||
namespace $LimitedUse {
|
||||
struct Release {
|
||||
Release() = default;
|
||||
|
||||
~Release();
|
||||
} inline gcRelease_LoggerRelease_memoryManagerRelease;
|
||||
} // namespace $LimitedUse
|
||||
|
||||
struct MemoryManager {
|
||||
struct MemoryInfo {
|
||||
const String msg;
|
||||
@@ -93,33 +105,39 @@ struct MemoryManager {
|
||||
Map<void*, MemoryInfo> allocated{};
|
||||
|
||||
constexpr MemoryManager() noexcept = default;
|
||||
} inline memoryManager;
|
||||
} inline& [[carlbeks::releasedat("def.cpp")]] memoryManager = *new MemoryManager;
|
||||
|
||||
void requireNonnull(const void* value) noexcept(false);
|
||||
void checkAllocation(const void* value) noexcept(false);
|
||||
inline String ptrtow(QWORD value);
|
||||
|
||||
#if defined __CARLBEKS_DEBUG__ || defined __CARLBEKS_MEMORY__
|
||||
namespace $LimitedUse {
|
||||
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);
|
||||
|
||||
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);
|
||||
const auto& k = memoryManager.allocated.emplace(value, MemoryManager::MemoryInfo{L"[" + atow(typeid(T).name()) + L"] " + msg, size}).first;
|
||||
#if __CARLBEKS_MEMORY__ > 1
|
||||
printAllocate(value, k->second.size, k->second.msg);
|
||||
$LimitedUse::printAllocate(value, k->second.size, k->second.msg);
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename T> T* deallocating$(T* value) {
|
||||
template <typename T>
|
||||
T* deallocating$(T* value, const String& stack) {
|
||||
#if __CARLBEKS_MEMORY__ > 1
|
||||
const MemoryManager::MemoryInfo* info = nullptr;
|
||||
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
|
||||
if (value) memoryManager.allocated.erase(value);
|
||||
if (value) { if (!memoryManager.allocated.erase(value)) $LimitedUse::printDeallocateWarning(value, L"value not recorded" + stack); }
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -128,13 +146,18 @@ template<typename T> T* deallocating$(T* value) {
|
||||
#else
|
||||
#define allocatedFor(val, ...) allocatedFor$(val, L"" __VA_OPT__(,) __VA_ARGS__)
|
||||
#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)
|
||||
#endif
|
||||
#else
|
||||
#define allocatedFor(val, ...) val
|
||||
#define deallocating(val) val
|
||||
#endif
|
||||
|
||||
template<TypeName Base> class ObjectHolder {
|
||||
template <TypeName Base>
|
||||
class ObjectHolder {
|
||||
Base* value;
|
||||
bool hasValue;
|
||||
char padding[7]{};
|
||||
@@ -207,14 +230,16 @@ public:
|
||||
bool operator!() const noexcept { return value == nullptr; }
|
||||
[[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{};
|
||||
ret.value = &other;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template<TypeName Base> class SynchronizedHolder {
|
||||
template <TypeName Base>
|
||||
class SynchronizedHolder {
|
||||
mutable Base* newValue = nullptr;
|
||||
mutable Base* value = nullptr;
|
||||
mutable bool isOk = false;
|
||||
@@ -223,7 +248,8 @@ public:
|
||||
SynchronizedHolder() = default;
|
||||
|
||||
~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 (value) delete deallocating(value);
|
||||
}
|
||||
|
||||
+38
-1
@@ -4,12 +4,15 @@
|
||||
|
||||
#include "Game.h"
|
||||
|
||||
#include "entity\Entity.h"
|
||||
#include "world\World.h"
|
||||
#include "..\ui\xWindows.h"
|
||||
|
||||
void Game::initialize() {
|
||||
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()) } {
|
||||
@@ -20,8 +23,42 @@ Game::Game() : caption{ allocatedFor(new CaptionWindow()) }, floatWindow{ alloca
|
||||
Game::~Game() {
|
||||
setWindow(nullptr);
|
||||
delete deallocating(floatWindow);
|
||||
gc.pack();
|
||||
gc.collect();
|
||||
delete deallocating(caption);
|
||||
gc.pack();
|
||||
gc.collect();
|
||||
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();
|
||||
|
||||
+6
-25
@@ -10,6 +10,7 @@
|
||||
#include "../ui/Window.h"
|
||||
|
||||
class [[carlbeks::predecl, carlbeks::defineat("World.h")]] WorldManager;
|
||||
class [[carlbeks::predecl, carlbeks::defineat("Entity.h")]] EntityManager;
|
||||
|
||||
class Game final /* : public IRenderable, public ITickable */ {
|
||||
friend void gameThread();
|
||||
@@ -23,24 +24,17 @@ public:
|
||||
TaskScheduler tasks; // 8
|
||||
std::minstd_rand random;
|
||||
WorldManager* worldManager = nullptr;
|
||||
EntityManager* entityManager = nullptr;
|
||||
|
||||
void initialize();
|
||||
Game();
|
||||
~Game();
|
||||
|
||||
[[nodiscard]] QWORD getTick() const noexcept { return currentTick; }
|
||||
int closeWindow(Window* const window) noexcept { return windows.pop(window); }
|
||||
|
||||
void render() const noexcept {
|
||||
if (renderer.checkResizing()) return;
|
||||
renderer.gameStartRender();
|
||||
caption->render();
|
||||
hud.render();
|
||||
windows.render();
|
||||
floatWindow->render();
|
||||
renderer.gameEndRender();
|
||||
gc.pack();
|
||||
}
|
||||
[[nodiscard]] FloatWindow& getFloatWindow() const noexcept { return *floatWindow; }
|
||||
[[nodiscard]] QWORD getTick() const noexcept { return currentTick; }
|
||||
void tick() noexcept;
|
||||
void render(double tickDelta) const noexcept;
|
||||
|
||||
/**
|
||||
* 所有窗口都提交给Game保管,在适当时刻自动删除。
|
||||
@@ -59,25 +53,12 @@ public:
|
||||
Success();
|
||||
}
|
||||
|
||||
[[nodiscard]] FloatWindow& getFloatWindow() const noexcept { return *floatWindow; }
|
||||
|
||||
[[nodiscard]] Window* getWindow() const noexcept {
|
||||
if (auto* const back = windows.back()) return dynamic_cast<Window*>(back);
|
||||
Logger.error(L"Game::getWindow returns 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() {
|
||||
caption->onResize();
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by EmsiaetKadosh on 25-3-22.
|
||||
//
|
||||
|
||||
#include "Entity.h"
|
||||
+52
-23
@@ -5,11 +5,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "..\..\utils\math.h"
|
||||
#include "..\..\render\Renderer.h"
|
||||
#include "..\world\Location.h"
|
||||
#include "Damage.h"
|
||||
|
||||
class Entity;
|
||||
class World;
|
||||
class [[carlbeks::predecl, carlbeks::defineat("World.h")]] World;
|
||||
class EntityManager;
|
||||
|
||||
using EntityID = QWORD;
|
||||
|
||||
interface IDamageable {
|
||||
protected:
|
||||
@@ -22,40 +26,65 @@ public:
|
||||
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 {
|
||||
protected:
|
||||
virtual ~IArtificialIntelligent() = default;
|
||||
virtual void aiProcess() {}
|
||||
};
|
||||
|
||||
class Entity {
|
||||
class Entity : public IRenderable, public ITickable {
|
||||
friend class World;
|
||||
Location location;
|
||||
QWORD id = 0;
|
||||
friend class EntityManager;
|
||||
EntityID idEntity = 0;
|
||||
World* world = nullptr;
|
||||
|
||||
protected:
|
||||
Entity(const Location& location) : location(location) {}
|
||||
Entity(Location&& location) : location(std::move(location)) {}
|
||||
virtual ~Entity() = default;
|
||||
Location location;
|
||||
Vector2D velocity;
|
||||
double maxSpeed = 1.0;
|
||||
|
||||
Entity(const Vector2D& location) : location(location) {}
|
||||
~Entity() override = default;
|
||||
|
||||
public:
|
||||
virtual void tick() {}
|
||||
virtual void onRemove() {}
|
||||
virtual void onRemove() = 0;
|
||||
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:
|
||||
Enemy(const Location& location) : Entity(location) {}
|
||||
Enemy(Location&& location) : Entity(std::move(location)) {}
|
||||
Enemy(const Vector2D& location) : Entity(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"
|
||||
|
||||
class Player : public Entity, public IMoveable, public IDamageable {
|
||||
class Player : public Entity, public IDamageable {
|
||||
public:
|
||||
Player(const Location& location) : Entity(location) {}
|
||||
Player(Location&& location) : Entity(std::move(location)) {}
|
||||
Player(const Vector2D& location) : Entity(location) {}
|
||||
};
|
||||
|
||||
+33
-2
@@ -4,9 +4,40 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "..\..\def.h"
|
||||
#include "..\..\utils\gc.h"
|
||||
#include "Location.h"
|
||||
|
||||
class Block {
|
||||
public:
|
||||
class [[carlbeks::predecl, carlbeks::defineat("World.h")]] World;
|
||||
|
||||
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;
|
||||
class Location;
|
||||
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;
|
||||
WorldID idWorld;
|
||||
|
||||
public:
|
||||
Location(const Vector2D& position, const WorldID idWorld) : position(position), idWorld(idWorld) {}
|
||||
Location(Vector2D&& position, const WorldID idWorld) : position(position), idWorld(idWorld) {}
|
||||
[[nodiscard]] Vector2D getPosition() const { return position; }
|
||||
[[nodiscard]] WorldID getWorld() const { return idWorld; }
|
||||
[[nodiscard]] double getX() const { return position.getX(); }
|
||||
[[nodiscard]] double getY() const { return position.getY(); }
|
||||
[[nodiscard]] BlockLocation getBlockLocation() const;
|
||||
Location(const Vector2D& position) noexcept : position(position), idWorld(0) {}
|
||||
Location(const Vector2D& position, const WorldID idWorld) noexcept : position(position), idWorld(idWorld) {}
|
||||
Location(const Location& other) noexcept = default;
|
||||
Location(Location&& other) noexcept = default;
|
||||
[[nodiscard]] Vector2D getPosition() const noexcept { return position; }
|
||||
[[nodiscard]] WorldID getWorld() const noexcept { return idWorld; }
|
||||
[[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;
|
||||
WorldID idWorld;
|
||||
|
||||
public:
|
||||
BlockLocation(const long long x, const long long y, const WorldID idWorld) : x(x), y(y), idWorld(idWorld) {}
|
||||
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) {}
|
||||
[[nodiscard]] Vector2D getPosition() const { return Vector2D(static_cast<double>(x), static_cast<double>(y)); }
|
||||
[[nodiscard]] WorldID getWorld() const { return idWorld; }
|
||||
[[nodiscard]] long long getX() const { return x; }
|
||||
[[nodiscard]] long long getY() const { return y; }
|
||||
[[nodiscard]] Location toLocation() const { return Location({ static_cast<double>(x), static_cast<double>(y) }, idWorld); }
|
||||
BlockLocation(const long long x, const long long y) noexcept : x(x), y(y), idWorld(0) {}
|
||||
BlockLocation(const Vector2D& position) noexcept : x(static_cast<long long>(position.getX())), y(static_cast<long long>(position.getY())), idWorld(0) {}
|
||||
BlockLocation(const long long x, const long long y, const WorldID idWorld) noexcept : x(x), y(y), idWorld(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) {}
|
||||
BlockLocation(const BlockLocation& other) noexcept = default;
|
||||
BlockLocation(BlockLocation&& other) noexcept = default;
|
||||
[[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 "..\entity\Entity.h"
|
||||
#include "Block.h"
|
||||
|
||||
class World {
|
||||
QWORD idEntity = 0;
|
||||
class World;
|
||||
class WorldManager;
|
||||
|
||||
class World : public IRenderable, public ITickable {
|
||||
friend class WorldManager;
|
||||
friend class Garbage<World>;
|
||||
WorldID idWorld;
|
||||
Map<QWORD, Entity*> entities;
|
||||
Map<BlockLocation, Block*, BlockLocation::Less> blocks;
|
||||
using IterEntity = Map<QWORD, Entity*>::const_iterator;
|
||||
using IterBlock = Map<BlockLocation, Block*, BlockLocation::Less>::const_iterator;
|
||||
|
||||
public:
|
||||
protected:
|
||||
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->id) Failed();
|
||||
entities.emplace(++idEntity, entity);
|
||||
if (!entity->idEntity) Failed();
|
||||
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();
|
||||
}
|
||||
|
||||
int removeEntity(Entity* entity) {
|
||||
virtual int removeEntity(Entity* entity, const WorldTransportReason reason) {
|
||||
if (!entity) Failed();
|
||||
if (!entity->id) Failed();
|
||||
const IterEntity iter = entities.find(entity->id);
|
||||
if (iter != entities.end()) Failed();
|
||||
entities.erase(iter);
|
||||
entity->onRemove();
|
||||
entity->id = 0;
|
||||
if (!entity->idEntity) Failed();
|
||||
if (!entities.erase(entity->idEntity)) Failed();
|
||||
if (!reason.isEntityReason()) Failed();
|
||||
entity->onExitWorld(this, reason);
|
||||
entity->location.setWorld(0);
|
||||
entity->world = nullptr;
|
||||
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 {
|
||||
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:
|
||||
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 {
|
||||
AllocConsole();
|
||||
FILE* pCout;
|
||||
freopen_s(&pCout, "CONOUT$", "w", stdout);
|
||||
FILE* pCin;
|
||||
freopen_s(&pCin, "CONOUT$", "r+", stdin);
|
||||
freopen("CONOUT$", "w", stdout);
|
||||
freopen("CONOUT$", "r+", stdin);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+7
-6
@@ -8,20 +8,21 @@
|
||||
|
||||
// Any include
|
||||
#include "def.h"
|
||||
#include "utils\math.h"
|
||||
#include "utils\math.h" // required by Location.h
|
||||
#include "utils\File.h"
|
||||
#include "utils\exception.h"
|
||||
#include "utils\Chars.h"
|
||||
|
||||
// utils serialized
|
||||
#include "utils\gc.h"
|
||||
#include "utils\utils.h"
|
||||
#include "hbp.h"
|
||||
#include "utils\Chars.h"
|
||||
#include "utils\gc.h" // required by utils.h
|
||||
#include "utils\utils.h" // required by Task.h
|
||||
#include "utils\Task.h"
|
||||
#include "hbp.h"
|
||||
|
||||
// game basic
|
||||
#include "interact\InteractManager.h"
|
||||
#include "utils\IText.h"
|
||||
#include "game\world\Location.h" // required by Renderer.h
|
||||
#include "render\Renderer.h"
|
||||
#include "game\Animation.h"
|
||||
#include "render\TextureManager.h"
|
||||
@@ -33,7 +34,7 @@
|
||||
|
||||
// game extension
|
||||
#include "ui\xWindows.h"
|
||||
#include "game\world\Location.h"
|
||||
#include "game\entity\Entity.h"
|
||||
#include "game\world\Block.h"
|
||||
#include "game\world\World.h"
|
||||
#include "game\entity\Player.h"
|
||||
|
||||
@@ -206,6 +206,7 @@ class InteractSettings {
|
||||
int marginWidth = 40;
|
||||
int fontHeight = 96;
|
||||
int floatWindowMargin = 16;
|
||||
double mapScale = 32.0; // 1格表现为32像素
|
||||
};
|
||||
|
||||
struct Constants {
|
||||
@@ -215,12 +216,15 @@ class InteractSettings {
|
||||
*/
|
||||
double uiScale = 1;
|
||||
double screenScale = 1;
|
||||
double smoothCamera = 0.5; // 相机平滑度。为0,始终瞬时设置相机的位置;为1,相机不动。
|
||||
long long msPerTick = 50;
|
||||
long long msPerRender = 16;
|
||||
unsigned int floatWindowBackground = 0xdd000000;
|
||||
};
|
||||
|
||||
public:
|
||||
Options options;
|
||||
Options actual;
|
||||
Options options; // 用户设置值
|
||||
Options actual; // 适应Scale后的实际值
|
||||
Constants constants;
|
||||
|
||||
InteractSettings& setUiScale(const double scale) noexcept {
|
||||
|
||||
+279
-16
@@ -1,6 +1,271 @@
|
||||
|
||||
#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) {
|
||||
switch (uMsg) {
|
||||
@@ -199,14 +464,16 @@ LRESULT __stdcall HookProc(const int code, const WPARAM wParam, const LPARAM lPa
|
||||
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() {
|
||||
try {
|
||||
using namespace std::chrono;
|
||||
using Time = time_point<system_clock>;
|
||||
Time lastTick = system_clock::now();
|
||||
while (isRunning) {
|
||||
const Time thisTime = system_clock::now();
|
||||
if (thisTime - lastTick < milliseconds(45)) {
|
||||
if (thisTime - lastTick < milliseconds(interactSettings.constants.msPerTick)) {
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
@@ -229,11 +496,11 @@ void renderThread() {
|
||||
Time lastRender = system_clock::now();
|
||||
while (isRunning) {
|
||||
const Time thisTime = system_clock::now();
|
||||
if (thisTime - lastRender < milliseconds(12)) {
|
||||
if (thisTime - lastRender < milliseconds(interactSettings.constants.msPerRender)) {
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
game.render();
|
||||
game.render(nRange(static_cast<double>((thisTime - lastTick).count()) / interactSettings.constants.msPerRender, 0.0, 1.0));
|
||||
lastRender = thisTime;
|
||||
}
|
||||
} 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) {
|
||||
Logger.info(L"wWinMain started");
|
||||
SetConsoleOutputCP(65001);
|
||||
SetUnhandledExceptionFilter(UnhandledExceptionFilter);
|
||||
translator.initialize();
|
||||
Logger.info(L"--------Program Start--------");
|
||||
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();
|
||||
interactManager.initialize();
|
||||
World* w = StartWorld::create();
|
||||
game.worldManager->addWorld(w);
|
||||
game.worldManager->setWorld(w);
|
||||
GameThread = Thread(gameThread);
|
||||
RenderThread = Thread(renderThread);
|
||||
}
|
||||
@@ -315,16 +586,8 @@ int __stdcall wWinMain(const HINSTANCE hInstance, const HINSTANCE, [[maybe_unuse
|
||||
Logger.info(L"------- Program End --------");
|
||||
for (const auto& [addr, info] : memoryManager.allocated) { Logger.print(L" using", addr, info.size, L"B", info.msg); }
|
||||
_wsystem(L"pause");
|
||||
{
|
||||
fontManager.finalize(); // 似乎GDI有终止自动回收,所以此代码需要提前
|
||||
}
|
||||
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
|
||||
|
||||
#include "..\def.h"
|
||||
#include "..\utils\math.h"
|
||||
#include "..\utils\exception.h"
|
||||
#include "..\utils\Task.h"
|
||||
#include "..\interact\InteractManager.h"
|
||||
#include "..\game\world\Location.h"
|
||||
|
||||
class Game;
|
||||
|
||||
@@ -17,7 +20,7 @@ enum class UILocation : char { LEFT_TOP, LEFT, LEFT_BOTTOM, TOP, CENTER, BOTTOM,
|
||||
|
||||
interface IRenderable {
|
||||
virtual ~IRenderable() = default;
|
||||
virtual void render() const noexcept = 0;
|
||||
virtual void render(double tickDelta) const noexcept = 0;
|
||||
};
|
||||
|
||||
interface ITickable {
|
||||
@@ -39,16 +42,36 @@ inline static constexpr Color TextColor = {
|
||||
.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 {
|
||||
friend class Game;
|
||||
friend class Font;
|
||||
mutable List<HGDIOBJ> failed;
|
||||
inline static BLENDFUNCTION blendFunction = {
|
||||
.BlendOp = AC_SRC_OVER, // Only
|
||||
.BlendFlags = 0, // Must 0
|
||||
.SourceConstantAlpha = 255, // 预乘
|
||||
.AlphaFormat = 0, // Not AC_SRC_ALPHA
|
||||
};
|
||||
mutable List<HGDIOBJ> failed;
|
||||
mutable Camera camera;
|
||||
HDC MainDC = nullptr; // 8
|
||||
HDC resizeCopyDC = nullptr; // 8
|
||||
HBITMAP resizeCopyBitmap = nullptr; // 8
|
||||
@@ -72,7 +95,8 @@ class Renderer final : public ITickable {
|
||||
public:
|
||||
byte windowSize = 0; // 1, Windows: SIZE_***
|
||||
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));
|
||||
if (!canvasBitmap) {
|
||||
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)));
|
||||
this->resizeEnd();
|
||||
}
|
||||
} };
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
void gameStartRender() noexcept;
|
||||
@@ -118,20 +143,16 @@ public:
|
||||
[[nodiscard]] int getSyncHeight() const noexcept { return syncHeight; }
|
||||
[[nodiscard]] bool checkResizing() const noexcept { return isResizing; }
|
||||
void tick() noexcept override {}
|
||||
|
||||
/**
|
||||
* @attention 会忽略A透明度值
|
||||
* @param argb ARGB式颜色
|
||||
* @return int BGR式颜色
|
||||
*/
|
||||
[[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 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 resizeShow() const noexcept { StretchBlt(MainDC, 0, 0, syncWidth, syncHeight, resizeCopyDC, 0, 0, resizeCopyWidth, resizeCopyHeight, SRCCOPY); }
|
||||
|
||||
void resizeEnd() noexcept {
|
||||
@@ -143,9 +164,13 @@ public:
|
||||
}
|
||||
|
||||
void deleteObject(HGDIOBJ obj) const noexcept {
|
||||
for (List<HGDIOBJ>::const_iterator iter = failed.cbegin(); iter != failed.cend(); ++iter)
|
||||
if (!DeleteObject(*iter)) Logger.error(L"DeleteObject failed again. Deleting: " + std::to_wstring(reinterpret_cast<QWORD>(*iter)));
|
||||
else failed.erase(iter);
|
||||
List<HGDIOBJ> tempList;
|
||||
tempList.swap(failed);
|
||||
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)) {
|
||||
failed.push_back(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));
|
||||
FillRect(canvasDC, &rect, clr);
|
||||
deleteObject(clr);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
const RECT rect{
|
||||
.left = 0,
|
||||
.top = 0,
|
||||
@@ -185,10 +211,12 @@ public:
|
||||
assertRendering();
|
||||
//assertRenderThread();
|
||||
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);
|
||||
deleteObject(clr);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
const RECT r{
|
||||
.left = 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");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
+1
-1
@@ -4,5 +4,5 @@
|
||||
|
||||
#include "Hud.h"
|
||||
|
||||
void Hud::render() const noexcept {}
|
||||
void Hud::render(double tickDelta) const noexcept {}
|
||||
void Hud::tick() noexcept {}
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
class Hud final : public IRenderable, public ITickable {
|
||||
public:
|
||||
void render() const noexcept override;
|
||||
void render(double tickDelta) const noexcept override;
|
||||
void tick() noexcept override;
|
||||
void onResize() noexcept {}
|
||||
};
|
||||
|
||||
+7
-7
@@ -13,7 +13,7 @@ int Window::pop() noexcept {
|
||||
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::onResize() { for (Widget* widget : widgets) widget->onResize(); }
|
||||
|
||||
@@ -111,9 +111,9 @@ CaptionWindow::CaptionWindow() {
|
||||
bool CaptionWindow::onOpen() { throw InvalidOperationException(L"Should not open 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);
|
||||
for (const Widget* widget : widgets) widget->render();
|
||||
for (const Widget* widget : widgets) widget->render(tickDelta);
|
||||
}
|
||||
|
||||
void CaptionWindow::onResize() {
|
||||
@@ -137,7 +137,7 @@ void CaptionWindow::onResize() {
|
||||
Window::onResize();
|
||||
}
|
||||
|
||||
void FloatWindow::render() const noexcept {
|
||||
void FloatWindow::render(double tickDelta) const noexcept {
|
||||
if (not interactManager.isInWindow()) {
|
||||
strings.async();
|
||||
return;
|
||||
@@ -180,7 +180,7 @@ unsigned int Widget::colorSelector(const Color& clr) const {
|
||||
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() {
|
||||
if (isAbsoluteLocation) {
|
||||
@@ -268,8 +268,8 @@ void Widget::onResize() {
|
||||
}
|
||||
}
|
||||
|
||||
void Button::render() const noexcept {
|
||||
Widget::render();
|
||||
void Button::render(const double tickDelta) const noexcept {
|
||||
Widget::render(tickDelta);
|
||||
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) {}
|
||||
|
||||
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 {
|
||||
location = loc;
|
||||
@@ -155,7 +155,7 @@ protected:
|
||||
|
||||
public:
|
||||
int pop() noexcept override;
|
||||
void render() const noexcept override;
|
||||
void render(double tickDelta) const noexcept override;
|
||||
void tick() noexcept override;
|
||||
/**
|
||||
* 在Game.setWindow()时,本窗口开启时调用。
|
||||
@@ -176,7 +176,7 @@ public:
|
||||
|
||||
class WindowManager final : public AnywhereEditableList<Window, WindowManager>, public IRenderable, public ITickable {
|
||||
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(); }
|
||||
int pop(Window* value) noexcept override;
|
||||
void clear() noexcept;
|
||||
@@ -188,7 +188,7 @@ public:
|
||||
CaptionWindow();
|
||||
bool onOpen() override;
|
||||
void onClose() override;
|
||||
void render() const noexcept override;
|
||||
void render(double tickDelta) const noexcept 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(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 {}
|
||||
bool onOpen() override { return true; }
|
||||
void onClose() override {}
|
||||
@@ -222,7 +222,7 @@ public:
|
||||
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, 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:
|
||||
~ConfirmWindow() override = default; // 不需要delete,析构时Window会自动delete
|
||||
|
||||
void render() const noexcept override {
|
||||
void render(const double tickDelta) const noexcept override {
|
||||
int w, h;
|
||||
w = renderer.getWidth(), h = renderer.getHeight();
|
||||
w >>= 2, h >>= 2;
|
||||
renderer.fill(w, h, w + w, h + h, 0xcc222222);
|
||||
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 = {});
|
||||
|
||||
+2
-2
@@ -34,8 +34,8 @@ public:
|
||||
static StartWindow* create() noexcept { return allocatedFor(new StartWindow()); }
|
||||
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());
|
||||
Window::render();
|
||||
Window::render(tickDelta);
|
||||
}
|
||||
};
|
||||
|
||||
+12
-5
@@ -146,19 +146,22 @@ public:
|
||||
if (config.idFont == idFont || config.idFont != 0) {
|
||||
font = false;
|
||||
++flags;
|
||||
} else config.idFont = idFont;
|
||||
}
|
||||
else config.idFont = idFont;
|
||||
}
|
||||
if (clr) {
|
||||
if (config.color == color || config.color != 0xffffffff) {
|
||||
clr = false;
|
||||
++flags;
|
||||
} else config.color = color;
|
||||
}
|
||||
else config.color = color;
|
||||
}
|
||||
if (bg) {
|
||||
if (config.background == background || config.background != 0xffffffff) {
|
||||
bg = false;
|
||||
++flags;
|
||||
} else config.background = background;
|
||||
}
|
||||
else config.background = background;
|
||||
}
|
||||
configs.push_back(std::move(config));
|
||||
++iterator;
|
||||
@@ -381,7 +384,10 @@ private:
|
||||
public:
|
||||
Font(const 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:
|
||||
HFONT tryCreate(const RenderableString::StringConfig& config) const {
|
||||
@@ -447,6 +453,8 @@ public:
|
||||
newFont(L"", 1.0, -0.05);
|
||||
}
|
||||
|
||||
void finalize() { for (auto& [id, font] : fonts) font.clear(); }
|
||||
|
||||
[[nodiscard]] const Font& get(const FontID id) const noexcept {
|
||||
const IterFonts iter = fonts.find(id);
|
||||
if (iter == fonts.cend()) return *defaultFont;
|
||||
@@ -583,7 +591,6 @@ public:
|
||||
void loadLang();
|
||||
|
||||
[[nodiscard]] const TranslatedText* getText(const String& id) const noexcept {
|
||||
Logger.debug(L"getText called");
|
||||
for (const Language* language : langList) {
|
||||
const Language::IterText iterator = language->translateTable.find(id);
|
||||
if (iterator != language->translateTable.cend()) return &iterator->second;
|
||||
|
||||
@@ -162,7 +162,7 @@ public:
|
||||
|
||||
template<typename T, typename... Ts> requires requires(T t, Ts... ts) {
|
||||
std::wcout << t;
|
||||
std::wcout << (ts, ...);
|
||||
(std::wcout << ... << std::forward<Ts>(ts));
|
||||
}
|
||||
PublicLogger& print(T&& msg, Ts&&... other) noexcept {
|
||||
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");
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
#include "..\warnings.h"
|
||||
#include "..\def.h"
|
||||
|
||||
class Vector3D;
|
||||
class Vector2D;
|
||||
template <typename T>
|
||||
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;
|
||||
|
||||
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]] double operator*(const Vector3D& other) const noexcept { return x * other.x + y * other.y + z * other.z; }
|
||||
|
||||
Vector3D& operator+=(const Vector3D& other) noexcept {
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
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;
|
||||
}
|
||||
|
||||
Vector3D& operator+=(const Vector3D& other) noexcept { return x += other.x, y += other.y, z += other.z, *this; }
|
||||
Vector3D& operator-=(const Vector3D& other) noexcept { return x -= other.x, y -= other.y, z -= other.z, *this; }
|
||||
Vector3D& operator*=(const double scalar) noexcept { return x *= scalar, y *= scalar, z *= scalar, *this; }
|
||||
Vector3D& operator/=(const double scalar) noexcept { return x /= scalar, y /= scalar, z /= scalar, *this; }
|
||||
[[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; }
|
||||
|
||||
[[nodiscard]] double length() const noexcept { return std::sqrt(x * x + y * y + z * z); }
|
||||
|
||||
[[nodiscard]] Vector3D getNormalized() const noexcept {
|
||||
@@ -74,17 +64,21 @@ public:
|
||||
Vector3D& normalize() noexcept {
|
||||
if (x == 0 && y == 0 && z == 0) return *this;
|
||||
const double length = this->length();
|
||||
x /= length;
|
||||
y /= length;
|
||||
z /= length;
|
||||
x /= length, y /= length, z /= length;
|
||||
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]] 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;
|
||||
|
||||
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]] double operator*(const Vector2D& other) const noexcept { return x * other.x + y * other.y; }
|
||||
|
||||
Vector2D& operator+=(const Vector2D& other) noexcept {
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
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;
|
||||
}
|
||||
|
||||
Vector2D& operator+=(const Vector2D& other) noexcept { return x += other.x, y += other.y, *this; }
|
||||
Vector2D& operator-=(const Vector2D& other) noexcept { return x -= other.x, y -= other.y, *this; }
|
||||
Vector2D& operator*=(const double scalar) noexcept { return x *= scalar, y *= scalar, *this; }
|
||||
Vector2D& operator/=(const double scalar) noexcept { return x /= scalar, y /= scalar, *this; }
|
||||
[[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; }
|
||||
|
||||
[[nodiscard]] double length() const noexcept { return std::sqrt(x * x + y * y); }
|
||||
|
||||
[[nodiscard]] Vector2D getNormalized() const noexcept {
|
||||
@@ -144,11 +116,16 @@ public:
|
||||
Vector2D& normalize() noexcept {
|
||||
if (x == 0 && y == 0) return *this;
|
||||
const double length = this->length();
|
||||
x /= length;
|
||||
y /= length;
|
||||
x /= length, y /= length;
|
||||
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]] Vector3D cross(const Vector2D& other) const noexcept { return Vector3D(0, 0, x * other.y - y * other.x); }
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user