mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
feat(item): add item manager with JSON asset loading
Implement ItemManager to load and query item definitions from assets/item JSON files. Add ItemData struct, item asset metadata, CMake source registration, and initialize the manager during app startup. Also add AGENTS.md repository guidelines.
This commit is contained in:
251
AGENTS.md
Normal file
251
AGENTS.md
Normal file
@@ -0,0 +1,251 @@
|
||||
# Code Modification Guidelines
|
||||
|
||||
## 1. Git Branch Protection
|
||||
|
||||
- Never modify code directly on the `main` branch.
|
||||
- Before editing, check the current branch:
|
||||
|
||||
```bash
|
||||
git branch --show-current
|
||||
````
|
||||
|
||||
* If the result is `main`, create or switch to a development branch first:
|
||||
|
||||
```bash
|
||||
git checkout -b feature/xxx
|
||||
```
|
||||
|
||||
* Do not bypass branch protection by:
|
||||
|
||||
* Committing directly to `main`.
|
||||
* Running code generation, formatting, or large refactors on `main`.
|
||||
* Rewriting or damaging `main` history.
|
||||
|
||||
---
|
||||
|
||||
## 2. Code Comments
|
||||
|
||||
* All new comments must be written in English.
|
||||
* Comments must be:
|
||||
|
||||
* Short and clear.
|
||||
* Explain the purpose, not repeat the code.
|
||||
* Avoid unnecessary details.
|
||||
|
||||
Recommended:
|
||||
|
||||
```cpp
|
||||
// AI-generated: Prevent stale handle access.
|
||||
```
|
||||
|
||||
Avoid:
|
||||
|
||||
```cpp
|
||||
// AI-generated: This checks if the handle is invalid because...
|
||||
```
|
||||
|
||||
* Important AI-added or modified logic should include:
|
||||
|
||||
```cpp
|
||||
// AI-generated
|
||||
```
|
||||
|
||||
* Do not add comments for trivial changes such as:
|
||||
|
||||
* One or two line logic fixes.
|
||||
* Spelling corrections.
|
||||
* Simple variable renames.
|
||||
|
||||
### 2.1 Do not write excessive or granular comments
|
||||
|
||||
AI must avoid sprinkling small explanatory comments throughout code.
|
||||
Specifically:
|
||||
|
||||
* **No line-by-line narration.** Do not add a comment above (or beside)
|
||||
every field, signal, slot, branch, or block just to restate what it is.
|
||||
If the name is self-explanatory, no comment is needed.
|
||||
* **No multi-part explanations on a single marker.** A line like
|
||||
`// AI-generated: abort the in-flight download; finished handler clears state.`
|
||||
is too much. Either drop it, or shorten to a single short clause
|
||||
(e.g. `// AI-generated: abort in-flight download.`).
|
||||
* **Prefer zero or one comment per file/section**, not many. A short
|
||||
header comment explaining the file's purpose is acceptable; dozens of
|
||||
inline labels are not.
|
||||
* **Do not comment obvious QML/C++ bindings, layout splits, or default
|
||||
values** (e.g. `// AI-generated: index 0 -> zh_CN, index 1 -> en.`).
|
||||
The code already says that.
|
||||
* **When in doubt, omit the comment.** A missing comment is fine; a
|
||||
redundant one is noise that future maintainers must clean up.
|
||||
|
||||
Rule of thumb: if removing the comment would not lose useful
|
||||
information, remove it.
|
||||
|
||||
---
|
||||
|
||||
## 3. Project Style
|
||||
|
||||
Follow the existing project style strictly:
|
||||
|
||||
* Naming conventions.
|
||||
* File organization.
|
||||
* Formatting rules.
|
||||
* Include order.
|
||||
* Existing architecture.
|
||||
|
||||
Do not:
|
||||
|
||||
* Introduce unrelated coding styles.
|
||||
* Add unnecessary design patterns.
|
||||
* Create duplicate systems.
|
||||
* Add abstractions without need.
|
||||
* Change module responsibilities.
|
||||
|
||||
---
|
||||
|
||||
## 4. Modification Scope
|
||||
|
||||
Only modify the minimum code required.
|
||||
|
||||
Do not:
|
||||
|
||||
* Format unrelated files.
|
||||
* Remove existing comments.
|
||||
* Rename large numbers of symbols.
|
||||
* Change public APIs.
|
||||
* Perform large refactors without confirmation.
|
||||
|
||||
If large changes are required, explain first:
|
||||
|
||||
1. Current problem.
|
||||
2. Required changes.
|
||||
3. Affected modules.
|
||||
4. Expected impact.
|
||||
|
||||
---
|
||||
|
||||
## 5. Build and Test
|
||||
|
||||
After modifications:
|
||||
|
||||
* Verify compilation.
|
||||
* Check for new warnings.
|
||||
* Ensure existing features still work.
|
||||
|
||||
Do not:
|
||||
|
||||
* Commit without verification.
|
||||
* Ignore compiler errors.
|
||||
* Hide problems with temporary hacks.
|
||||
|
||||
---
|
||||
|
||||
## 6. Compatibility
|
||||
|
||||
Consider:
|
||||
|
||||
* Existing callers.
|
||||
* API/ABI compatibility.
|
||||
* Serialization formats.
|
||||
* Network protocols.
|
||||
* Save data.
|
||||
* Threading impact.
|
||||
|
||||
Do not:
|
||||
|
||||
* Change network structures without compatibility handling.
|
||||
* Break old data formats.
|
||||
* Change public data layouts carelessly.
|
||||
|
||||
---
|
||||
|
||||
## 7. Multi-threading Safety
|
||||
|
||||
For multi-threaded code, check:
|
||||
|
||||
* Data races.
|
||||
* Object lifetime.
|
||||
* Lock contention.
|
||||
* Atomic correctness.
|
||||
* Cross-thread resource access.
|
||||
|
||||
Do not:
|
||||
|
||||
* Assume single-threaded execution.
|
||||
* Modify shared data without protection.
|
||||
* Add hidden locks that hurt performance.
|
||||
|
||||
---
|
||||
|
||||
## 8. Memory Safety
|
||||
|
||||
Consider:
|
||||
|
||||
* Ownership.
|
||||
* Lifetime.
|
||||
* RAII.
|
||||
* Memory leaks.
|
||||
* Dangling references.
|
||||
* Iterator invalidation.
|
||||
|
||||
Do not:
|
||||
|
||||
* Return references to local variables.
|
||||
* Store pointers to temporary objects.
|
||||
* Use uninitialized data.
|
||||
* Introduce undefined behavior.
|
||||
|
||||
---
|
||||
|
||||
## 9. Third-party Libraries
|
||||
|
||||
Before adding or changing dependencies:
|
||||
|
||||
Check:
|
||||
|
||||
* Existing project dependencies.
|
||||
* Build system impact.
|
||||
* Maintenance cost.
|
||||
|
||||
Do not:
|
||||
|
||||
* Add large libraries for simple features.
|
||||
* Duplicate existing library functionality.
|
||||
* Modify third-party source code.
|
||||
|
||||
---
|
||||
|
||||
## 10. AI Behavior Rules
|
||||
|
||||
AI-generated code must:
|
||||
|
||||
* Reuse existing code first.
|
||||
* Preserve current architecture.
|
||||
* Prefer simple solutions.
|
||||
* Minimize risk and code changes.
|
||||
|
||||
Do not:
|
||||
|
||||
* Guess requirements.
|
||||
* Add unrequested features.
|
||||
* Redesign architecture.
|
||||
* Add unnecessary abstraction layers.
|
||||
|
||||
Choose the implementation with:
|
||||
|
||||
> The smallest change, lowest risk, and best compatibility with existing code.
|
||||
|
||||
---
|
||||
|
||||
## 11. Pre-commit Checklist
|
||||
|
||||
Before committing:
|
||||
|
||||
* [ ] Not on `main`.
|
||||
* [ ] Changes match the requested task.
|
||||
* [ ] New comments are in English.
|
||||
* [ ] AI changes are marked when needed.
|
||||
* [ ] No unrelated formatting changes.
|
||||
* [ ] Build passes.
|
||||
* [ ] No obvious performance/security/thread issues.
|
||||
* [ ] No API, protocol, or data format breakage.
|
||||
|
||||
5
assets/item/air.json
Normal file
5
assets/item/air.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"id": 0,
|
||||
"name": "air",
|
||||
"description": ""
|
||||
}
|
||||
6
assets/item/dirt.json
Normal file
6
assets/item/dirt.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"id": 2,
|
||||
"name": "dirt",
|
||||
"description": "",
|
||||
"texture": "texture/item/block/dirt.png"
|
||||
}
|
||||
6
assets/item/grass.json
Normal file
6
assets/item/grass.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"id": 9,
|
||||
"name": "grass",
|
||||
"description": "",
|
||||
"texture": "texture/item/block/grass.png"
|
||||
}
|
||||
6
assets/item/grass_block.json
Normal file
6
assets/item/grass_block.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"id": 1,
|
||||
"name": "grass_block",
|
||||
"description": "",
|
||||
"texture": "texture/item/block/grass_block.png"
|
||||
}
|
||||
6
assets/item/leaf.json
Normal file
6
assets/item/leaf.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"id": 6,
|
||||
"name": "leaf",
|
||||
"description": "",
|
||||
"texture": "texture/item/block/leaf.png"
|
||||
}
|
||||
6
assets/item/log.json
Normal file
6
assets/item/log.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"id": 5,
|
||||
"name": "log",
|
||||
"description": "",
|
||||
"texture": "texture/item/block/log.png"
|
||||
}
|
||||
6
assets/item/sand.json
Normal file
6
assets/item/sand.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"id": 4,
|
||||
"name": "sand",
|
||||
"description": "",
|
||||
"texture": "texture/item/block/sand.png"
|
||||
}
|
||||
6
assets/item/snowy_grass_block.json
Normal file
6
assets/item/snowy_grass_block.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"id": 8,
|
||||
"name": "snowy_grass_block",
|
||||
"description": "",
|
||||
"texture": "texture/item/block/snowy_grass_block.png"
|
||||
}
|
||||
6
assets/item/stone.json
Normal file
6
assets/item/stone.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"id": 3,
|
||||
"name": "stone",
|
||||
"description": "",
|
||||
"texture": "texture/item/block/stone.png"
|
||||
}
|
||||
6
assets/item/water.json
Normal file
6
assets/item/water.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"id": 7,
|
||||
"name": "water",
|
||||
"description": "",
|
||||
"texture": "texture/item/block/water.png"
|
||||
}
|
||||
14
include/Cubed/gameplay/item.hpp
Normal file
14
include/Cubed/gameplay/item.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
namespace Cubed {
|
||||
using ItemID = uint16_t;
|
||||
|
||||
struct ItemData {
|
||||
ItemID id = 0;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string path;
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
36
include/Cubed/gameplay/item_manager.hpp
Normal file
36
include/Cubed/gameplay/item_manager.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cubed/gameplay/item.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <string_view>
|
||||
#include <tbb/concurrent_hash_map.h>
|
||||
namespace Cubed {
|
||||
class ItemManager {
|
||||
public:
|
||||
ItemManager();
|
||||
void init();
|
||||
static ItemManager& instance();
|
||||
|
||||
static const ItemData& get(std::string_view key);
|
||||
static const ItemData& get(ItemID id);
|
||||
|
||||
const ItemData& get_item_data(std::string_view key) const;
|
||||
const ItemData& get_item_data(ItemID id) const;
|
||||
|
||||
private:
|
||||
using ItemMap = tbb::concurrent_hash_map<ItemID, ItemData>;
|
||||
using acc = ItemMap::accessor;
|
||||
using cacc = ItemMap::const_accessor;
|
||||
|
||||
using IDMap = tbb::concurrent_hash_map<std::string_view, ItemID>;
|
||||
|
||||
void add(const std::filesystem::path& path);
|
||||
|
||||
ItemMap m_map;
|
||||
|
||||
IDMap m_id_map;
|
||||
|
||||
static constexpr ItemData EMPTY;
|
||||
};
|
||||
} // namespace Cubed
|
||||
@@ -104,4 +104,5 @@ target_sources(${PROJECT_NAME}
|
||||
gameplay/client_entity_manager.cpp
|
||||
gameplay/systems/wander_ai_system.cpp
|
||||
tools/json_utils.cpp
|
||||
gameplay/item_manager.cpp
|
||||
)
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Cubed/config.hpp"
|
||||
#include "Cubed/debug_collector.hpp"
|
||||
#include "Cubed/gameplay/item_manager.hpp"
|
||||
#include "Cubed/localization.hpp"
|
||||
#include "Cubed/tools/arg_parser.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
@@ -73,7 +74,7 @@ void App::init(int argc, char** argv) {
|
||||
Localization::instance().load_language(
|
||||
m_game_config.get("language", default_value));
|
||||
}
|
||||
|
||||
ItemManager::instance().init();
|
||||
m_window.init(m_argument);
|
||||
m_window.imgui_init();
|
||||
m_opengl_init = true;
|
||||
|
||||
106
src/gameplay/item_manager.cpp
Normal file
106
src/gameplay/item_manager.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#include "Cubed/gameplay/item_manager.hpp"
|
||||
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/istreamwrapper.h>
|
||||
namespace fs = std::filesystem;
|
||||
using namespace rapidjson;
|
||||
namespace Cubed {
|
||||
ItemManager::ItemManager() {}
|
||||
|
||||
ItemManager& ItemManager::instance() {
|
||||
static ItemManager inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
void ItemManager::init() {
|
||||
m_id_map.clear();
|
||||
m_map.clear();
|
||||
|
||||
fs::path dir = ASSETS_PATH "item";
|
||||
if (!fs::is_directory(dir)) {
|
||||
throw std::runtime_error("Item path not exist!");
|
||||
}
|
||||
for (const auto& entry : fs::recursive_directory_iterator(
|
||||
dir, fs::directory_options::skip_permission_denied)) {
|
||||
if (fs::is_regular_file(entry)) {
|
||||
if (entry.path().extension().string() == ".json") {
|
||||
add(entry.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ItemManager::add(const std::filesystem::path& path) {
|
||||
|
||||
std::ifstream s(path);
|
||||
if (!s.is_open()) {
|
||||
return;
|
||||
}
|
||||
IStreamWrapper isw(s);
|
||||
|
||||
Document doc;
|
||||
doc.ParseStream(isw);
|
||||
if (doc.HasParseError()) {
|
||||
Logger::error("Can't Parse File {}, error code {}", path.string(),
|
||||
static_cast<int>(doc.GetParseError()));
|
||||
return;
|
||||
}
|
||||
ItemData data;
|
||||
if (doc.HasMember("id")) {
|
||||
data.id = static_cast<ItemID>(doc["id"].GetInt());
|
||||
}
|
||||
if (doc.HasMember("name")) {
|
||||
data.name = doc["name"].GetString();
|
||||
}
|
||||
if (doc.HasMember("description")) {
|
||||
data.description = doc["description"].GetString();
|
||||
}
|
||||
if (doc.HasMember("texture")) {
|
||||
data.path = doc["texture"].GetString();
|
||||
}
|
||||
acc a;
|
||||
if (m_map.emplace(a, data.id, std::move(data))) {
|
||||
if (!m_id_map.emplace(a->second.name, a->first)) {
|
||||
Logger::error("ItemManager: Can't Insterd {} {} to id map",
|
||||
a->second.name, a->first);
|
||||
}
|
||||
} else {
|
||||
Logger::error("ItemManager: Can't Insterd {} to map", path.string());
|
||||
}
|
||||
}
|
||||
|
||||
const ItemData& ItemManager::get_item_data(std::string_view key) const {
|
||||
IDMap::const_accessor cacc;
|
||||
ItemID id = 0;
|
||||
if (m_id_map.find(cacc, key)) {
|
||||
id = cacc->second;
|
||||
} else {
|
||||
Logger::error("Can't Find key {} in id map", key);
|
||||
ASSERT(false);
|
||||
return EMPTY;
|
||||
}
|
||||
return get_item_data(id);
|
||||
}
|
||||
const ItemData& ItemManager::get_item_data(ItemID id) const {
|
||||
cacc c;
|
||||
if (!m_map.find(c, id)) {
|
||||
Logger::error("Can't find item {} in map", id);
|
||||
ASSERT(false);
|
||||
return EMPTY;
|
||||
}
|
||||
return c->second;
|
||||
}
|
||||
|
||||
const ItemData& ItemManager::get(std::string_view key) {
|
||||
return instance().get_item_data(key);
|
||||
}
|
||||
const ItemData& ItemManager::get(ItemID id) {
|
||||
return instance().get_item_data(id);
|
||||
}
|
||||
|
||||
} // namespace Cubed
|
||||
Reference in New Issue
Block a user