world初步

This commit is contained in:
EmsiaetKadosh
2025-03-23 13:23:10 +08:00
parent 037e532748
commit a335259edc
27 changed files with 982 additions and 313 deletions
+14 -31
View File
@@ -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})
+1
View File
@@ -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
View File
@@ -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";
}
}
+60 -34
View File
@@ -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; }
@@ -65,61 +69,75 @@ template<typename F> using Function = std::function<F>;
#pragma comment(lib, "Uxtheme.lib")
#pragma comment(lib, "winmm.lib")
template<typename T>
template <typename 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); };
template<typename T>
template <typename 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)); };
template<typename T>
template <typename T>
concept NonreferenceType = !std::is_reference_v<T>;
template<typename T>
template <typename T>
concept NonpointerType = !std::is_pointer_v<T>;
template<typename T>
template <typename T>
concept ReferenceType = std::is_reference_v<T>;
template<typename T>
template <typename T>
concept PointerType = std::is_pointer_v<T>;
template<typename 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;
std::size_t size;
};
Map<void*, MemoryInfo> allocated {};
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__
void printAllocate(void* value, std::size_t size, const String&);
void printDeallocate(void* value, std::size_t size, const String&);
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;
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]{};
@@ -147,10 +170,10 @@ public:
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) {}
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(const ObjectHolder& other) noexcept: value(other.value), hasValue(false) {}
@@ -160,10 +183,10 @@ public:
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);
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);
~ObjectHolder() {
@@ -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);
}
@@ -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 {
isOk = false;
if (newValue && newValue != value) deleteNew();
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 {
isOk = false;
if (newValue && newValue != value) deleteNew();
+38 -1
View File
@@ -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();
+7 -26
View File
@@ -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);
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();
+5
View File
@@ -0,0 +1,5 @@
//
// Created by EmsiaetKadosh on 25-3-22.
//
#include "Entity.h"
+52 -23
View File
@@ -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();
}
};
+2 -3
View File
@@ -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
View File
@@ -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)); }
};
+12
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
};
+2 -4
View File
@@ -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
View File
@@ -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"
+6 -2
View File
@@ -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
View File
@@ -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;
+88 -28
View File
@@ -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,22 +95,24 @@ class Renderer final : public ITickable {
public:
byte windowSize = 0; // 1, Windows: SIZE_***
byte reserved[5]{};
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);
if (canvasBitmap) SelectObject(canvasDC, canvasBitmap);
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);
if (canvasBitmap) SelectObject(canvasDC, canvasBitmap);
}
if (!assistBitmap) {
assistBitmap = CreateCompatibleBitmap(canvasDC, windowWidth, windowHeight);
if (assistBitmap) SelectObject(assistDC, assistBitmap);
}
if (canvasBitmap && assistBitmap) {
task.pop();
Logger.info(L"Successfully reload bitmap " + ptrtow(reinterpret_cast<QWORD>(canvasBitmap)) + L" " + ptrtow(reinterpret_cast<QWORD>(assistBitmap)));
this->resizeEnd();
}
}
if (!assistBitmap) {
assistBitmap = CreateCompatibleBitmap(canvasDC, windowWidth, windowHeight);
if (assistBitmap) SelectObject(assistDC, assistBitmap);
}
if (canvasBitmap && assistBitmap) {
task.pop();
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
View File
@@ -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
View File
@@ -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 {}
};
+9 -9
View File
@@ -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(); }
@@ -58,13 +58,13 @@ CaptionWindow::CaptionWindow() {
close->foregroundColor.inactive = 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& self, MouseButtonCode) {
if ((self.unused[1] = static_cast<char>(IsZoomed(MainWindowHandle)))) ShowWindow(MainWindowHandle, SW_RESTORE);
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->unused[1] = static_cast<char>(IsZoomed(MainWindowHandle));
maxRestore->backgroundColor.hover = 0xffcccccc;
@@ -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
View File
@@ -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
View File
@@ -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);
}
};
+15 -8
View File
@@ -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;
@@ -374,14 +377,17 @@ private:
const FontID id;
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:
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;
@@ -543,7 +551,7 @@ void languageMakeChinese(Language&);
class Translator {
Map<String, Language> langMap{};
List<Language*> langList{};
TranslatedText nullText{ L"\\#FF""EE0000<translator-null>" };
TranslatedText nullText{L"\\#FF""EE0000<translator-null>"};
String lang = L"zh-cn";
LangID idLangMax = 0;
int langConfig = 1;
@@ -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;
+2 -2
View File
@@ -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");
+2 -2
View File
@@ -76,7 +76,7 @@ public:
}
/** 只能在gameThread调用 */
template <TypeName T>
template<TypeName T>
void submit(T* ptr) noexcept(false) {
IGarbage* newedGarbage = allocatedFor(new Garbage<T>(ptr));
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
View File
@@ -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); }
};