mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
Compare commits
54 Commits
feature/js
...
b2187bf0ad
| Author | SHA1 | Date | |
|---|---|---|---|
| b2187bf0ad | |||
| 2aa9d07e43 | |||
| 8ff789c576 | |||
| 322fb2fea0 | |||
| 277aab1b81 | |||
| 30b4060fb5 | |||
| 0ffa2804d1 | |||
| abf1f4db7d | |||
| 1514338144 | |||
| 8af30e159d | |||
| 0259ca71ce | |||
| 2358cfd9a4 | |||
| 5e7c6ec891 | |||
| ef3be12b64 | |||
| 67fbbe1229 | |||
| d970988022 | |||
| e2bbc2d57f | |||
| 6b1f9d7354 | |||
| 5980400e2e | |||
| 9bb1882d92 | |||
| a54858e4c6 | |||
| 18e308bd03 | |||
| 2e4a32fed7 | |||
| c5ce91e653 | |||
| 412f88565a | |||
| 8451921161 | |||
| d6f304e6ca | |||
| 826c6600d0 | |||
| b166bab4f3 | |||
| efa49a98b7 | |||
| 3a9ab6a14a | |||
| d15037e7a3 | |||
| 0ff5820e6e | |||
| 5e96c1573b | |||
| 90273e87f2 | |||
| 1e106d75a3 | |||
| bd1a9557a5 | |||
| 831569cec6 | |||
| a5c1c7d4aa | |||
| 802d2ecb5a | |||
| ab605f7590 | |||
| 15d5af34b9 | |||
| 6d0e60e241 | |||
| 7b530968af | |||
| 930226cc47 | |||
| f9bf2f4b89 | |||
| df3ac5b5db | |||
| 2568eb7d18 | |||
| 2e3b4f4f0f | |||
| 5951a5e81c | |||
| 849386a3bc | |||
| 3e7ce71219 | |||
| 94fed9a810 | |||
| f4174724c6 |
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.
|
||||||
|
|
||||||
@@ -148,6 +148,7 @@ target_link_libraries(${PROJECT_NAME}
|
|||||||
OpenAL::OpenAL
|
OpenAL::OpenAL
|
||||||
harfbuzz::harfbuzz
|
harfbuzz::harfbuzz
|
||||||
Opus::Opus
|
Opus::Opus
|
||||||
|
assimp::assimp
|
||||||
$<$<PLATFORM_ID:Windows>:ws2_32>
|
$<$<PLATFORM_ID:Windows>:ws2_32>
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,5 +8,4 @@ is_passable = true
|
|||||||
is_transitional = false
|
is_transitional = false
|
||||||
is_transparent = true
|
is_transparent = true
|
||||||
name = 'air'
|
name = 'air'
|
||||||
name_key = 'block.air'
|
|
||||||
roughness = 1.0
|
roughness = 1.0
|
||||||
@@ -8,5 +8,4 @@ is_passable = false
|
|||||||
is_transitional = true
|
is_transitional = true
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'dirt'
|
name = 'dirt'
|
||||||
name_key = 'block.dirt'
|
|
||||||
roughness = 1.0
|
roughness = 1.0
|
||||||
@@ -8,5 +8,4 @@ is_passable = true
|
|||||||
is_transitional = false
|
is_transitional = false
|
||||||
is_transparent = true
|
is_transparent = true
|
||||||
name = 'grass'
|
name = 'grass'
|
||||||
name_key = 'block.grass'
|
|
||||||
roughness = 0.90000000000000002
|
roughness = 0.90000000000000002
|
||||||
@@ -8,5 +8,4 @@ is_passable = false
|
|||||||
is_transitional = true
|
is_transitional = true
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'grass_block'
|
name = 'grass_block'
|
||||||
name_key = 'block.grass_block'
|
|
||||||
roughness = 0.90000000000000002
|
roughness = 0.90000000000000002
|
||||||
@@ -8,5 +8,4 @@ is_passable = false
|
|||||||
is_transitional = false
|
is_transitional = false
|
||||||
is_transparent = true
|
is_transparent = true
|
||||||
name = 'leaf'
|
name = 'leaf'
|
||||||
name_key = 'block.leaf'
|
|
||||||
roughness = 0.69999999999999996
|
roughness = 0.69999999999999996
|
||||||
@@ -8,5 +8,4 @@ is_passable = false
|
|||||||
is_transitional = false
|
is_transitional = false
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'log'
|
name = 'log'
|
||||||
name_key = 'block.log'
|
|
||||||
roughness = 0.69999999999999996
|
roughness = 0.69999999999999996
|
||||||
@@ -8,5 +8,4 @@ is_passable = false
|
|||||||
is_transitional = true
|
is_transitional = true
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'sand'
|
name = 'sand'
|
||||||
name_key = 'block.sand'
|
|
||||||
roughness = 0.80000000000000004
|
roughness = 0.80000000000000004
|
||||||
@@ -8,5 +8,4 @@ is_passable = false
|
|||||||
is_transitional = true
|
is_transitional = true
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'snowy_grass_block'
|
name = 'snowy_grass_block'
|
||||||
name_key = 'block.snowy_grass_block'
|
|
||||||
roughness = 0.90000000000000002
|
roughness = 0.90000000000000002
|
||||||
@@ -8,5 +8,4 @@ is_passable = false
|
|||||||
is_transitional = true
|
is_transitional = true
|
||||||
is_transparent = false
|
is_transparent = false
|
||||||
name = 'stone'
|
name = 'stone'
|
||||||
name_key = 'block.stone'
|
|
||||||
roughness = 0.75
|
roughness = 0.75
|
||||||
@@ -9,4 +9,3 @@ is_discard = false
|
|||||||
is_blend = false
|
is_blend = false
|
||||||
is_transitional = false
|
is_transitional = false
|
||||||
roughness = 1.0
|
roughness = 1.0
|
||||||
name_key = "block.template"
|
|
||||||
|
|||||||
@@ -8,5 +8,4 @@ is_passable = true
|
|||||||
is_transitional = false
|
is_transitional = false
|
||||||
is_transparent = true
|
is_transparent = true
|
||||||
name = 'water'
|
name = 'water'
|
||||||
name_key = 'block.water'
|
|
||||||
roughness = 0.02
|
roughness = 0.02
|
||||||
6
assets/item/air.json
Normal file
6
assets/item/air.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "air",
|
||||||
|
"description": "",
|
||||||
|
"type": "block"
|
||||||
|
}
|
||||||
7
assets/item/dirt.json
Normal file
7
assets/item/dirt.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "dirt",
|
||||||
|
"description": "",
|
||||||
|
"texture": "texture/item/block/dirt.png",
|
||||||
|
"type": "block"
|
||||||
|
}
|
||||||
7
assets/item/grass.json
Normal file
7
assets/item/grass.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"id": 9,
|
||||||
|
"name": "grass",
|
||||||
|
"description": "",
|
||||||
|
"texture": "texture/item/block/grass.png",
|
||||||
|
"type": "block"
|
||||||
|
}
|
||||||
7
assets/item/grass_block.json
Normal file
7
assets/item/grass_block.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "grass_block",
|
||||||
|
"description": "",
|
||||||
|
"texture": "texture/item/block/grass_block.png",
|
||||||
|
"type": "block"
|
||||||
|
}
|
||||||
7
assets/item/leaf.json
Normal file
7
assets/item/leaf.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"name": "leaf",
|
||||||
|
"description": "",
|
||||||
|
"texture": "texture/item/block/leaf.png",
|
||||||
|
"type": "block"
|
||||||
|
}
|
||||||
7
assets/item/log.json
Normal file
7
assets/item/log.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"name": "log",
|
||||||
|
"description": "",
|
||||||
|
"texture": "texture/item/block/log.png",
|
||||||
|
"type": "block"
|
||||||
|
}
|
||||||
8
assets/item/pig_spawn_egg.json
Normal file
8
assets/item/pig_spawn_egg.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"id": 10,
|
||||||
|
"name": "pig_spawn_egg",
|
||||||
|
"description": "",
|
||||||
|
"texture": "texture/item/spawn_egg/pig_spawn_egg.png",
|
||||||
|
"type": "spawn_egg",
|
||||||
|
"creature": "cubed:pig"
|
||||||
|
}
|
||||||
7
assets/item/sand.json
Normal file
7
assets/item/sand.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "sand",
|
||||||
|
"description": "",
|
||||||
|
"texture": "texture/item/block/sand.png",
|
||||||
|
"type": "block"
|
||||||
|
}
|
||||||
7
assets/item/snowy_grass_block.json
Normal file
7
assets/item/snowy_grass_block.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"name": "snowy_grass_block",
|
||||||
|
"description": "",
|
||||||
|
"texture": "texture/item/block/snowy_grass_block.png",
|
||||||
|
"type": "block"
|
||||||
|
}
|
||||||
7
assets/item/stone.json
Normal file
7
assets/item/stone.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "stone",
|
||||||
|
"description": "",
|
||||||
|
"texture": "texture/item/block/stone.png",
|
||||||
|
"type": "block"
|
||||||
|
}
|
||||||
7
assets/item/water.json
Normal file
7
assets/item/water.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"name": "water",
|
||||||
|
"description": "",
|
||||||
|
"texture": "texture/item/block/water.png",
|
||||||
|
"type": "block"
|
||||||
|
}
|
||||||
@@ -36,14 +36,15 @@
|
|||||||
"joingame.server_ip": "Server Ip",
|
"joingame.server_ip": "Server Ip",
|
||||||
"joingame.join_world": "Join World",
|
"joingame.join_world": "Join World",
|
||||||
"error.disable_voice": "Server Disable Voice Chat",
|
"error.disable_voice": "Server Disable Voice Chat",
|
||||||
"block.air": "air",
|
"item.air.name": "air",
|
||||||
"block.dirt": "dirt",
|
"item.dirt.name": "dirt",
|
||||||
"block.grass_block": "grass block",
|
"item.grass_block.name": "grass block",
|
||||||
"block.grass": "grass",
|
"item.grass.name": "grass",
|
||||||
"block.leaf": "leaf",
|
"item.leaf.name": "leaf",
|
||||||
"block.log": "log",
|
"item.log.name": "log",
|
||||||
"block.sand": "sand",
|
"item.sand.name": "sand",
|
||||||
"block.snowy_grass_block": "snowy grass block",
|
"item.snowy_grass_block.name": "snowy grass block",
|
||||||
"block.stone": "stone",
|
"item.stone.name": "stone",
|
||||||
"block.water": "water"
|
"item.water.name": "water",
|
||||||
|
"item.pig_spawn_egg.name": "pig spawn egg"
|
||||||
}
|
}
|
||||||
@@ -36,14 +36,15 @@
|
|||||||
"joingame.server_ip": "服务器IP",
|
"joingame.server_ip": "服务器IP",
|
||||||
"joingame.join_world": "加入世界",
|
"joingame.join_world": "加入世界",
|
||||||
"error.disable_voice": "服务器已禁用语音聊天",
|
"error.disable_voice": "服务器已禁用语音聊天",
|
||||||
"block.air": "空气",
|
"item.air.name": "空气",
|
||||||
"block.dirt": "泥土",
|
"item.dirt.name": "泥土",
|
||||||
"block.grass_block": "草方块",
|
"item.grass_block.name": "草方块",
|
||||||
"block.grass": "草",
|
"item.grass.name": "草",
|
||||||
"block.leaf": "树叶",
|
"item.leaf.name": "树叶",
|
||||||
"block.log": "原木",
|
"item.log.name": "原木",
|
||||||
"block.sand": "沙子",
|
"item.sand.name": "沙子",
|
||||||
"block.snowy_grass_block": "覆雪草方块",
|
"item.snowy_grass_block.name": "覆雪草方块",
|
||||||
"block.stone": "石头",
|
"item.stone.name": "石头",
|
||||||
"block.water": "水"
|
"item.water.name": "水",
|
||||||
|
"item.pig_spawn_egg.name": "猪猪刷怪蛋"
|
||||||
}
|
}
|
||||||
16
assets/model/creature/pig/collision.json
Normal file
16
assets/model/creature/pig/collision.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"boxes": [
|
||||||
|
{
|
||||||
|
"center": [
|
||||||
|
0,
|
||||||
|
0.78,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"half": [
|
||||||
|
0.53,
|
||||||
|
0.78,
|
||||||
|
0.406
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
assets/model/creature/pig/pig.glb
Normal file
BIN
assets/model/creature/pig/pig.glb
Normal file
Binary file not shown.
BIN
assets/model/creature/player/player.glb
Normal file
BIN
assets/model/creature/player/player.glb
Normal file
Binary file not shown.
@@ -7,7 +7,6 @@ uniform mat4 lightSpaceMatrix;
|
|||||||
uniform mat4 modelMatrix;
|
uniform mat4 modelMatrix;
|
||||||
|
|
||||||
out vec2 tc;
|
out vec2 tc;
|
||||||
flat out int tex_layer;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
tc = texCoord;
|
tc = texCoord;
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
layout (location = 0) in vec3 pos;
|
layout (location = 0) in vec3 pos;
|
||||||
layout (location = 1) in vec2 texCoord;
|
layout (location = 1) in vec2 texCoord;
|
||||||
layout (location = 2) in vec3 aNormal;
|
layout (location = 2) in vec3 aNormal;
|
||||||
layout (location = 3) in vec3 aTangent;
|
|
||||||
|
|
||||||
uniform mat4 mv_matrix;
|
uniform mat4 mv_matrix;
|
||||||
uniform mat4 proj_matrix;
|
uniform mat4 proj_matrix;
|
||||||
BIN
assets/texture/item/spawn_egg/pig_spawn_egg.png
Normal file
BIN
assets/texture/item/spawn_egg/pig_spawn_egg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 174 B |
@@ -10,7 +10,7 @@ find_package(harfbuzz REQUIRED)
|
|||||||
find_package(Freetype REQUIRED)
|
find_package(Freetype REQUIRED)
|
||||||
find_package(SDL3 REQUIRED)
|
find_package(SDL3 REQUIRED)
|
||||||
find_package(Opus REQUIRED)
|
find_package(Opus REQUIRED)
|
||||||
|
find_package(assimp REQUIRED)
|
||||||
# Third-party libraries
|
# Third-party libraries
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
namespace Cubed {
|
|
||||||
|
|
||||||
struct AABB {
|
|
||||||
glm::vec3 min{0.0f, 0.0f, 0.0f};
|
|
||||||
glm::vec3 max{0.0f, 0.0f, 0.0f};
|
|
||||||
|
|
||||||
AABB(glm::vec3 min_point, glm::vec3 max_point)
|
|
||||||
: min(min_point), max(max_point) {}
|
|
||||||
|
|
||||||
bool intersects(const AABB& other) const {
|
|
||||||
return (min.x <= other.max.x && max.x >= other.min.x) &&
|
|
||||||
(min.y <= other.max.y && max.y >= other.min.y) &&
|
|
||||||
(min.z <= other.max.z && max.z >= other.min.z);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Cubed
|
|
||||||
@@ -49,7 +49,6 @@ private:
|
|||||||
Window m_window;
|
Window m_window;
|
||||||
|
|
||||||
TextureManager m_texture_manager;
|
TextureManager m_texture_manager;
|
||||||
|
|
||||||
AudioEngine m_audio;
|
AudioEngine m_audio;
|
||||||
|
|
||||||
Renderer m_renderer;
|
Renderer m_renderer;
|
||||||
|
|||||||
@@ -13,5 +13,6 @@ struct Argument {
|
|||||||
std::optional<int> log_level;
|
std::optional<int> log_level;
|
||||||
std::optional<bool> enable_filelog;
|
std::optional<bool> enable_filelog;
|
||||||
std::optional<bool> enable_consolelog;
|
std::optional<bool> enable_consolelog;
|
||||||
|
std::optional<bool> direct_enter;
|
||||||
};
|
};
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
class ClientPlayer;
|
class LocalPlayer;
|
||||||
|
|
||||||
class Camera {
|
class Camera {
|
||||||
private:
|
private:
|
||||||
@@ -18,7 +18,7 @@ private:
|
|||||||
THIRD_PERSON_FRONT,
|
THIRD_PERSON_FRONT,
|
||||||
};
|
};
|
||||||
|
|
||||||
ClientPlayer* m_player;
|
LocalPlayer* m_player;
|
||||||
float m_last_mouse_x, m_last_mouse_y;
|
float m_last_mouse_x, m_last_mouse_y;
|
||||||
glm::vec3 m_camera_pos;
|
glm::vec3 m_camera_pos;
|
||||||
bool m_under_water = false;
|
bool m_under_water = false;
|
||||||
@@ -35,7 +35,7 @@ public:
|
|||||||
|
|
||||||
void update_move_camera();
|
void update_move_camera();
|
||||||
|
|
||||||
void camera_init(ClientPlayer* player);
|
void camera_init(LocalPlayer* player);
|
||||||
void hot_reload();
|
void hot_reload();
|
||||||
void update_cursor_position_camera(float offset_x, float offset_y);
|
void update_cursor_position_camera(float offset_x, float offset_y);
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ public:
|
|||||||
void change_perspective();
|
void change_perspective();
|
||||||
bool is_first_person() const;
|
bool is_first_person() const;
|
||||||
bool handle_event(const Event& e);
|
bool handle_event(const Event& e);
|
||||||
ClientPlayer* player();
|
LocalPlayer* player();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
class WorldScene;
|
class WorldScene;
|
||||||
class ClientPlayer;
|
class LocalPlayer;
|
||||||
class App;
|
class App;
|
||||||
class DevPanel {
|
class DevPanel {
|
||||||
struct ConfigView {
|
struct ConfigView {
|
||||||
@@ -42,7 +42,7 @@ private:
|
|||||||
WorldScene& m_world_scene;
|
WorldScene& m_world_scene;
|
||||||
Config& m_config;
|
Config& m_config;
|
||||||
ConfigView m_config_view;
|
ConfigView m_config_view;
|
||||||
ClientPlayer* m_player;
|
LocalPlayer* m_player;
|
||||||
PlayerProfile m_player_profile;
|
PlayerProfile m_player_profile;
|
||||||
bool m_need_save_config = false;
|
bool m_need_save_config = false;
|
||||||
bool m_gen_thread_running = true;
|
bool m_gen_thread_running = true;
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ struct LookBlock {
|
|||||||
|
|
||||||
struct BlockData {
|
struct BlockData {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string name_key;
|
|
||||||
BlockType id = 0;
|
BlockType id = 0;
|
||||||
|
|
||||||
bool is_liquid = false;
|
bool is_liquid = false;
|
||||||
@@ -56,42 +55,14 @@ struct BlockData {
|
|||||||
bool is_blend = false;
|
bool is_blend = false;
|
||||||
bool is_transitional = false;
|
bool is_transitional = false;
|
||||||
float roughness = 1.0f;
|
float roughness = 1.0f;
|
||||||
BlockData(std::string_view b_name, std::string_view name_k, BlockType b_id,
|
BlockData(std::string_view b_name, BlockType b_id, bool liquid,
|
||||||
bool liquid, bool passable, bool cross_plane, bool transparent,
|
bool passable, bool cross_plane, bool transparent, bool gas,
|
||||||
bool gas, bool discard, bool blend, bool transitional, float r)
|
bool discard, bool blend, bool transitional, float r)
|
||||||
: name(b_name), name_key(name_k), id(b_id), is_liquid(liquid),
|
: name(b_name), id(b_id), is_liquid(liquid), is_gas(gas),
|
||||||
is_gas(gas), is_passable(passable), is_cross_plane(cross_plane),
|
is_passable(passable), is_cross_plane(cross_plane),
|
||||||
is_transparent(transparent), is_discard(discard), is_blend(blend),
|
is_transparent(transparent), is_discard(discard), is_blend(blend),
|
||||||
is_transitional(transitional), roughness(r) {}
|
is_transitional(transitional), roughness(r) {}
|
||||||
};
|
BlockData() { name = ""; }
|
||||||
|
|
||||||
class BlockManager {
|
|
||||||
|
|
||||||
public:
|
|
||||||
static const std::vector<BlockData>& datas();
|
|
||||||
static void init();
|
|
||||||
static unsigned sums();
|
|
||||||
static unsigned cross_plane_sum();
|
|
||||||
static const std::string& name_form_id(BlockType id);
|
|
||||||
static std::string local_name(BlockType id);
|
|
||||||
static bool is_gas(BlockType id);
|
|
||||||
static bool is_liquid(BlockType id);
|
|
||||||
|
|
||||||
static bool is_cross_plane(BlockType id);
|
|
||||||
static bool is_transparent(BlockType id);
|
|
||||||
static bool is_passable(BlockType id);
|
|
||||||
|
|
||||||
static bool is_discard(BlockType id);
|
|
||||||
static bool is_blend(BlockType id);
|
|
||||||
static bool is_transitional(BlockType id);
|
|
||||||
static float roughness(BlockType id);
|
|
||||||
static BlockType cross_plane_index(BlockType id);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void set_up_cross_plane_map();
|
|
||||||
static inline std::vector<BlockData> m_datas;
|
|
||||||
static inline bool is_init = false;
|
|
||||||
static inline std::unordered_map<BlockType, BlockType> m_cross_plane_map;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
45
include/Cubed/gameplay/block_manager.hpp
Normal file
45
include/Cubed/gameplay/block_manager.hpp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Cubed/gameplay/block.hpp"
|
||||||
|
|
||||||
|
#include <tbb/concurrent_hash_map.h>
|
||||||
|
namespace Cubed {
|
||||||
|
class BlockManager {
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void init();
|
||||||
|
static unsigned sums();
|
||||||
|
static unsigned cross_plane_sum();
|
||||||
|
static const std::string& name_form_id(BlockType id);
|
||||||
|
static bool is_gas(BlockType id);
|
||||||
|
static bool is_liquid(BlockType id);
|
||||||
|
|
||||||
|
static bool is_cross_plane(BlockType id);
|
||||||
|
static bool is_transparent(BlockType id);
|
||||||
|
static bool is_passable(BlockType id);
|
||||||
|
|
||||||
|
static bool is_discard(BlockType id);
|
||||||
|
static bool is_blend(BlockType id);
|
||||||
|
static bool is_transitional(BlockType id);
|
||||||
|
static float roughness(BlockType id);
|
||||||
|
static BlockType cross_plane_index(BlockType id);
|
||||||
|
|
||||||
|
static BlockType id_from_name(const std::string& name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
using BlockMap = tbb::concurrent_hash_map<BlockType, BlockData>;
|
||||||
|
using acc = BlockMap::accessor;
|
||||||
|
using cacc = BlockMap::const_accessor;
|
||||||
|
using IDMap = tbb::concurrent_hash_map<std::string, BlockType>;
|
||||||
|
using CrossPlaneMap = tbb::concurrent_hash_map<BlockType, BlockType>;
|
||||||
|
|
||||||
|
static inline const BlockData EMPTY;
|
||||||
|
|
||||||
|
static inline BlockMap m_datas;
|
||||||
|
static inline IDMap m_id_map;
|
||||||
|
static inline bool is_init = false;
|
||||||
|
static inline CrossPlaneMap m_cross_plane_map;
|
||||||
|
static void set_up_cross_plane_map(
|
||||||
|
const std::vector<std::pair<bool, BlockType>>& types);
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
27
include/Cubed/gameplay/chunk.hpp
Normal file
27
include/Cubed/gameplay/chunk.hpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <tuple>
|
||||||
|
namespace Cubed {
|
||||||
|
class Chunk {
|
||||||
|
public:
|
||||||
|
Chunk() = default;
|
||||||
|
Chunk(const Chunk&) = delete;
|
||||||
|
Chunk(Chunk&&) = delete;
|
||||||
|
Chunk& operator=(const Chunk&) = delete;
|
||||||
|
Chunk& operator=(Chunk&&) = delete;
|
||||||
|
virtual ~Chunk() = default;
|
||||||
|
static int index(int x, int y, int z);
|
||||||
|
static int index(const glm::vec3& pos);
|
||||||
|
static std::tuple<int, int, int> world_to_block(int world_x, int world_y,
|
||||||
|
int world_z, int chunk_x,
|
||||||
|
int chunk_z);
|
||||||
|
static std::tuple<int, int, int> world_to_block(const glm::ivec3& block_pos,
|
||||||
|
ChunkPos chunk_pos);
|
||||||
|
static std::tuple<int, int, int> block_to_world(int x, int y, int z,
|
||||||
|
int chunk_x, int chunk_z);
|
||||||
|
static std::tuple<int, int, int> block_to_world(const glm::ivec3& block_pos,
|
||||||
|
ChunkPos chunk_pos);
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
@@ -50,6 +50,8 @@ public:
|
|||||||
void generate_cave();
|
void generate_cave();
|
||||||
void generate_river();
|
void generate_river();
|
||||||
|
|
||||||
|
void spawn_creature();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static inline std::atomic<bool> is_init{false};
|
static inline std::atomic<bool> is_init{false};
|
||||||
static inline unsigned m_generator_seed{0};
|
static inline unsigned m_generator_seed{0};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "Cubed/constants.hpp"
|
#include "Cubed/constants.hpp"
|
||||||
#include "Cubed/gameplay/biome.hpp"
|
#include "Cubed/gameplay/biome.hpp"
|
||||||
#include "Cubed/gameplay/block.hpp"
|
#include "Cubed/gameplay/block.hpp"
|
||||||
|
#include "Cubed/gameplay/chunk.hpp"
|
||||||
#include "Cubed/gameplay/chunk_pos.hpp"
|
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||||
#include "Cubed/gameplay/vertex_data.hpp"
|
#include "Cubed/gameplay/vertex_data.hpp"
|
||||||
#include "world/chunk_data.pb.h"
|
#include "world/chunk_data.pb.h"
|
||||||
@@ -26,7 +27,7 @@ struct ChunkRenderSnapshot {
|
|||||||
glm::vec3 center;
|
glm::vec3 center;
|
||||||
glm::vec3 half_extents;
|
glm::vec3 half_extents;
|
||||||
};
|
};
|
||||||
class ClientChunk {
|
class ClientChunk : public Chunk {
|
||||||
public:
|
public:
|
||||||
ClientChunk(ClientWorld& world);
|
ClientChunk(ClientWorld& world);
|
||||||
~ClientChunk();
|
~ClientChunk();
|
||||||
@@ -35,17 +36,6 @@ public:
|
|||||||
ClientChunk(ClientChunk&&) noexcept;
|
ClientChunk(ClientChunk&&) noexcept;
|
||||||
ClientChunk& operator=(ClientChunk&&) noexcept;
|
ClientChunk& operator=(ClientChunk&&) noexcept;
|
||||||
|
|
||||||
static int index(int x, int y, int z);
|
|
||||||
static int index(const glm::vec3& pos);
|
|
||||||
static std::tuple<int, int, int> world_to_block(int world_x, int world_y,
|
|
||||||
int world_z, int chunk_x,
|
|
||||||
int chunk_z);
|
|
||||||
static std::tuple<int, int, int> world_to_block(const glm::ivec3& block_pos,
|
|
||||||
ChunkPos chunk_pos);
|
|
||||||
static std::tuple<int, int, int> block_to_world(int x, int y, int z,
|
|
||||||
int chunk_x, int chunk_z);
|
|
||||||
static std::tuple<int, int, int> block_to_world(const glm::ivec3& block_pos,
|
|
||||||
ChunkPos chunk_pos);
|
|
||||||
BiomeType get_biome() const;
|
BiomeType get_biome() const;
|
||||||
ChunkPos get_chunk_pos() const;
|
ChunkPos get_chunk_pos() const;
|
||||||
const std::vector<BlockType>& get_chunk_blocks() const;
|
const std::vector<BlockType>& get_chunk_blocks() const;
|
||||||
|
|||||||
77
include/Cubed/gameplay/client_entity_manager.hpp
Normal file
77
include/Cubed/gameplay/client_entity_manager.hpp
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/ecs/entity.hpp"
|
||||||
|
#include "glm/ext/vector_float3.hpp"
|
||||||
|
#include "world/entity.pb.h"
|
||||||
|
|
||||||
|
#include <entt/entt.hpp>
|
||||||
|
#include <tbb/concurrent_hash_map.h>
|
||||||
|
#include <tbb/concurrent_queue.h>
|
||||||
|
namespace Cubed {
|
||||||
|
class ClientWorld;
|
||||||
|
class ClientEntityManager {
|
||||||
|
public:
|
||||||
|
enum class Command { CREATE, DESTORY, UPDATE };
|
||||||
|
|
||||||
|
ClientEntityManager(ClientWorld& world);
|
||||||
|
void update();
|
||||||
|
void init();
|
||||||
|
|
||||||
|
void receive_entity_create(S2CEntityCreate& msg);
|
||||||
|
void receive_entity_destory(EntityID id);
|
||||||
|
void receive_entity_update(S2CEntityUpdate& msg);
|
||||||
|
|
||||||
|
void destory(EntityID id);
|
||||||
|
void create(std::string_view name, const glm::vec3& pos);
|
||||||
|
|
||||||
|
const entt::registry& get_registry() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct EntityCreateElement {
|
||||||
|
EntityID id;
|
||||||
|
std::string name;
|
||||||
|
glm::vec3 pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UpdateInfo {
|
||||||
|
EntityID id;
|
||||||
|
glm::vec3 pos;
|
||||||
|
glm::vec3 direction;
|
||||||
|
};
|
||||||
|
|
||||||
|
using EntityMap = tbb::concurrent_hash_map<EntityID, entt::entity>;
|
||||||
|
using acc = EntityMap::accessor;
|
||||||
|
using cacc = EntityMap::const_accessor;
|
||||||
|
using CreateFunc = std::function<void(EntityID id)>;
|
||||||
|
using TaskElement = std::variant<EntityCreateElement, EntityID, UpdateInfo>;
|
||||||
|
using TaskPair = std::pair<Command, TaskElement>;
|
||||||
|
|
||||||
|
ClientWorld& m_world;
|
||||||
|
entt::registry m_registry;
|
||||||
|
EntityMap m_entities;
|
||||||
|
std::unordered_map<std::string_view, CreateFunc> m_factories;
|
||||||
|
tbb::concurrent_queue<TaskPair> m_tasks;
|
||||||
|
|
||||||
|
void handle_task();
|
||||||
|
void handle_entity_destory(EntityID id);
|
||||||
|
// not thread safe
|
||||||
|
void handle_entity_create(EntityID id, std::string_view name,
|
||||||
|
const glm::vec3& pos);
|
||||||
|
void handle_entity_update(UpdateInfo& info);
|
||||||
|
template <typename... Args>
|
||||||
|
void create_entity_in_registry(EntityID id, Args&&... args) {
|
||||||
|
{
|
||||||
|
cacc a;
|
||||||
|
if (m_entities.find(a, id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto entity = m_registry.create();
|
||||||
|
|
||||||
|
((m_registry.emplace<std::remove_cvref_t<Args>>(
|
||||||
|
entity, std::forward<Args>(args))),
|
||||||
|
...);
|
||||||
|
m_entities.emplace(id, entity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
@@ -1,167 +1,25 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Cubed/AABB.hpp"
|
|
||||||
#include "Cubed/constants.hpp"
|
|
||||||
#include "Cubed/gameplay/block.hpp"
|
|
||||||
#include "Cubed/gameplay/chunk_pos.hpp"
|
|
||||||
#include "Cubed/gameplay/game_mode.hpp"
|
|
||||||
#include "Cubed/gameplay/game_time.hpp"
|
|
||||||
#include "Cubed/gameplay/item_stack.hpp"
|
|
||||||
#include "Cubed/gameplay/player.hpp"
|
|
||||||
#include "Cubed/input/event.hpp"
|
|
||||||
#include "Cubed/input/input.hpp"
|
|
||||||
|
|
||||||
#include <absl/container/flat_hash_set.h>
|
#include "Cubed/gameplay/ecs/animation.hpp"
|
||||||
#include <glm/glm.hpp>
|
#include "Cubed/gameplay/ecs/identity.hpp"
|
||||||
#include <optional>
|
#include "Cubed/gameplay/ecs/transform.hpp"
|
||||||
#include <shared_mutex>
|
#include "Cubed/gameplay/player.hpp"
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
class ClientWorld;
|
struct ClientPlayer {
|
||||||
class ClientPlayer {
|
Position pos{};
|
||||||
public:
|
Position render_pos{};
|
||||||
static constexpr size_t HOTBAR_SUM = 10;
|
EntityInfo entity{};
|
||||||
static constexpr float WALK_SOUND_INTERVAL = 0.45f;
|
WalkPose walk{};
|
||||||
static constexpr float RUN_SOUND_INTERVAL = 0.3f;
|
Orientation angle{};
|
||||||
using ChunkPosSet = absl::flat_hash_set<ChunkPos, ChunkPos::Hash>;
|
Orientation render_angle{};
|
||||||
ClientPlayer(ClientWorld& world);
|
|
||||||
~ClientPlayer();
|
|
||||||
|
|
||||||
bool handle_mouse_button_event(const MouseButtonEvent& e);
|
|
||||||
bool handle_key_event(const KeyEvent& e);
|
|
||||||
bool handle_mouse_wheel_event(const MouseWheelEvent& e);
|
|
||||||
|
|
||||||
void update_front_vec(float offset_x, float offset_y);
|
|
||||||
bool update_player_move_state(Key key, KeyAction action);
|
|
||||||
bool update_scroll(float yoffset);
|
|
||||||
|
|
||||||
void update_chunk_set(const ChunkPosSet& set);
|
|
||||||
const ChunkPosSet& get_chunk_pos_set() const;
|
|
||||||
ChunkPosSet get_chunk_pos_set();
|
|
||||||
|
|
||||||
static AABB get_aabb(const glm::vec3& pos);
|
|
||||||
const glm::vec3& get_front() const;
|
|
||||||
Gait get_gait() const;
|
|
||||||
const std::optional<LookBlock>& get_look_block_pos() const;
|
|
||||||
// thread safe
|
|
||||||
glm::vec3 get_player_pos() const;
|
|
||||||
const MoveState& get_move_state() const;
|
|
||||||
|
|
||||||
void change_mode(GameMode mode);
|
|
||||||
void reload_config();
|
|
||||||
void set_player_pos(const glm::vec3& pos);
|
|
||||||
void update(float delta_time);
|
|
||||||
|
|
||||||
float& max_walk_speed();
|
|
||||||
float& max_run_speed();
|
|
||||||
float& max_speed();
|
|
||||||
float& acceleration();
|
|
||||||
float& deceleration();
|
|
||||||
float& g();
|
|
||||||
float& fly_y_speed();
|
|
||||||
|
|
||||||
const ItemStack& get_current_itemstack() const;
|
|
||||||
|
|
||||||
void set_gait(Gait gait);
|
|
||||||
GameMode& game_mode();
|
|
||||||
|
|
||||||
ClientWorld& get_world();
|
|
||||||
|
|
||||||
void set_uuid(std::string_view uuid);
|
|
||||||
std::string get_uuid() const;
|
|
||||||
const std::string& get_name() const;
|
|
||||||
void reset_key_status();
|
|
||||||
void init(std::string_view name);
|
|
||||||
|
|
||||||
float yaw() const;
|
|
||||||
float pitch() const;
|
|
||||||
float& angle();
|
|
||||||
float& walk_time();
|
|
||||||
bool ray_cast(const glm::vec3& start, const glm::vec3& dir,
|
|
||||||
glm::ivec3& block_pos, glm::vec3& normal,
|
|
||||||
float distance = 4.0f);
|
|
||||||
bool is_underwater() const;
|
|
||||||
void set_underwater(bool u);
|
|
||||||
void place_block(float dt);
|
|
||||||
|
|
||||||
int selected_hotbar() const;
|
|
||||||
void set_hotbar(int pos, const ItemStack& item);
|
|
||||||
std::span<const ItemStack, HOTBAR_SUM> get_hotbar() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
using enum GameMode;
|
|
||||||
float m_max_walk_speed = DEFAULT_MAX_WALK_SPEED;
|
|
||||||
float m_max_run_speed = DEFAULT_MAX_RUN_SPEED;
|
|
||||||
float m_acceleration = DEFAULT_ACCELERATION;
|
|
||||||
float m_deceleration = DEFAULT_DECELERATION;
|
|
||||||
float m_g = DEFAULT_G;
|
|
||||||
static constexpr float MAX_SPACE_ON_TIME = 0.3f;
|
|
||||||
static constexpr float PLACE_BLOCK_INTERVAL = 0.2f;
|
|
||||||
|
|
||||||
float m_place_time = PLACE_BLOCK_INTERVAL;
|
|
||||||
std::atomic<float> m_yaw = 0.0f;
|
|
||||||
std::atomic<float> m_pitch = 0.0f;
|
|
||||||
std::array<ItemStack, HOTBAR_SUM> m_hotbar;
|
|
||||||
float m_sensitivity = 0.15f;
|
|
||||||
|
|
||||||
float m_max_speed = m_max_walk_speed;
|
|
||||||
float m_y_speed = 0.0f;
|
|
||||||
float m_fly_y_speed = 7.5f;
|
|
||||||
bool can_up = true;
|
|
||||||
|
|
||||||
float space_on_time = 0.0f;
|
|
||||||
bool space_on = false;
|
|
||||||
bool is_fly = false;
|
|
||||||
|
|
||||||
float m_xz_speed = 0.0f;
|
|
||||||
|
|
||||||
int m_selected_hotbar = 0;
|
|
||||||
|
|
||||||
bool m_moving = false;
|
|
||||||
bool m_sprinting = false;
|
|
||||||
bool m_underwater = false;
|
|
||||||
|
|
||||||
glm::vec3 direction = glm::vec3(0.0f, 0.0f, 0.0f);
|
|
||||||
glm::vec3 move_distance{0.0f, 0.0f, 0.0f};
|
|
||||||
// player is tow block tall, the pos is the lower pos
|
|
||||||
|
|
||||||
glm::vec3 m_player_pos{0.0f, 255.0f, 0.0f};
|
|
||||||
ChunkPos m_last_chunk_pos{0, 0};
|
|
||||||
|
|
||||||
glm::vec3 m_front{0, 0, -1};
|
|
||||||
glm::vec3 m_right{0, 0, 0};
|
|
||||||
static constexpr glm::vec3 M_SIZE{0.6f, 1.8f, 0.6f};
|
|
||||||
|
|
||||||
std::atomic<Gait> m_gait = Gait::STOP;
|
|
||||||
MoveState m_move_state{};
|
|
||||||
MouseState m_mouse_state{};
|
|
||||||
GameMode m_game_mode = CREATIVE;
|
|
||||||
std::optional<LookBlock> m_look_block = std::nullopt;
|
|
||||||
std::string m_name{};
|
|
||||||
mutable std::shared_mutex m_uuid_mutex;
|
|
||||||
std::string m_uuid;
|
|
||||||
ClientWorld& m_world;
|
|
||||||
|
|
||||||
float m_angle{0.0f};
|
|
||||||
float m_walk_time{0.0f};
|
|
||||||
|
|
||||||
std::unordered_map<std::string, Timer> m_timers;
|
|
||||||
|
|
||||||
mutable std::shared_mutex m_player_pos_mutex;
|
|
||||||
mutable std::shared_mutex m_chunk_pos_mutex;
|
|
||||||
ChunkPosSet m_player_chunk_pos_set;
|
|
||||||
|
|
||||||
void update_direction();
|
|
||||||
void update_lookup_block();
|
|
||||||
|
|
||||||
void update_move(float delta_time);
|
|
||||||
|
|
||||||
void update_x_move(glm::vec3& player_pos);
|
|
||||||
void update_y_move(glm::vec3& player_pos);
|
|
||||||
void update_z_move(glm::vec3& player_pos);
|
|
||||||
|
|
||||||
void update_player_chunk();
|
|
||||||
|
|
||||||
void play_walk_sound(float dt);
|
|
||||||
Gait compute_gait() const;
|
|
||||||
};
|
};
|
||||||
} // namespace Cubed
|
|
||||||
|
struct PlayerRenderData {
|
||||||
|
EntityInfo info{};
|
||||||
|
Position render_pos{};
|
||||||
|
Orientation angle{};
|
||||||
|
Gait gait{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
45
include/Cubed/gameplay/client_player_manager.hpp
Normal file
45
include/Cubed/gameplay/client_player_manager.hpp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/client_player.hpp"
|
||||||
|
#include "Cubed/gameplay/local_player.hpp"
|
||||||
|
#include "Cubed/gameplay/network_client.hpp"
|
||||||
|
#include "Cubed/tools/sparse_vector.hpp"
|
||||||
|
namespace Cubed {
|
||||||
|
class ClientWorld;
|
||||||
|
class ClientPlayerManager {
|
||||||
|
public:
|
||||||
|
ClientPlayerManager(const ClientPlayerManager&) = delete;
|
||||||
|
ClientPlayerManager(ClientPlayerManager&&) = delete;
|
||||||
|
ClientPlayerManager& operator=(const ClientPlayerManager&) = delete;
|
||||||
|
ClientPlayerManager& operator=(ClientPlayerManager&&) = delete;
|
||||||
|
ClientPlayerManager(ClientWorld& world);
|
||||||
|
~ClientPlayerManager();
|
||||||
|
|
||||||
|
void init(std::string_view local_name);
|
||||||
|
void update(float dt);
|
||||||
|
|
||||||
|
std::span<PlayerRenderData> render_player_data();
|
||||||
|
|
||||||
|
bool has_player(const Hitbox& hitbox) const;
|
||||||
|
|
||||||
|
LocalPlayer& get_local();
|
||||||
|
const LocalPlayer& get_local() const;
|
||||||
|
|
||||||
|
void receive_remote_player(const PlayerInfoRsp& rsp);
|
||||||
|
void receive_player_logout(const LogoutRsp& rsp);
|
||||||
|
|
||||||
|
void reload_config();
|
||||||
|
|
||||||
|
void report_player_info(NetworkClient* client);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ClientWorld& m_world;
|
||||||
|
mutable std::shared_mutex m_players_mutex;
|
||||||
|
using PlayerHandle = SparseVector<ClientPlayer>::Handle;
|
||||||
|
SparseVector<ClientPlayer> m_players;
|
||||||
|
std::vector<PlayerRenderData> m_render_data;
|
||||||
|
std::unordered_map<std::string, PlayerHandle> m_players_handle;
|
||||||
|
LocalPlayer m_local;
|
||||||
|
|
||||||
|
void update_players_data(float dt);
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
@@ -5,9 +5,12 @@
|
|||||||
#include "Cubed/gameplay/chat_message.hpp"
|
#include "Cubed/gameplay/chat_message.hpp"
|
||||||
#include "Cubed/gameplay/chunk_pos.hpp"
|
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||||
#include "Cubed/gameplay/client_chunk.hpp"
|
#include "Cubed/gameplay/client_chunk.hpp"
|
||||||
#include "Cubed/gameplay/client_player.hpp"
|
#include "Cubed/gameplay/client_entity_manager.hpp"
|
||||||
|
#include "Cubed/gameplay/client_player_manager.hpp"
|
||||||
#include "Cubed/gameplay/game_time.hpp"
|
#include "Cubed/gameplay/game_time.hpp"
|
||||||
|
#include "Cubed/gameplay/local_player.hpp"
|
||||||
#include "Cubed/gameplay/network_client.hpp"
|
#include "Cubed/gameplay/network_client.hpp"
|
||||||
|
#include "Cubed/gameplay/world.hpp"
|
||||||
#include "Cubed/input/event.hpp"
|
#include "Cubed/input/event.hpp"
|
||||||
#include "Cubed/tools/cubed_random.hpp"
|
#include "Cubed/tools/cubed_random.hpp"
|
||||||
#include "Cubed/tools/priority_thread_pool.hpp"
|
#include "Cubed/tools/priority_thread_pool.hpp"
|
||||||
@@ -19,46 +22,26 @@
|
|||||||
#include <tbb/concurrent_unordered_map.h>
|
#include <tbb/concurrent_unordered_map.h>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
struct PlayerInfo {
|
|
||||||
std::string name;
|
|
||||||
std::string uuid;
|
|
||||||
glm::vec3 render_pos;
|
|
||||||
glm::vec3 target_pos;
|
|
||||||
float render_yaw;
|
|
||||||
float yaw;
|
|
||||||
float render_pitch;
|
|
||||||
float pitch;
|
|
||||||
Gait gait;
|
|
||||||
float angle = 0.0f;
|
|
||||||
float walk_time = 0.0f;
|
|
||||||
float moving_time = 0.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PlayerRenderData {
|
|
||||||
std::string name;
|
|
||||||
std::string uuid;
|
|
||||||
glm::vec3 render_pos;
|
|
||||||
float yaw;
|
|
||||||
float pitch;
|
|
||||||
Gait gait;
|
|
||||||
float angle;
|
|
||||||
};
|
|
||||||
class WorldScene;
|
class WorldScene;
|
||||||
class ClientWorld {
|
class ClientWorld : public World {
|
||||||
public:
|
public:
|
||||||
|
ClientWorld(const ClientWorld&) = delete;
|
||||||
|
ClientWorld(ClientWorld&&) = delete;
|
||||||
|
ClientWorld& operator=(const ClientWorld&) = delete;
|
||||||
|
ClientWorld& operator=(ClientWorld&&) = delete;
|
||||||
ClientWorld(AudioEngine& auido, Config& config, WorldScene& scene);
|
ClientWorld(AudioEngine& auido, Config& config, WorldScene& scene);
|
||||||
~ClientWorld();
|
~ClientWorld();
|
||||||
void init(std::string_view player_name,
|
void init(std::string_view player_name,
|
||||||
std::shared_ptr<NetworkClient> client);
|
std::shared_ptr<NetworkClient> client, RunMode mode);
|
||||||
void update(float delta_time);
|
void update(float dt);
|
||||||
bool handle_event(const Event& e);
|
bool handle_event(const Event& e);
|
||||||
const std::optional<LookBlock>& get_look_block_pos() const;
|
const std::optional<LookBlock>& get_look_block_pos() const;
|
||||||
ClientPlayer& get_player();
|
LocalPlayer& get_player();
|
||||||
const ClientPlayer& get_player() const;
|
const LocalPlayer& get_player() const;
|
||||||
int get_block(const glm::ivec3& block_pos) const;
|
int get_block(const glm::ivec3& block_pos) const override;
|
||||||
bool is_solid(const glm::ivec3& block_pos) const;
|
bool is_solid(const glm::ivec3& block_pos) const override;
|
||||||
bool can_pass_block(const glm::ivec3& block_pos) const;
|
bool can_pass_block(const glm::ivec3& block_pos) const override;
|
||||||
BlockType get_block_tpye(const glm::ivec3& block_pos) const;
|
BlockType get_block_tpye(const glm::ivec3& block_pos) const override;
|
||||||
|
|
||||||
void rebuild_world();
|
void rebuild_world();
|
||||||
|
|
||||||
@@ -71,7 +54,6 @@ public:
|
|||||||
void receive_block_change(const BlockChangeRsp& rsp);
|
void receive_block_change(const BlockChangeRsp& rsp);
|
||||||
void receive_time(const UpdateTime& rsp);
|
void receive_time(const UpdateTime& rsp);
|
||||||
|
|
||||||
void receive_remote_player(const PlayerInfoRsp& rsp);
|
|
||||||
void receive_player_logout(const LogoutRsp& rsp);
|
void receive_player_logout(const LogoutRsp& rsp);
|
||||||
void receive_player_water_sound(const PlayerWaterSound& rsp);
|
void receive_player_water_sound(const PlayerWaterSound& rsp);
|
||||||
void send_player_water_sound(bool underwater, const glm::vec3& pos);
|
void send_player_water_sound(bool underwater, const glm::vec3& pos);
|
||||||
@@ -90,8 +72,6 @@ public:
|
|||||||
void reset_key_status();
|
void reset_key_status();
|
||||||
std::vector<glm::vec4>& planes();
|
std::vector<glm::vec4>& planes();
|
||||||
const std::vector<const ChunkRenderSnapshot*>& render_snapshots() const;
|
const std::vector<const ChunkRenderSnapshot*>& render_snapshots() const;
|
||||||
const std::vector<PlayerRenderData>& render_player_data() const;
|
|
||||||
std::vector<PlayerRenderData>& render_player_data();
|
|
||||||
|
|
||||||
glm::vec3 sunlight_dir() const;
|
glm::vec3 sunlight_dir() const;
|
||||||
bool sphere_collide_world(glm::vec3 center, float radius) const;
|
bool sphere_collide_world(glm::vec3 center, float radius) const;
|
||||||
@@ -99,23 +79,29 @@ public:
|
|||||||
void request_exit();
|
void request_exit();
|
||||||
bool is_receive_exit();
|
bool is_receive_exit();
|
||||||
int chunk_size() const;
|
int chunk_size() const;
|
||||||
static AABB get_block_aabb(const glm::ivec3& pos);
|
|
||||||
AudioEngine& get_audio();
|
AudioEngine& get_audio();
|
||||||
const AudioEngine& get_audio() const;
|
const AudioEngine& get_audio() const;
|
||||||
Config& get_config();
|
Config& get_config();
|
||||||
WorldScene& world_scene();
|
WorldScene& world_scene();
|
||||||
|
ClientPlayerManager& player_manager();
|
||||||
|
ClientEntityManager& entity_manager();
|
||||||
|
std::shared_ptr<NetworkClient> get_client() const;
|
||||||
void set_direct_exit();
|
void set_direct_exit();
|
||||||
|
|
||||||
void receive_chat_message(ChatMsg& msg);
|
void receive_chat_message(ChatMsg& msg);
|
||||||
void send_chat_message(ChatMessage& message);
|
void send_chat_message(ChatMessage& message);
|
||||||
void receive_voice_message(VoiceMsg& msg);
|
void receive_voice_message(VoiceMsg& msg);
|
||||||
bool enable_voice_chat() const;
|
bool enable_voice_chat() const;
|
||||||
|
int get_per_tick_time() const override;
|
||||||
|
|
||||||
|
bool is_render(const glm::vec3& pos) const;
|
||||||
|
|
||||||
template <typename Fn>
|
template <typename Fn>
|
||||||
void register_ticktimer(std::string_view id, TickType threshold, Fn&& f) {
|
void register_timer(std::string_view id, float threshold, Fn&& f) {
|
||||||
m_ticktimers.emplace(
|
m_timers.emplace(std::piecewise_construct,
|
||||||
std::piecewise_construct, std::forward_as_tuple(std::string(id)),
|
std::forward_as_tuple(std::string(id)),
|
||||||
std::forward_as_tuple(threshold, std::forward<Fn>(f)));
|
std::forward_as_tuple(threshold, std::forward<Fn>(f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -136,7 +122,6 @@ private:
|
|||||||
ChunkPos::TBBHash>;
|
ChunkPos::TBBHash>;
|
||||||
using ChunkPosSet = absl::flat_hash_set<ChunkPos, ChunkPos::Hash>;
|
using ChunkPosSet = absl::flat_hash_set<ChunkPos, ChunkPos::Hash>;
|
||||||
using ChunkPosVector = std::vector<ChunkPos>;
|
using ChunkPosVector = std::vector<ChunkPos>;
|
||||||
using OtherPlayerHashMap = std::unordered_map<std::string, PlayerInfo>;
|
|
||||||
using chunk_acc = ChunkHashMap::accessor;
|
using chunk_acc = ChunkHashMap::accessor;
|
||||||
using chunk_cacc = ChunkHashMap::const_accessor;
|
using chunk_cacc = ChunkHashMap::const_accessor;
|
||||||
|
|
||||||
@@ -147,16 +132,14 @@ private:
|
|||||||
|
|
||||||
static constexpr int WORLD_EXIT_TIMEOUT = 200;
|
static constexpr int WORLD_EXIT_TIMEOUT = 200;
|
||||||
static constexpr int MAX_UPLOAD_CHUNK_SUM = 16;
|
static constexpr int MAX_UPLOAD_CHUNK_SUM = 16;
|
||||||
ClientPlayer m_player;
|
std::atomic<RunMode> m_runmode = RunMode::HYBRID;
|
||||||
OtherPlayerHashMap m_player_info;
|
ClientEntityManager m_entity_manager;
|
||||||
|
ClientPlayerManager m_player_manager;
|
||||||
ChunkHashMap m_chunks;
|
ChunkHashMap m_chunks;
|
||||||
AudioEngine& m_audio;
|
AudioEngine& m_audio;
|
||||||
Config& m_config;
|
Config& m_config;
|
||||||
WorldScene& m_world_scene;
|
WorldScene& m_world_scene;
|
||||||
std::vector<glm::vec4> m_planes;
|
std::vector<glm::vec4> m_planes;
|
||||||
std::jthread m_client_thread;
|
|
||||||
|
|
||||||
mutable std::shared_mutex m_player_info_mutex;
|
|
||||||
|
|
||||||
tbb::concurrent_queue<std::unique_ptr<ClientChunk>> m_pending_upload_queue;
|
tbb::concurrent_queue<std::unique_ptr<ClientChunk>> m_pending_upload_queue;
|
||||||
tbb::concurrent_queue<ChunkPos> m_dirty_chunk_queue;
|
tbb::concurrent_queue<ChunkPos> m_dirty_chunk_queue;
|
||||||
@@ -166,9 +149,7 @@ private:
|
|||||||
|
|
||||||
std::deque<ChunkPos> m_dirty_queue;
|
std::deque<ChunkPos> m_dirty_queue;
|
||||||
std::vector<const ChunkRenderSnapshot*> m_render_snapshots;
|
std::vector<const ChunkRenderSnapshot*> m_render_snapshots;
|
||||||
std::vector<PlayerRenderData> m_render_player_data;
|
|
||||||
|
|
||||||
tbb::concurrent_unordered_map<std::string, TickTimer> m_ticktimers;
|
|
||||||
std::unordered_map<std::string, Timer> m_timers;
|
std::unordered_map<std::string, Timer> m_timers;
|
||||||
std::atomic<bool> m_exit_direct{false};
|
std::atomic<bool> m_exit_direct{false};
|
||||||
std::atomic<bool> m_game_running{false};
|
std::atomic<bool> m_game_running{false};
|
||||||
@@ -176,6 +157,7 @@ private:
|
|||||||
std::atomic<int> m_rendering_distance{24};
|
std::atomic<int> m_rendering_distance{24};
|
||||||
std::atomic<TickType> m_game_ticks{0};
|
std::atomic<TickType> m_game_ticks{0};
|
||||||
std::atomic<TickType> m_day_tick{6000};
|
std::atomic<TickType> m_day_tick{6000};
|
||||||
|
std::atomic<int> m_per_tick_time = DEFAULT_PER_TICK_TIME;
|
||||||
std::atomic<bool> m_requesting_chunk{false};
|
std::atomic<bool> m_requesting_chunk{false};
|
||||||
std::atomic<bool> m_is_rebuilding{false};
|
std::atomic<bool> m_is_rebuilding{false};
|
||||||
std::atomic<int> m_chunk_task_id{0};
|
std::atomic<int> m_chunk_task_id{0};
|
||||||
@@ -187,10 +169,6 @@ private:
|
|||||||
|
|
||||||
Random m_random;
|
Random m_random;
|
||||||
|
|
||||||
void client_run(std::stop_token token);
|
|
||||||
|
|
||||||
void report_player_info();
|
|
||||||
|
|
||||||
void set_block(const glm::ivec3& pos, unsigned id);
|
void set_block(const glm::ivec3& pos, unsigned id);
|
||||||
|
|
||||||
void update_chunk(const ChunkPosSet& old, const ChunkPosSet& now);
|
void update_chunk(const ChunkPosSet& old, const ChunkPosSet& now);
|
||||||
|
|||||||
13
include/Cubed/gameplay/creatures/pig.hpp
Normal file
13
include/Cubed/gameplay/creatures/pig.hpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Cubed {
|
||||||
|
struct PigTag {};
|
||||||
|
|
||||||
|
namespace PigDefaults {
|
||||||
|
constexpr float MAX_SPEED = 0.1f; // tiles/tick → 2 tiles/sec
|
||||||
|
constexpr float ACCELERATION = 0.01f; // ~10 ticks (0.5s) to reach full speed
|
||||||
|
constexpr float DECELERATION = 0.02f; // ~5 ticks (0.25s) to stop
|
||||||
|
constexpr float GRAVITY = 1.0f; // ≈20 tiles/s², close to the player
|
||||||
|
} // namespace PigDefaults
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
20
include/Cubed/gameplay/creatures/spawn.hpp
Normal file
20
include/Cubed/gameplay/creatures/spawn.hpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/biome.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <span>
|
||||||
|
#include <string_view>
|
||||||
|
namespace Cubed {
|
||||||
|
struct SpawnConfig {
|
||||||
|
std::string_view name; // factory key, e.g. "cubed:pig"
|
||||||
|
std::span<const BiomeType> biomes; // allowed biomes
|
||||||
|
float probability = 0.0f; // per chunk spawn probability
|
||||||
|
unsigned max_spawn_count = 0; // per chunk_max_spawn_sum
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace SpawnDefaults {
|
||||||
|
constexpr std::array<BiomeType, 2> PIG_BIOMES{BiomeType::PLAIN,
|
||||||
|
BiomeType::FOREST};
|
||||||
|
constexpr SpawnConfig PIG{"cubed:pig", PIG_BIOMES, 0.02f, 3};
|
||||||
|
} // namespace SpawnDefaults
|
||||||
|
} // namespace Cubed
|
||||||
17
include/Cubed/gameplay/ecs/ai_struct.hpp
Normal file
17
include/Cubed/gameplay/ecs/ai_struct.hpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Cubed/gameplay/game_time.hpp"
|
||||||
|
namespace Cubed {
|
||||||
|
struct AIBase {
|
||||||
|
TickType interval = 1;
|
||||||
|
TickType count = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WanderAITag {};
|
||||||
|
|
||||||
|
struct MoveBoost {
|
||||||
|
TickType duration = 0;
|
||||||
|
TickType count = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
14
include/Cubed/gameplay/ecs/animation.hpp
Normal file
14
include/Cubed/gameplay/ecs/animation.hpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Cubed/gameplay/player.hpp"
|
||||||
|
namespace Cubed {
|
||||||
|
|
||||||
|
struct WalkPose {
|
||||||
|
Gait gait = Gait::STOP;
|
||||||
|
// for arm roll caculate
|
||||||
|
float walk_time = 0.0f;
|
||||||
|
// for sound play
|
||||||
|
float moving_time = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
14
include/Cubed/gameplay/ecs/client_entity.hpp
Normal file
14
include/Cubed/gameplay/ecs/client_entity.hpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/ecs/animation.hpp"
|
||||||
|
#include "Cubed/gameplay/ecs/transform.hpp"
|
||||||
|
#include "Cubed/gameplay/model.hpp"
|
||||||
|
namespace Cubed {
|
||||||
|
struct BaseClientCreature {
|
||||||
|
|
||||||
|
Transform transform;
|
||||||
|
|
||||||
|
WalkPose pose;
|
||||||
|
|
||||||
|
ModelID model;
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
11
include/Cubed/gameplay/ecs/entity.hpp
Normal file
11
include/Cubed/gameplay/ecs/entity.hpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
namespace Cubed {
|
||||||
|
using EntityID = uint64_t;
|
||||||
|
|
||||||
|
struct Entity {
|
||||||
|
EntityID id;
|
||||||
|
explicit Entity(EntityID id) : id(id) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
10
include/Cubed/gameplay/ecs/health.hpp
Normal file
10
include/Cubed/gameplay/ecs/health.hpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Cubed {
|
||||||
|
|
||||||
|
struct Health {
|
||||||
|
float hp = 20;
|
||||||
|
float max_hp = 20;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
10
include/Cubed/gameplay/ecs/identity.hpp
Normal file
10
include/Cubed/gameplay/ecs/identity.hpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Cubed {
|
||||||
|
struct EntityInfo {
|
||||||
|
std::string name;
|
||||||
|
std::string uuid;
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
34
include/Cubed/gameplay/ecs/movement.hpp
Normal file
34
include/Cubed/gameplay/ecs/movement.hpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/constants.hpp"
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
namespace Cubed {
|
||||||
|
struct TickVelocity {
|
||||||
|
|
||||||
|
glm::vec3 value{0.0f};
|
||||||
|
// blocks/tick!!! -1 for in
|
||||||
|
glm::vec3 max{1.0f, -1.0f, 1.0f};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Velocity {
|
||||||
|
|
||||||
|
glm::vec3 value{0.0f};
|
||||||
|
// blocks/second!!!
|
||||||
|
glm::vec3 max{4.5f, 7.5f, 7.5f};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Movement {
|
||||||
|
|
||||||
|
float acceleration = DEFAULT_ACCELERATION;
|
||||||
|
|
||||||
|
float deceleration = DEFAULT_DECELERATION;
|
||||||
|
|
||||||
|
float jump_power = 7.5f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Gravity {
|
||||||
|
|
||||||
|
float value = DEFAULT_G;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
22
include/Cubed/gameplay/ecs/server_entity.hpp
Normal file
22
include/Cubed/gameplay/ecs/server_entity.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/ecs/health.hpp"
|
||||||
|
#include "Cubed/gameplay/ecs/movement.hpp"
|
||||||
|
#include "Cubed/gameplay/ecs/transform.hpp"
|
||||||
|
#include "Cubed/gameplay/hitbox.hpp"
|
||||||
|
namespace Cubed {
|
||||||
|
|
||||||
|
struct BaseServerCreature {
|
||||||
|
Transform transform{};
|
||||||
|
|
||||||
|
TickVelocity velocity{};
|
||||||
|
|
||||||
|
Movement movement{};
|
||||||
|
|
||||||
|
Gravity gravity{};
|
||||||
|
|
||||||
|
Health health{};
|
||||||
|
|
||||||
|
HitboxID hitbox{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
18
include/Cubed/gameplay/ecs/state.hpp
Normal file
18
include/Cubed/gameplay/ecs/state.hpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Cubed {
|
||||||
|
struct MoveState {
|
||||||
|
|
||||||
|
bool forward = false;
|
||||||
|
bool back = false;
|
||||||
|
bool left = false;
|
||||||
|
bool right = false;
|
||||||
|
|
||||||
|
bool down = false;
|
||||||
|
bool up = false;
|
||||||
|
|
||||||
|
bool is_fly = false;
|
||||||
|
bool can_up = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
30
include/Cubed/gameplay/ecs/transform.hpp
Normal file
30
include/Cubed/gameplay/ecs/transform.hpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
namespace Cubed {
|
||||||
|
struct Position {
|
||||||
|
glm::vec3 value{0.0f};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Orientation {
|
||||||
|
float yaw = 0.0f;
|
||||||
|
float pitch = 0.0f;
|
||||||
|
float roll = 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Direction {
|
||||||
|
glm::vec3 value{0.0f};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Transform {
|
||||||
|
Position position{};
|
||||||
|
Orientation orientation{};
|
||||||
|
Direction direction{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RenderTransform {
|
||||||
|
Position position{};
|
||||||
|
Orientation orientation{};
|
||||||
|
Direction direction{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
26
include/Cubed/gameplay/hitbox.hpp
Normal file
26
include/Cubed/gameplay/hitbox.hpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
namespace Cubed {
|
||||||
|
|
||||||
|
using HitboxID = uint32_t;
|
||||||
|
|
||||||
|
struct Hitbox {
|
||||||
|
glm::vec3 center{0.0f};
|
||||||
|
glm::vec3 half{0.0f};
|
||||||
|
|
||||||
|
Hitbox(glm::vec3 center_point, glm::vec3 half_size)
|
||||||
|
: center(center_point), half(half_size) {}
|
||||||
|
|
||||||
|
glm::vec3 min() const { return center - half; }
|
||||||
|
|
||||||
|
glm::vec3 max() const { return center + half; }
|
||||||
|
|
||||||
|
bool intersects(const Hitbox& other) const {
|
||||||
|
return (glm::abs(center.x - other.center.x) <= half.x + other.half.x) &&
|
||||||
|
(glm::abs(center.y - other.center.y) <= half.y + other.half.y) &&
|
||||||
|
(glm::abs(center.z - other.center.z) <= half.z + other.half.z);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
37
include/Cubed/gameplay/hitbox_manager.hpp
Normal file
37
include/Cubed/gameplay/hitbox_manager.hpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/hitbox.hpp"
|
||||||
|
|
||||||
|
#include <tbb/concurrent_hash_map.h>
|
||||||
|
namespace Cubed {
|
||||||
|
class HitboxManager {
|
||||||
|
public:
|
||||||
|
struct Handle {
|
||||||
|
Hitbox box;
|
||||||
|
HitboxID id = 0;
|
||||||
|
};
|
||||||
|
HitboxManager();
|
||||||
|
~HitboxManager();
|
||||||
|
static HitboxManager& instance();
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
Handle get_hitbox(const std::string& key);
|
||||||
|
[[nodiscard]]
|
||||||
|
Handle get_hitbox(HitboxID id);
|
||||||
|
[[nodiscard]]
|
||||||
|
static Handle hitbox(const std::string& name);
|
||||||
|
[[nodiscard]]
|
||||||
|
static Handle hitbox(HitboxID id);
|
||||||
|
HitboxID get_hitbox_id(const std::string& name);
|
||||||
|
const std::string& get_hitbox_name(HitboxID id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
using HitboxMap = tbb::concurrent_hash_map<HitboxID, Hitbox>;
|
||||||
|
using IDMap = tbb::concurrent_hash_map<std::string, HitboxID>;
|
||||||
|
using NameMap = tbb::concurrent_hash_map<HitboxID, std::string>;
|
||||||
|
HitboxID m_next = 0;
|
||||||
|
IDMap m_id_map;
|
||||||
|
NameMap m_name_map;
|
||||||
|
HitboxMap m_hitboxes;
|
||||||
|
Handle load(std::string_view name);
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
39
include/Cubed/gameplay/item.hpp
Normal file
39
include/Cubed/gameplay/item.hpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/block.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
namespace Cubed {
|
||||||
|
using ItemID = uint16_t;
|
||||||
|
|
||||||
|
enum class ItemKind {
|
||||||
|
NONE,
|
||||||
|
BLOCK,
|
||||||
|
SPAWN_EGG
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
using ItemProperty = std::variant<BlockType, std::string>;
|
||||||
|
|
||||||
|
struct ItemData {
|
||||||
|
ItemID id = 0;
|
||||||
|
std::string name;
|
||||||
|
std::string local_name;
|
||||||
|
std::string description;
|
||||||
|
std::string path;
|
||||||
|
ItemKind kind = ItemKind::NONE;
|
||||||
|
ItemProperty property;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr ItemKind get_item_kind(std::string_view kind) {
|
||||||
|
if (kind == "block") {
|
||||||
|
return ItemKind::BLOCK;
|
||||||
|
}
|
||||||
|
if (kind == "spawn_egg") {
|
||||||
|
return ItemKind::SPAWN_EGG;
|
||||||
|
}
|
||||||
|
return ItemKind::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
39
include/Cubed/gameplay/item_manager.hpp
Normal file
39
include/Cubed/gameplay/item_manager.hpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#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);
|
||||||
|
|
||||||
|
static ItemID size();
|
||||||
|
|
||||||
|
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, ItemID>;
|
||||||
|
using BlockToIDMap = tbb::concurrent_hash_map<BlockType, ItemID>;
|
||||||
|
void add(const std::filesystem::path& path);
|
||||||
|
|
||||||
|
ItemMap m_map;
|
||||||
|
|
||||||
|
IDMap m_id_map;
|
||||||
|
BlockToIDMap m_block_to_id_map;
|
||||||
|
|
||||||
|
static inline const ItemData EMPTY;
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Cubed/gameplay/block.hpp"
|
#include "Cubed/gameplay/item.hpp"
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
struct ItemStack {
|
struct ItemStack {
|
||||||
BlockType type = 0;
|
ItemID id = 0;
|
||||||
size_t sum = 0;
|
size_t sum = 0;
|
||||||
};
|
};
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
|
|||||||
162
include/Cubed/gameplay/local_player.hpp
Normal file
162
include/Cubed/gameplay/local_player.hpp
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/constants.hpp"
|
||||||
|
#include "Cubed/gameplay/block.hpp"
|
||||||
|
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||||
|
#include "Cubed/gameplay/ecs/animation.hpp"
|
||||||
|
#include "Cubed/gameplay/ecs/identity.hpp"
|
||||||
|
#include "Cubed/gameplay/ecs/movement.hpp"
|
||||||
|
#include "Cubed/gameplay/ecs/state.hpp"
|
||||||
|
#include "Cubed/gameplay/ecs/transform.hpp"
|
||||||
|
#include "Cubed/gameplay/game_mode.hpp"
|
||||||
|
#include "Cubed/gameplay/game_time.hpp"
|
||||||
|
#include "Cubed/gameplay/hitbox.hpp"
|
||||||
|
#include "Cubed/gameplay/item_stack.hpp"
|
||||||
|
#include "Cubed/gameplay/player.hpp"
|
||||||
|
#include "Cubed/input/event.hpp"
|
||||||
|
#include "Cubed/input/input.hpp"
|
||||||
|
|
||||||
|
#include <absl/container/flat_hash_set.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <optional>
|
||||||
|
#include <shared_mutex>
|
||||||
|
namespace Cubed {
|
||||||
|
|
||||||
|
class ClientWorld;
|
||||||
|
class LocalPlayer {
|
||||||
|
public:
|
||||||
|
static constexpr size_t HOTBAR_SUM = 10;
|
||||||
|
static constexpr float WALK_SOUND_INTERVAL = 0.45f;
|
||||||
|
static constexpr float RUN_SOUND_INTERVAL = 0.3f;
|
||||||
|
using ChunkPosSet = absl::flat_hash_set<ChunkPos, ChunkPos::Hash>;
|
||||||
|
LocalPlayer(ClientWorld& world);
|
||||||
|
~LocalPlayer();
|
||||||
|
|
||||||
|
bool handle_mouse_button_event(const MouseButtonEvent& e);
|
||||||
|
bool handle_key_event(const KeyEvent& e);
|
||||||
|
bool handle_mouse_wheel_event(const MouseWheelEvent& e);
|
||||||
|
|
||||||
|
void update_front_vec(float offset_x, float offset_y);
|
||||||
|
bool update_player_move_state(Key key, KeyAction action);
|
||||||
|
bool update_scroll(float yoffset);
|
||||||
|
|
||||||
|
void update_chunk_set(const ChunkPosSet& set);
|
||||||
|
|
||||||
|
const ChunkPosSet& get_chunk_pos_set() const;
|
||||||
|
ChunkPosSet get_chunk_pos_set();
|
||||||
|
|
||||||
|
const glm::vec3& get_front() const;
|
||||||
|
|
||||||
|
const std::optional<LookBlock>& get_look_block_pos() const;
|
||||||
|
// thread safe
|
||||||
|
glm::vec3 get_player_pos() const;
|
||||||
|
const MoveState& get_move_state() const;
|
||||||
|
|
||||||
|
void change_mode(GameMode mode);
|
||||||
|
void reload_config();
|
||||||
|
void set_player_pos(const glm::vec3& pos);
|
||||||
|
void update(float delta_time);
|
||||||
|
|
||||||
|
float& max_walk_speed();
|
||||||
|
float& max_run_speed();
|
||||||
|
float& fly_y_speed();
|
||||||
|
|
||||||
|
const ItemStack& get_current_itemstack() const;
|
||||||
|
|
||||||
|
GameMode& game_mode();
|
||||||
|
|
||||||
|
ClientWorld& get_world();
|
||||||
|
|
||||||
|
void set_uuid(std::string_view uuid);
|
||||||
|
std::string get_uuid() const;
|
||||||
|
const std::string& get_name() const;
|
||||||
|
void reset_input_status();
|
||||||
|
void init(std::string_view name);
|
||||||
|
|
||||||
|
bool ray_cast(const glm::vec3& start, const glm::vec3& dir,
|
||||||
|
glm::ivec3& block_pos, glm::vec3& normal,
|
||||||
|
float distance = 4.0f);
|
||||||
|
bool is_underwater() const;
|
||||||
|
void set_underwater(bool u);
|
||||||
|
void place_block(float dt);
|
||||||
|
|
||||||
|
int selected_hotbar() const;
|
||||||
|
void set_hotbar(int pos, const ItemStack& item);
|
||||||
|
std::span<const ItemStack, HOTBAR_SUM> get_hotbar() const;
|
||||||
|
|
||||||
|
glm::vec3& max_speed();
|
||||||
|
float& acceleration();
|
||||||
|
float& deceleration();
|
||||||
|
float& g();
|
||||||
|
void set_gait(Gait gait);
|
||||||
|
float yaw() const;
|
||||||
|
float pitch() const;
|
||||||
|
float& roll();
|
||||||
|
float& walk_time();
|
||||||
|
Gait get_gait() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using enum GameMode;
|
||||||
|
float m_max_walk_speed = DEFAULT_MAX_WALK_SPEED;
|
||||||
|
float m_max_run_speed = DEFAULT_MAX_RUN_SPEED;
|
||||||
|
float m_max_y_speed = 7.5f;
|
||||||
|
static constexpr float MAX_SPACE_ON_TIME = 0.3f;
|
||||||
|
static constexpr float PLACE_BLOCK_INTERVAL = 0.2f;
|
||||||
|
|
||||||
|
EntityInfo m_info;
|
||||||
|
Position m_pos;
|
||||||
|
WalkPose m_walk_pose;
|
||||||
|
Velocity m_velocity;
|
||||||
|
Orientation m_angle;
|
||||||
|
Movement m_movement;
|
||||||
|
Gravity m_gravity;
|
||||||
|
MoveState m_move_state;
|
||||||
|
Direction m_direction;
|
||||||
|
HitboxID m_hitbox = 0;
|
||||||
|
|
||||||
|
float m_place_time = PLACE_BLOCK_INTERVAL;
|
||||||
|
|
||||||
|
std::array<ItemStack, HOTBAR_SUM> m_hotbar;
|
||||||
|
float m_sensitivity = 0.15f;
|
||||||
|
|
||||||
|
float space_on_time = 0.0f;
|
||||||
|
bool space_on = false;
|
||||||
|
|
||||||
|
int m_selected_hotbar = 0;
|
||||||
|
|
||||||
|
bool m_moving = false;
|
||||||
|
bool m_sprinting = false;
|
||||||
|
bool m_underwater = false;
|
||||||
|
|
||||||
|
// player is tow block tall, the pos is the lower pos
|
||||||
|
ChunkPos m_last_chunk_pos{0, 0};
|
||||||
|
|
||||||
|
glm::vec3 m_front{0, 0, -1};
|
||||||
|
glm::vec3 m_right{0, 0, 0};
|
||||||
|
|
||||||
|
MouseState m_mouse_state{};
|
||||||
|
GameMode m_game_mode = CREATIVE;
|
||||||
|
std::optional<LookBlock> m_look_block = std::nullopt;
|
||||||
|
std::string m_name{};
|
||||||
|
mutable std::shared_mutex m_uuid_mutex;
|
||||||
|
std::string m_uuid;
|
||||||
|
ClientWorld& m_world;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, Timer> m_timers;
|
||||||
|
|
||||||
|
mutable std::shared_mutex m_player_pos_mutex;
|
||||||
|
mutable std::shared_mutex m_chunk_pos_mutex;
|
||||||
|
ChunkPosSet m_player_chunk_pos_set;
|
||||||
|
|
||||||
|
void update_direction();
|
||||||
|
void update_lookup_block();
|
||||||
|
void update_move(float dt);
|
||||||
|
void update_player_chunk();
|
||||||
|
|
||||||
|
void play_walk_sound(float dt);
|
||||||
|
Gait compute_gait() const;
|
||||||
|
|
||||||
|
void update_speed(float dt);
|
||||||
|
std::tuple<bool, bool, bool> update_physical(float dt, glm::vec3& pos);
|
||||||
|
glm::vec3 get_move_distance(float dt);
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
7
include/Cubed/gameplay/model.hpp
Normal file
7
include/Cubed/gameplay/model.hpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
using ModelID = uint32_t;
|
||||||
|
struct Model {
|
||||||
|
ModelID id;
|
||||||
|
};
|
||||||
@@ -14,8 +14,7 @@ public:
|
|||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
// Run in another thread after initialization is complete
|
// Run in another thread after initialization is complete
|
||||||
void start_server(int port);
|
void start_server(int port, RunMode mode);
|
||||||
void start_server();
|
|
||||||
int port() const;
|
int port() const;
|
||||||
ServerWorld& server_world();
|
ServerWorld& server_world();
|
||||||
|
|
||||||
|
|||||||
@@ -51,18 +51,27 @@ enum class PacketEnum : uint16_t {
|
|||||||
LOGIN_RSP = 1002,
|
LOGIN_RSP = 1002,
|
||||||
LOGOUT_REQ = 1003,
|
LOGOUT_REQ = 1003,
|
||||||
LOGOUT_RSP = 1004,
|
LOGOUT_RSP = 1004,
|
||||||
|
|
||||||
PLAYER_INFO = 2001,
|
PLAYER_INFO = 2001,
|
||||||
C2S_PLAYER_INFO = 2002,
|
C2S_PLAYER_INFO = 2002,
|
||||||
PLAYER_INFO_RSP = 2003,
|
PLAYER_INFO_RSP = 2003,
|
||||||
PLAYER_WATER_SOUND = 2004,
|
PLAYER_WATER_SOUND = 2004,
|
||||||
|
|
||||||
CHUNK_DATA_REQ = 3001,
|
CHUNK_DATA_REQ = 3001,
|
||||||
CHUNK_DATA_RSP = 3002,
|
CHUNK_DATA_RSP = 3002,
|
||||||
BLOCK_CHANGE_REQ = 3003,
|
BLOCK_CHANGE_REQ = 3003,
|
||||||
BLOCK_CHANGE_RSP = 3004,
|
BLOCK_CHANGE_RSP = 3004,
|
||||||
S2C_CLEAR_ALL_CHUNKS = 3005,
|
S2C_CLEAR_ALL_CHUNKS = 3005,
|
||||||
UPDATE_TIME = 3006,
|
UPDATE_TIME = 3006,
|
||||||
|
S2C_ENTITY_CREATE = 3007,
|
||||||
|
S2C_ENTITY_DESTORY = 3008,
|
||||||
|
C2S_ENTITY_CREATE_REQUEST = 3009,
|
||||||
|
C2S_ENTITY_DESTORY_REQUEST = 3010,
|
||||||
|
S2C_ENTITY_UPDATE = 3011,
|
||||||
|
|
||||||
CHAT_MSG = 4001,
|
CHAT_MSG = 4001,
|
||||||
VOICE_MSG = 4002,
|
VOICE_MSG = 4002,
|
||||||
|
|
||||||
PING = 9001,
|
PING = 9001,
|
||||||
PONG = 9002
|
PONG = 9002
|
||||||
|
|
||||||
@@ -111,6 +120,18 @@ template <> constexpr uint16_t get_packet_id<BlockChangeRsp>() {
|
|||||||
template <> constexpr uint16_t get_packet_id<S2C_ClearAllChunks>() {
|
template <> constexpr uint16_t get_packet_id<S2C_ClearAllChunks>() {
|
||||||
return std::to_underlying(PacketEnum::S2C_CLEAR_ALL_CHUNKS);
|
return std::to_underlying(PacketEnum::S2C_CLEAR_ALL_CHUNKS);
|
||||||
}
|
}
|
||||||
|
template <> constexpr uint16_t get_packet_id<S2CEntityCreate>() {
|
||||||
|
return std::to_underlying(PacketEnum::S2C_ENTITY_CREATE);
|
||||||
|
}
|
||||||
|
template <> constexpr uint16_t get_packet_id<S2CEntityDestory>() {
|
||||||
|
return std::to_underlying(PacketEnum::S2C_ENTITY_DESTORY);
|
||||||
|
}
|
||||||
|
template <> constexpr uint16_t get_packet_id<C2SEntityCreateRequest>() {
|
||||||
|
return std::to_underlying(PacketEnum::C2S_ENTITY_CREATE_REQUEST);
|
||||||
|
}
|
||||||
|
template <> constexpr uint16_t get_packet_id<C2SEntityDestoryRequest>() {
|
||||||
|
return std::to_underlying(PacketEnum::C2S_ENTITY_DESTORY_REQUEST);
|
||||||
|
}
|
||||||
template <> constexpr uint16_t get_packet_id<UpdateTime>() {
|
template <> constexpr uint16_t get_packet_id<UpdateTime>() {
|
||||||
return std::to_underlying(PacketEnum::UPDATE_TIME);
|
return std::to_underlying(PacketEnum::UPDATE_TIME);
|
||||||
}
|
}
|
||||||
@@ -129,6 +150,9 @@ template <> constexpr uint16_t get_packet_id<ChatMsg>() {
|
|||||||
template <> constexpr uint16_t get_packet_id<VoiceMsg>() {
|
template <> constexpr uint16_t get_packet_id<VoiceMsg>() {
|
||||||
return std::to_underlying(PacketEnum::VOICE_MSG);
|
return std::to_underlying(PacketEnum::VOICE_MSG);
|
||||||
}
|
}
|
||||||
|
template <> constexpr uint16_t get_packet_id<S2CEntityUpdate>() {
|
||||||
|
return std::to_underlying(PacketEnum::S2C_ENTITY_UPDATE);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
requires std::derived_from<T, google::protobuf::Message>
|
requires std::derived_from<T, google::protobuf::Message>
|
||||||
@@ -180,6 +204,12 @@ Packet make_packet(const T& msg) {
|
|||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires std::derived_from<T, google::protobuf::Message>
|
||||||
|
Packet make_packet(const T* msg) {
|
||||||
|
return make_packet(*msg);
|
||||||
|
}
|
||||||
|
|
||||||
inline PacketHeader decode_packet_header(std::span<const uint8_t> header) {
|
inline PacketHeader decode_packet_header(std::span<const uint8_t> header) {
|
||||||
if (header.size() < HEADER_LEN)
|
if (header.size() < HEADER_LEN)
|
||||||
throw std::runtime_error("Invalid header");
|
throw std::runtime_error("Invalid header");
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "glm/ext/vector_float3.hpp"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
@@ -17,5 +19,5 @@ inline Gait get_gait_from_id(int id) {
|
|||||||
throw std::runtime_error("Unknown Gait");
|
throw std::runtime_error("Unknown Gait");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static constexpr glm::vec3 PLAYER_SIZE{0.6f, 1.8f, 0.6f};
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "Cubed/constants.hpp"
|
#include "Cubed/constants.hpp"
|
||||||
#include "Cubed/gameplay/biome.hpp"
|
#include "Cubed/gameplay/biome.hpp"
|
||||||
#include "Cubed/gameplay/block.hpp"
|
#include "Cubed/gameplay/block.hpp"
|
||||||
|
#include "Cubed/gameplay/chunk.hpp"
|
||||||
#include "Cubed/gameplay/chunk_generator.hpp"
|
#include "Cubed/gameplay/chunk_generator.hpp"
|
||||||
#include "Cubed/gameplay/chunk_pos.hpp"
|
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
class ServerWorld;
|
class ServerWorld;
|
||||||
class ServerChunk {
|
class ServerChunk : public Chunk {
|
||||||
public:
|
public:
|
||||||
ServerChunk(ServerWorld& world, ChunkPos chunk_pos,
|
ServerChunk(ServerWorld& world, ChunkPos chunk_pos,
|
||||||
bool temp_chunk = false);
|
bool temp_chunk = false);
|
||||||
|
|||||||
65
include/Cubed/gameplay/server_entity_manager.hpp
Normal file
65
include/Cubed/gameplay/server_entity_manager.hpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/ecs/entity.hpp"
|
||||||
|
#include "glm/ext/vector_float3.hpp"
|
||||||
|
|
||||||
|
#include <entt/entt.hpp>
|
||||||
|
#include <tbb/concurrent_hash_map.h>
|
||||||
|
#include <tbb/concurrent_queue.h>
|
||||||
|
#include <tbb/concurrent_vector.h>
|
||||||
|
namespace Cubed {
|
||||||
|
class ServerWorld;
|
||||||
|
class Session;
|
||||||
|
class ServerEntityManager {
|
||||||
|
public:
|
||||||
|
ServerEntityManager(ServerWorld& world);
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void update();
|
||||||
|
// not thread safe
|
||||||
|
void add_entity(std::string_view name, const glm::vec3& world_pos);
|
||||||
|
void destory(EntityID id);
|
||||||
|
void handle_player_login(std::shared_ptr<Session> session);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class Command { CREATE, SEND_ALL_ENTITIES, DESTORY };
|
||||||
|
struct EntityCreateElement {
|
||||||
|
std::string name;
|
||||||
|
glm::vec3 pos;
|
||||||
|
};
|
||||||
|
using EntityMap = tbb::concurrent_hash_map<EntityID, entt::entity>;
|
||||||
|
using acc = EntityMap::accessor;
|
||||||
|
using cacc = EntityMap::const_accessor;
|
||||||
|
using CreateFunc = std::function<EntityID()>;
|
||||||
|
using TaskElement =
|
||||||
|
std::variant<std::shared_ptr<Session>, EntityCreateElement, EntityID>;
|
||||||
|
using TaskPair = std::pair<Command, TaskElement>;
|
||||||
|
ServerWorld& m_world;
|
||||||
|
tbb::concurrent_queue<TaskPair> m_tasks;
|
||||||
|
entt::registry m_registry;
|
||||||
|
EntityID m_next = 0;
|
||||||
|
EntityMap m_entities;
|
||||||
|
std::unordered_map<std::string_view, CreateFunc> m_factories;
|
||||||
|
void create_entity(std::string_view name, const glm::vec3& pos);
|
||||||
|
void handle_entity_create(EntityID id, std::string_view name,
|
||||||
|
const glm::vec3& pos);
|
||||||
|
void handle_entity_destory(EntityID id);
|
||||||
|
void handle_task();
|
||||||
|
void send_all_entities(std::shared_ptr<Session>& session);
|
||||||
|
void update_ai(entt::entity e);
|
||||||
|
void update_move(entt::entity e);
|
||||||
|
void
|
||||||
|
update_send(entt::entity e,
|
||||||
|
tbb::concurrent_vector<std::shared_ptr<Session>>& sessions);
|
||||||
|
template <typename... Args>
|
||||||
|
EntityID create_entity_in_factory(Args&&... args) {
|
||||||
|
auto entity = m_registry.create();
|
||||||
|
|
||||||
|
((m_registry.emplace<std::remove_cvref_t<Args>>(
|
||||||
|
entity, std::forward<Args>(args))),
|
||||||
|
...);
|
||||||
|
auto id = m_next++;
|
||||||
|
m_entities.emplace(id, entity);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
@@ -7,7 +7,9 @@
|
|||||||
#include "Cubed/gameplay/packet.hpp" // IWYU pragma: keep
|
#include "Cubed/gameplay/packet.hpp" // IWYU pragma: keep
|
||||||
#include "Cubed/gameplay/river_worm.hpp"
|
#include "Cubed/gameplay/river_worm.hpp"
|
||||||
#include "Cubed/gameplay/server_chunk.hpp"
|
#include "Cubed/gameplay/server_chunk.hpp"
|
||||||
|
#include "Cubed/gameplay/server_entity_manager.hpp"
|
||||||
#include "Cubed/gameplay/server_player.hpp"
|
#include "Cubed/gameplay/server_player.hpp"
|
||||||
|
#include "Cubed/gameplay/world.hpp"
|
||||||
#include "Cubed/tools/priority_thread_pool.hpp"
|
#include "Cubed/tools/priority_thread_pool.hpp"
|
||||||
#include "Cubed/tools/recent_queue.hpp"
|
#include "Cubed/tools/recent_queue.hpp"
|
||||||
#include "Cubed/tools/sensitive_filter.hpp"
|
#include "Cubed/tools/sensitive_filter.hpp"
|
||||||
@@ -20,19 +22,20 @@
|
|||||||
#include <tbb/concurrent_hash_map.h>
|
#include <tbb/concurrent_hash_map.h>
|
||||||
#include <tbb/concurrent_queue.h>
|
#include <tbb/concurrent_queue.h>
|
||||||
#include <tbb/concurrent_unordered_map.h>
|
#include <tbb/concurrent_unordered_map.h>
|
||||||
|
#include <tbb/concurrent_vector.h>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
class Session;
|
class Session;
|
||||||
class ServerWorld {
|
class ServerWorld : public World {
|
||||||
public:
|
public:
|
||||||
enum class ThreadPoolKind { NET, GEN };
|
enum class ThreadPoolKind { NET, GEN };
|
||||||
ServerWorld(Config& config);
|
ServerWorld(Config& config);
|
||||||
~ServerWorld();
|
~ServerWorld();
|
||||||
void stop();
|
void stop();
|
||||||
void handle_player_exit(const std::string& uuid);
|
void handle_player_exit(const std::string& uuid);
|
||||||
void init_world();
|
void init_world(RunMode mode);
|
||||||
void need_gen(std::string uuid);
|
void need_gen(std::string uuid);
|
||||||
void update();
|
void update();
|
||||||
void hot_reload();
|
void hot_reload();
|
||||||
@@ -84,7 +87,22 @@ public:
|
|||||||
|
|
||||||
void handle_chat_message(ChatMsg& msg);
|
void handle_chat_message(ChatMsg& msg);
|
||||||
void handle_voice_message(VoiceMsg& msg);
|
void handle_voice_message(VoiceMsg& msg);
|
||||||
|
|
||||||
|
void handle_entity_create(C2SEntityCreateRequest& req);
|
||||||
|
void handle_entity_destory(C2SEntityDestoryRequest& req);
|
||||||
|
|
||||||
int chunk_size() const;
|
int chunk_size() const;
|
||||||
|
|
||||||
|
tbb::concurrent_vector<std::shared_ptr<Session>> get_all_session() const;
|
||||||
|
|
||||||
|
uint32_t get_chunk_ref_count(const glm::vec3& pos) const;
|
||||||
|
ServerEntityManager& entity_manager();
|
||||||
|
std::shared_ptr<ThreadPool> get_compute_pool();
|
||||||
|
int get_block(const glm::ivec3& block_pos) const override;
|
||||||
|
bool is_solid(const glm::ivec3& block_pos) const override;
|
||||||
|
bool can_pass_block(const glm::ivec3& block_pos) const override;
|
||||||
|
BlockType get_block_tpye(const glm::ivec3& block_pos) const override;
|
||||||
|
int get_per_tick_time() const override;
|
||||||
template <typename Fn>
|
template <typename Fn>
|
||||||
void register_timer(std::string_view id, TickType threshold, Fn&& f) {
|
void register_timer(std::string_view id, TickType threshold, Fn&& f) {
|
||||||
m_timers.emplace(std::piecewise_construct,
|
m_timers.emplace(std::piecewise_construct,
|
||||||
@@ -97,7 +115,27 @@ private:
|
|||||||
struct ChunkEntity {
|
struct ChunkEntity {
|
||||||
ChunkState state;
|
ChunkState state;
|
||||||
std::shared_ptr<ServerChunk> chunk;
|
std::shared_ptr<ServerChunk> chunk;
|
||||||
uint32_t ref_count = 0;
|
std::atomic<uint32_t> ref_count = 0;
|
||||||
|
ChunkEntity() = default;
|
||||||
|
ChunkEntity(ChunkState s, std::shared_ptr<ServerChunk> c = {})
|
||||||
|
: state(s), chunk(std::move(c)) {}
|
||||||
|
|
||||||
|
ChunkEntity& operator=(ChunkEntity&& o) noexcept {
|
||||||
|
if (this == &o) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = std::exchange(o.state, ServerWorld::ChunkState::NONE);
|
||||||
|
chunk = std::move(o.chunk);
|
||||||
|
ref_count = o.ref_count.exchange(0);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChunkEntity(ChunkEntity&& o) noexcept
|
||||||
|
: state(std::exchange(o.state, ServerWorld::ChunkState::NONE)),
|
||||||
|
chunk(std::move(o.chunk)), ref_count(o.ref_count.exchange(0)) {}
|
||||||
|
ChunkEntity(const ChunkEntity&) = delete;
|
||||||
|
ChunkEntity& operator=(const ChunkEntity&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ChunkLoadStyle { RANDOM, CENTER };
|
enum class ChunkLoadStyle { RANDOM, CENTER };
|
||||||
@@ -119,13 +157,14 @@ private:
|
|||||||
using PlayerUUIDMap = tbb::concurrent_hash_map<std::string, std::string>;
|
using PlayerUUIDMap = tbb::concurrent_hash_map<std::string, std::string>;
|
||||||
|
|
||||||
using chunk_acc = ChunkHashMap::accessor;
|
using chunk_acc = ChunkHashMap::accessor;
|
||||||
using chunk_caac = ChunkHashMap::const_accessor;
|
using chunk_cacc = ChunkHashMap::const_accessor;
|
||||||
|
|
||||||
using uuid_acc = PlayerUUIDMap::accessor;
|
using uuid_acc = PlayerUUIDMap::accessor;
|
||||||
using uuid_cacc = PlayerUUIDMap::const_accessor;
|
using uuid_cacc = PlayerUUIDMap::const_accessor;
|
||||||
|
|
||||||
Config& m_config;
|
Config& m_config;
|
||||||
|
std::atomic<RunMode> m_runmode{RunMode::HYBRID};
|
||||||
|
ServerEntityManager m_entity_manager;
|
||||||
// key = uuid
|
// key = uuid
|
||||||
PlayerHashMap m_players;
|
PlayerHashMap m_players;
|
||||||
ChunkHashMap m_chunks;
|
ChunkHashMap m_chunks;
|
||||||
@@ -146,8 +185,9 @@ private:
|
|||||||
std::atomic<bool> m_init{false};
|
std::atomic<bool> m_init{false};
|
||||||
std::atomic<bool> m_stopped{false};
|
std::atomic<bool> m_stopped{false};
|
||||||
std::atomic<int> m_rendering_distance{24};
|
std::atomic<int> m_rendering_distance{24};
|
||||||
std::atomic<int> m_gen_pool_threads{0};
|
std::atomic<int> m_gen_threads{0};
|
||||||
std::atomic<int> m_net_pool_threads{0};
|
std::atomic<int> m_net_threads{0};
|
||||||
|
std::atomic<int> m_compute_threads{0};
|
||||||
std::atomic<int> m_max_threads{1};
|
std::atomic<int> m_max_threads{1};
|
||||||
std::atomic<size_t> m_player_sum{0};
|
std::atomic<size_t> m_player_sum{0};
|
||||||
std::atomic<TickType> m_game_ticks{0};
|
std::atomic<TickType> m_game_ticks{0};
|
||||||
@@ -155,7 +195,7 @@ private:
|
|||||||
std::atomic<bool> m_tick_running{true};
|
std::atomic<bool> m_tick_running{true};
|
||||||
std::atomic<int> m_per_tick_time = DEFAULT_PER_TICK_TIME; // ms
|
std::atomic<int> m_per_tick_time = DEFAULT_PER_TICK_TIME; // ms
|
||||||
|
|
||||||
mutable std::shared_mutex m_player_mutex;
|
mutable std::shared_mutex m_players_mutex;
|
||||||
std::mutex m_need_gen_queue_mutex;
|
std::mutex m_need_gen_queue_mutex;
|
||||||
std::condition_variable_any m_gen_cv;
|
std::condition_variable_any m_gen_cv;
|
||||||
|
|
||||||
@@ -163,6 +203,7 @@ private:
|
|||||||
|
|
||||||
std::atomic<std::shared_ptr<PriorityThreadPool>> m_gen_thread_pool;
|
std::atomic<std::shared_ptr<PriorityThreadPool>> m_gen_thread_pool;
|
||||||
std::atomic<std::shared_ptr<ThreadPool>> m_net_thread_pool;
|
std::atomic<std::shared_ptr<ThreadPool>> m_net_thread_pool;
|
||||||
|
std::atomic<std::shared_ptr<ThreadPool>> m_compute_thread_pool;
|
||||||
|
|
||||||
std::atomic<ChunkLoadStyle> m_chunk_load_style{ChunkLoadStyle::CENTER};
|
std::atomic<ChunkLoadStyle> m_chunk_load_style{ChunkLoadStyle::CENTER};
|
||||||
|
|
||||||
|
|||||||
16
include/Cubed/gameplay/systems/physical_system.hpp
Normal file
16
include/Cubed/gameplay/systems/physical_system.hpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/ecs/movement.hpp"
|
||||||
|
|
||||||
|
#include <entt/entt.hpp>
|
||||||
|
namespace Cubed {
|
||||||
|
class ServerWorld;
|
||||||
|
class PhysicalSystem {
|
||||||
|
public:
|
||||||
|
static glm::vec3 get_move_distance(const TickVelocity& v);
|
||||||
|
|
||||||
|
static void update(ServerWorld& world, entt::registry& registry,
|
||||||
|
entt::entity e);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
11
include/Cubed/gameplay/systems/speed_system.hpp
Normal file
11
include/Cubed/gameplay/systems/speed_system.hpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <entt/entt.hpp>
|
||||||
|
namespace Cubed {
|
||||||
|
class SpeedSystem {
|
||||||
|
public:
|
||||||
|
static void update(float dt, entt::registry& registry, entt::entity e);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
14
include/Cubed/gameplay/systems/wander_ai_system.hpp
Normal file
14
include/Cubed/gameplay/systems/wander_ai_system.hpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/ecs/ai_struct.hpp"
|
||||||
|
#include "Cubed/gameplay/ecs/server_entity.hpp"
|
||||||
|
|
||||||
|
#include <entt/entt.hpp>
|
||||||
|
namespace Cubed {
|
||||||
|
class WanderAISystem {
|
||||||
|
public:
|
||||||
|
static void update(entt::registry& registry, entt::entity e);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void do_ai(BaseServerCreature& creature, MoveBoost& move_boost);
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
32
include/Cubed/gameplay/world.hpp
Normal file
32
include/Cubed/gameplay/world.hpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/block.hpp"
|
||||||
|
#include "Cubed/gameplay/hitbox.hpp"
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
namespace Cubed {
|
||||||
|
class World {
|
||||||
|
public:
|
||||||
|
World() = default;
|
||||||
|
World(const World&) = delete;
|
||||||
|
World(World&&) = delete;
|
||||||
|
World& operator=(const World&) = delete;
|
||||||
|
World& operator=(World&&) = delete;
|
||||||
|
virtual ~World() = default;
|
||||||
|
|
||||||
|
virtual int get_block(const glm::ivec3& block_pos) const = 0;
|
||||||
|
virtual bool is_solid(const glm::ivec3& block_pos) const = 0;
|
||||||
|
virtual bool can_pass_block(const glm::ivec3& block_pos) const = 0;
|
||||||
|
virtual BlockType get_block_tpye(const glm::ivec3& block_pos) const = 0;
|
||||||
|
virtual int get_per_tick_time() const = 0;
|
||||||
|
|
||||||
|
static Hitbox get_block_aabb(const glm::ivec3& pos) {
|
||||||
|
return {glm::vec3{static_cast<float>(pos.x) + 0.5f,
|
||||||
|
static_cast<float>(pos.y) + 0.5f,
|
||||||
|
static_cast<float>(pos.z) + 0.5f},
|
||||||
|
glm::vec3{0.5f, 0.5f, 0.5f}};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class RunMode { CLIENT_ONLY, SERVER_ONLY, HYBRID };
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
@@ -2,15 +2,6 @@
|
|||||||
|
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
struct MoveState {
|
|
||||||
bool forward = false;
|
|
||||||
bool back = false;
|
|
||||||
bool left = false;
|
|
||||||
bool right = false;
|
|
||||||
bool down = false;
|
|
||||||
bool up = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MouseState {
|
struct MouseState {
|
||||||
bool left = false;
|
bool left = false;
|
||||||
bool right = false;
|
bool right = false;
|
||||||
|
|||||||
45
include/Cubed/render/model_manager.hpp
Normal file
45
include/Cubed/render/model_manager.hpp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/model.hpp"
|
||||||
|
#include "Cubed/render/model_node.hpp"
|
||||||
|
#include "Cubed/tools/model_loader.hpp"
|
||||||
|
|
||||||
|
#include <tbb/concurrent_hash_map.h>
|
||||||
|
namespace Cubed {
|
||||||
|
class ModelManager {
|
||||||
|
public:
|
||||||
|
struct Handle {
|
||||||
|
const ModelNode& node;
|
||||||
|
ModelID id = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ModelManager();
|
||||||
|
ModelManager(const ModelManager&) = delete;
|
||||||
|
ModelManager(ModelManager&&) = delete;
|
||||||
|
ModelManager& operator=(const ModelManager&) = delete;
|
||||||
|
ModelManager& operator=(ModelManager&&) = delete;
|
||||||
|
static ModelManager& instance();
|
||||||
|
~ModelManager();
|
||||||
|
[[nodiscard]]
|
||||||
|
Handle get_model(const std::string& model_name);
|
||||||
|
[[nodiscard]]
|
||||||
|
Handle get_model(ModelID id);
|
||||||
|
[[nodiscard]]
|
||||||
|
static Handle model(const std::string& model_name);
|
||||||
|
[[nodiscard]]
|
||||||
|
static Handle model(ModelID id);
|
||||||
|
ModelID get_model_id(const std::string& name);
|
||||||
|
const std::string& get_model_name(ModelID id);
|
||||||
|
void init();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ModelLoader m_loader;
|
||||||
|
ModelID m_next = 0;
|
||||||
|
using ModelMap = tbb::concurrent_hash_map<ModelID, ModelNode>;
|
||||||
|
using IDMap = tbb::concurrent_hash_map<std::string, ModelID>;
|
||||||
|
using NameMap = tbb::concurrent_hash_map<ModelID, std::string>;
|
||||||
|
ModelMap m_models;
|
||||||
|
IDMap m_id_map;
|
||||||
|
NameMap m_name_map;
|
||||||
|
Handle load_model(std::string_view model_name);
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
42
include/Cubed/render/model_node.hpp
Normal file
42
include/Cubed/render/model_node.hpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Cubed/primitive_data.hpp"
|
||||||
|
#include "Cubed/render/texture.hpp"
|
||||||
|
#include "Cubed/render/vertex_array.hpp"
|
||||||
|
#include "Cubed/render/vertex_buffer.hpp"
|
||||||
|
|
||||||
|
#include <glad/glad.h>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
namespace Cubed {
|
||||||
|
|
||||||
|
struct Mesh {
|
||||||
|
std::vector<Vertex3D> vertices;
|
||||||
|
std::vector<uint32_t> indices;
|
||||||
|
std::unique_ptr<VertexBuffer> vbo;
|
||||||
|
std::unique_ptr<VertexBuffer> ebo;
|
||||||
|
std::unique_ptr<VertexArray> vao;
|
||||||
|
std::unique_ptr<Texture> texture;
|
||||||
|
void upload() {
|
||||||
|
vao = std::make_unique<VertexArray>();
|
||||||
|
vao->bind();
|
||||||
|
vbo = std::make_unique<VertexBuffer>();
|
||||||
|
vbo->buffer_data(vertices.data(), vertices.size() * sizeof(Vertex3D));
|
||||||
|
ebo = std::make_unique<VertexBuffer>(BufferType::ELEMENT_ARRAY_BUFFER);
|
||||||
|
ebo->buffer_data(indices.data(), indices.size() * sizeof(uint32_t));
|
||||||
|
vao->attribute(0, 3, GL_FLOAT, sizeof(Vertex3D), (void*)0);
|
||||||
|
vao->attribute(1, 2, GL_FLOAT, sizeof(Vertex3D),
|
||||||
|
(void*)offsetof(Vertex3D, s));
|
||||||
|
vao->attribute(2, 3, GL_FLOAT, sizeof(Vertex3D),
|
||||||
|
(void*)offsetof(Vertex3D, nx));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
struct ModelNode {
|
||||||
|
std::string name;
|
||||||
|
glm::mat4 transform{1.0f};
|
||||||
|
std::vector<Mesh> meshes;
|
||||||
|
std::vector<ModelNode> children;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
26
include/Cubed/render/model_renderer.hpp
Normal file
26
include/Cubed/render/model_renderer.hpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Cubed/gameplay/model.hpp"
|
||||||
|
#include "Cubed/render/model_node.hpp"
|
||||||
|
#include "Cubed/shader.hpp"
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
namespace Cubed {
|
||||||
|
class Renderer;
|
||||||
|
class Camera;
|
||||||
|
class ModelRender {
|
||||||
|
public:
|
||||||
|
ModelRender(Renderer& renderer);
|
||||||
|
void render_model(ModelID id, const glm::vec3& pos, float yaw,
|
||||||
|
Camera& camera);
|
||||||
|
|
||||||
|
void shadow_pass(ModelID id, const glm::vec3& pos, float yaw,
|
||||||
|
Camera& camera);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Renderer& m_renderer;
|
||||||
|
void render_node(const ModelNode& node, const glm::mat4& parent,
|
||||||
|
const glm::mat4& view, const Shader& shader, bool shadow);
|
||||||
|
void render_mesh(const Mesh& mesh, bool shadow);
|
||||||
|
};
|
||||||
|
} // namespace Cubed
|
||||||
@@ -13,9 +13,7 @@ public:
|
|||||||
PlayerRenderer(Renderer& renderer);
|
PlayerRenderer(Renderer& renderer);
|
||||||
~PlayerRenderer();
|
~PlayerRenderer();
|
||||||
void init();
|
void init();
|
||||||
void render(const Shader& shader, ClientWorld& world);
|
void render(const Shader& shader, ClientWorld& world, bool shadow_render);
|
||||||
void shadow_render(const Shader& shader, glm::mat4& light_matrix,
|
|
||||||
ClientWorld& world);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct PlayerVertex {
|
struct PlayerVertex {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "Cubed/constants.hpp"
|
#include "Cubed/constants.hpp"
|
||||||
#include "Cubed/input/event.hpp"
|
#include "Cubed/input/event.hpp"
|
||||||
#include "Cubed/primitive_data.hpp"
|
#include "Cubed/primitive_data.hpp"
|
||||||
|
#include "Cubed/render/model_renderer.hpp"
|
||||||
#include "Cubed/render/player_renderer.hpp"
|
#include "Cubed/render/player_renderer.hpp"
|
||||||
#include "Cubed/render/shader_manager.hpp"
|
#include "Cubed/render/shader_manager.hpp"
|
||||||
#include "Cubed/render/vertex_array.hpp"
|
#include "Cubed/render/vertex_array.hpp"
|
||||||
@@ -19,6 +20,7 @@
|
|||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
class TextureManager;
|
class TextureManager;
|
||||||
class ClientWorld;
|
class ClientWorld;
|
||||||
|
class ModelManager;
|
||||||
class DevPanel;
|
class DevPanel;
|
||||||
class Renderer {
|
class Renderer {
|
||||||
public:
|
public:
|
||||||
@@ -79,9 +81,10 @@ public:
|
|||||||
|
|
||||||
bool handle_event(const Event& e);
|
bool handle_event(const Event& e);
|
||||||
|
|
||||||
|
ModelRender& model_renderer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TextureManager& m_texture_manager;
|
TextureManager& m_texture_manager;
|
||||||
|
|
||||||
bool m_init = false;
|
bool m_init = false;
|
||||||
|
|
||||||
float m_aspect = 0.0f;
|
float m_aspect = 0.0f;
|
||||||
@@ -118,6 +121,7 @@ private:
|
|||||||
std::vector<Vertex2D> m_ui;
|
std::vector<Vertex2D> m_ui;
|
||||||
|
|
||||||
WorldRenderer m_world_renderer;
|
WorldRenderer m_world_renderer;
|
||||||
|
ModelRender m_model_renderer;
|
||||||
Config& m_config;
|
Config& m_config;
|
||||||
|
|
||||||
bool handle_window_resize_event(const WindowResizeEvent& e);
|
bool handle_window_resize_event(const WindowResizeEvent& e);
|
||||||
|
|||||||
@@ -38,9 +38,11 @@ enum TextureFormat : GLenum {
|
|||||||
R8 = GL_R8,
|
R8 = GL_R8,
|
||||||
RGB = GL_RGB,
|
RGB = GL_RGB,
|
||||||
RGBA8 = GL_RGBA8,
|
RGBA8 = GL_RGBA8,
|
||||||
|
BGRA = GL_BGRA
|
||||||
|
|
||||||
};
|
};
|
||||||
|
// You need to set the texture scaling method, otherwise it will render as
|
||||||
|
// black.
|
||||||
class Texture {
|
class Texture {
|
||||||
public:
|
public:
|
||||||
explicit Texture(TextureType type);
|
explicit Texture(TextureType type);
|
||||||
|
|||||||
@@ -132,7 +132,8 @@ private:
|
|||||||
|
|
||||||
void render_underwater(ClientWorld& world);
|
void render_underwater(ClientWorld& world);
|
||||||
void render_outline(ClientWorld& world);
|
void render_outline(ClientWorld& world);
|
||||||
void render_player(ClientWorld& world);
|
void shadow_entity(ClientWorld& world, const glm::mat4& light_matrix);
|
||||||
|
void render_entity(ClientWorld& world);
|
||||||
|
|
||||||
void render_normal_block(const glm::mat4& model_mat,
|
void render_normal_block(const glm::mat4& model_mat,
|
||||||
const glm::mat4& mv_mat, const glm::mat4& norm_mat,
|
const glm::mat4& mv_mat, const glm::mat4& norm_mat,
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public:
|
|||||||
|
|
||||||
App& app();
|
App& app();
|
||||||
WorldSceneParam& world_scene_param();
|
WorldSceneParam& world_scene_param();
|
||||||
|
void push(SceneType type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class OperationType { PUSH, POP, CHANGE };
|
enum class OperationType { PUSH, POP, CHANGE };
|
||||||
@@ -51,7 +52,7 @@ private:
|
|||||||
std::stack<std::unique_ptr<Scene>> m_scenes;
|
std::stack<std::unique_ptr<Scene>> m_scenes;
|
||||||
void process_operation();
|
void process_operation();
|
||||||
void change(SceneType type);
|
void change(SceneType type);
|
||||||
void push(SceneType type);
|
|
||||||
void pop(bool re_enter = true);
|
void pop(bool re_enter = true);
|
||||||
|
|
||||||
std::unique_ptr<Scene> create_scene(SceneType);
|
std::unique_ptr<Scene> create_scene(SceneType);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Cubed/config.hpp"
|
#include "Cubed/config.hpp"
|
||||||
#include "Cubed/gameplay/block.hpp"
|
#include "Cubed/gameplay/block.hpp"
|
||||||
|
#include "Cubed/gameplay/item.hpp"
|
||||||
#include "Cubed/input/event.hpp"
|
#include "Cubed/input/event.hpp"
|
||||||
#include "Cubed/render/texture.hpp"
|
#include "Cubed/render/texture.hpp"
|
||||||
|
|
||||||
@@ -10,6 +11,26 @@
|
|||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
class TextureManager {
|
class TextureManager {
|
||||||
|
public:
|
||||||
|
using ItemTextureMap = std::unordered_map<ItemID, std::shared_ptr<Texture>>;
|
||||||
|
TextureManager(Config& config);
|
||||||
|
~TextureManager();
|
||||||
|
|
||||||
|
void delete_texture();
|
||||||
|
const Texture* get_block_status_array() const;
|
||||||
|
const Texture* get_texture_array() const;
|
||||||
|
const Texture* get_cross_plane_array() const;
|
||||||
|
const Texture* get_image_texture(const std::string& path);
|
||||||
|
const Texture* get_pbr_texture() const;
|
||||||
|
const ItemTextureMap& get_item_textures() const;
|
||||||
|
const Texture* get_skin() const;
|
||||||
|
void init_texture();
|
||||||
|
|
||||||
|
void need_reload();
|
||||||
|
void update();
|
||||||
|
int max_aniso() const;
|
||||||
|
bool handle_event(const Event& e);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_need_reload = false;
|
bool m_need_reload = false;
|
||||||
bool m_init = false;
|
bool m_init = false;
|
||||||
@@ -18,7 +39,7 @@ private:
|
|||||||
std::unique_ptr<Texture> m_cross_plane_array;
|
std::unique_ptr<Texture> m_cross_plane_array;
|
||||||
std::unique_ptr<Texture> m_normal_texture_array;
|
std::unique_ptr<Texture> m_normal_texture_array;
|
||||||
std::unique_ptr<Texture> m_skin;
|
std::unique_ptr<Texture> m_skin;
|
||||||
std::vector<std::unique_ptr<Texture>> m_item_textures;
|
ItemTextureMap m_item_textures;
|
||||||
std::unordered_map<std::string, std::unique_ptr<Texture>> m_ui_map;
|
std::unordered_map<std::string, std::unique_ptr<Texture>> m_ui_map;
|
||||||
GLfloat m_max_aniso = 0.0f;
|
GLfloat m_max_aniso = 0.0f;
|
||||||
Config& m_config;
|
Config& m_config;
|
||||||
@@ -26,7 +47,7 @@ private:
|
|||||||
|
|
||||||
void load_block_status(unsigned status_id);
|
void load_block_status(unsigned status_id);
|
||||||
void load_block_texture(unsigned block_id);
|
void load_block_texture(unsigned block_id);
|
||||||
void load_block_item_texture(unsigned id);
|
void init_item_texture();
|
||||||
void load_cross_plane_texture(unsigned id);
|
void load_cross_plane_texture(unsigned id);
|
||||||
const Texture* load_image_texture(const std::string& path);
|
const Texture* load_image_texture(const std::string& path);
|
||||||
void load_pbr_texture(unsigned id);
|
void load_pbr_texture(unsigned id);
|
||||||
@@ -37,25 +58,6 @@ private:
|
|||||||
void init_skin();
|
void init_skin();
|
||||||
void hot_reload();
|
void hot_reload();
|
||||||
bool handle_key_event(const KeyEvent& e);
|
bool handle_key_event(const KeyEvent& e);
|
||||||
|
|
||||||
public:
|
|
||||||
TextureManager(Config& config);
|
|
||||||
~TextureManager();
|
|
||||||
|
|
||||||
void delete_texture();
|
|
||||||
const Texture* get_block_status_array() const;
|
|
||||||
const Texture* get_texture_array() const;
|
|
||||||
const Texture* get_cross_plane_array() const;
|
|
||||||
const Texture* get_image_texture(const std::string& path);
|
|
||||||
const Texture* get_pbr_texture() const;
|
|
||||||
const std::vector<std::unique_ptr<Texture>>& get_item_textures() const;
|
|
||||||
const Texture* get_skin() const;
|
|
||||||
void init_texture();
|
|
||||||
|
|
||||||
void need_reload();
|
|
||||||
void update();
|
|
||||||
int max_aniso() const;
|
|
||||||
bool handle_event(const Event& e);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
7
include/Cubed/tools/cubed_concepts.hpp
Normal file
7
include/Cubed/tools/cubed_concepts.hpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
namespace Cubed {
|
||||||
|
template <typename T>
|
||||||
|
concept Ptr = std::is_pointer_v<T>;
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "glm/ext/vector_float3.hpp"
|
||||||
|
|
||||||
#include <random>
|
#include <random>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
|
|
||||||
@@ -14,6 +16,8 @@ public:
|
|||||||
int random_int(int min, int max);
|
int random_int(int min, int max);
|
||||||
float random_float(float min, float max);
|
float random_float(float min, float max);
|
||||||
|
|
||||||
|
glm::vec3 random_direction_horizontal();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int m_seed = 0;
|
unsigned int m_seed = 0;
|
||||||
std::mt19937 m_engine;
|
std::mt19937 m_engine;
|
||||||
|
|||||||
8
include/Cubed/tools/json_utils.hpp
Normal file
8
include/Cubed/tools/json_utils.hpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
#include <rapidjson/document.h>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
namespace Tools {
|
||||||
|
std::unordered_map<std::string, std::string>
|
||||||
|
doc_to_map(const rapidjson::Document& doc);
|
||||||
|
}
|
||||||
22
include/Cubed/tools/model_loader.hpp
Normal file
22
include/Cubed/tools/model_loader.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/render/model_node.hpp"
|
||||||
|
|
||||||
|
#include <assimp/Importer.hpp>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
namespace Cubed {
|
||||||
|
|
||||||
|
class ModelLoader {
|
||||||
|
public:
|
||||||
|
ModelLoader();
|
||||||
|
ModelNode load(const std::string& path);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Assimp::Importer m_importer;
|
||||||
|
ModelNode process_node(aiNode* node, const aiScene* scene);
|
||||||
|
Mesh process_mesh(aiMesh* mesh, const aiScene* scene);
|
||||||
|
bool process_texture(Mesh& mesh, aiMaterial* material, const aiScene* scene,
|
||||||
|
aiTextureType type);
|
||||||
|
glm::mat4 convert_matrix(const aiMatrix4x4& matrix);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
19
include/Cubed/tools/name_space.hpp
Normal file
19
include/Cubed/tools/name_space.hpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
namespace Cubed {
|
||||||
|
inline std::vector<std::string_view> parse_namespace(std::string_view str) {
|
||||||
|
std::vector<std::string_view> space;
|
||||||
|
space.reserve(4);
|
||||||
|
std::size_t p = str.find(':');
|
||||||
|
std::size_t start = 0;
|
||||||
|
while (p != std::string_view::npos) {
|
||||||
|
space.emplace_back(str.substr(start, p));
|
||||||
|
start = p + 1;
|
||||||
|
p = str.find(':', p + 1);
|
||||||
|
}
|
||||||
|
space.emplace_back(str.substr(start));
|
||||||
|
return space;
|
||||||
|
}
|
||||||
|
} // namespace Cubed
|
||||||
24
include/Cubed/tools/net_utils.hpp
Normal file
24
include/Cubed/tools/net_utils.hpp
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Cubed/tools/cubed_concepts.hpp"
|
||||||
|
#include "common/vector3.pb.h"
|
||||||
|
#include "glm/ext/vector_float3.hpp"
|
||||||
|
namespace Cubed {
|
||||||
|
namespace Tools {
|
||||||
|
inline void set_net_vec3(Vec3* p, const glm::vec3& pos) {
|
||||||
|
p->set_x(pos.x);
|
||||||
|
p->set_y(pos.y);
|
||||||
|
p->set_z(pos.z);
|
||||||
|
}
|
||||||
|
template <Ptr T> void set_net_pos(T ptr, const glm::vec3& pos) {
|
||||||
|
set_net_vec3(ptr->mutable_pos(), pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline glm::vec3 get_net_vec3(const Vec3* p) {
|
||||||
|
return glm::vec3{p->x(), p->y(), p->z()};
|
||||||
|
}
|
||||||
|
inline glm::vec3 get_net_vec3(const Vec3& p) {
|
||||||
|
return glm::vec3{p.x(), p.y(), p.z()};
|
||||||
|
}
|
||||||
|
} // namespace Tools
|
||||||
|
} // namespace Cubed
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <rapidjson/document.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
class SensitiveFilter {
|
class SensitiveFilter {
|
||||||
public:
|
public:
|
||||||
SensitiveFilter();
|
SensitiveFilter();
|
||||||
void load(const nlohmann::json& j);
|
void load(const rapidjson::Document& doc);
|
||||||
std::string filter(std::string_view text);
|
std::string filter(std::string_view text);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ bool check_opengl_error();
|
|||||||
std::string read_shader_source(const std::string& file_path);
|
std::string read_shader_source(const std::string& file_path);
|
||||||
|
|
||||||
ImageData load_image_data(const std::string& tex_image_path,
|
ImageData load_image_data(const std::string& tex_image_path,
|
||||||
bool check_exist = true);
|
bool check_exist = true, bool full_path = false);
|
||||||
|
|
||||||
} // namespace Tools
|
} // namespace Tools
|
||||||
|
|
||||||
|
|||||||
318
include/Cubed/tools/sparse_vector.hpp
Normal file
318
include/Cubed/tools/sparse_vector.hpp
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <iterator>
|
||||||
|
#include <optional>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
namespace Cubed {
|
||||||
|
template <typename T> class SparseVector {
|
||||||
|
private:
|
||||||
|
std::vector<std::optional<T>> m_data;
|
||||||
|
std::vector<uint32_t> m_free_list;
|
||||||
|
std::vector<uint32_t> m_generation;
|
||||||
|
|
||||||
|
std::vector<uint32_t> m_dense;
|
||||||
|
std::vector<uint32_t> m_dense_index;
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct Handle {
|
||||||
|
uint32_t index;
|
||||||
|
uint32_t generation;
|
||||||
|
|
||||||
|
uint64_t value() const noexcept {
|
||||||
|
return (uint64_t(index) << 32) | generation;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Handle&) const = default;
|
||||||
|
|
||||||
|
struct Hash {
|
||||||
|
size_t operator()(const Handle& h) const noexcept {
|
||||||
|
return h.value();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
using value_type = T;
|
||||||
|
using reference = T&;
|
||||||
|
using const_reference = const T&;
|
||||||
|
using pointer = T*;
|
||||||
|
|
||||||
|
using size_type = size_t;
|
||||||
|
|
||||||
|
class iterator { // NOLINT
|
||||||
|
private:
|
||||||
|
SparseVector* m_owner;
|
||||||
|
size_t m_index;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
|
using iterator_concept = std::random_access_iterator_tag;
|
||||||
|
using value_type = T;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using pointer = T*;
|
||||||
|
using reference = T&;
|
||||||
|
|
||||||
|
iterator(SparseVector* owner, size_t index)
|
||||||
|
: m_owner(owner), m_index(index) {}
|
||||||
|
|
||||||
|
reference operator*() {
|
||||||
|
return m_owner->m_data[m_owner->m_dense[m_index]].value();
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer operator->() { return &(**this); }
|
||||||
|
|
||||||
|
iterator& operator++() {
|
||||||
|
++m_index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator++(int) {
|
||||||
|
iterator tmp = *this;
|
||||||
|
++(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator& operator--() {
|
||||||
|
--m_index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator--(int) {
|
||||||
|
iterator tmp = *this;
|
||||||
|
--(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const iterator& other) const {
|
||||||
|
return m_owner == other.m_owner && m_index == other.m_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const iterator& other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator+(difference_type n) const {
|
||||||
|
return iterator(m_owner, m_index + n);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator-(difference_type n) const {
|
||||||
|
return iterator(m_owner, m_index - n);
|
||||||
|
}
|
||||||
|
|
||||||
|
difference_type operator-(const iterator& other) const {
|
||||||
|
return static_cast<difference_type>(m_index) -
|
||||||
|
static_cast<difference_type>(other.m_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator& operator+=(difference_type n) {
|
||||||
|
m_index += n;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator& operator-=(difference_type n) {
|
||||||
|
m_index -= n;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
reference operator[](difference_type n) const { return *(*this + n); }
|
||||||
|
|
||||||
|
bool operator<(const iterator& other) const {
|
||||||
|
return m_index < other.m_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>(const iterator& other) const {
|
||||||
|
return m_index > other.m_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<=(const iterator& other) const {
|
||||||
|
return m_index <= other.m_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>=(const iterator& other) const {
|
||||||
|
return m_index >= other.m_index;
|
||||||
|
}
|
||||||
|
friend iterator operator+(difference_type n, const iterator& it) {
|
||||||
|
return it + n;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class const_iterator { // NOLINT
|
||||||
|
private:
|
||||||
|
const SparseVector* m_owner;
|
||||||
|
size_t m_index;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
|
using iterator_concept = std::random_access_iterator_tag;
|
||||||
|
using value_type = T;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using pointer = const T*;
|
||||||
|
using reference = const T&;
|
||||||
|
|
||||||
|
const_iterator(const SparseVector* owner, size_t index)
|
||||||
|
: m_owner(owner), m_index(index) {}
|
||||||
|
|
||||||
|
reference operator*() const {
|
||||||
|
return m_owner->m_data[m_owner->m_dense[m_index]].value();
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer operator->() const { return &(**this); }
|
||||||
|
|
||||||
|
const_iterator& operator++() {
|
||||||
|
++m_index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator operator++(int) {
|
||||||
|
const_iterator tmp = *this;
|
||||||
|
++(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator& operator--() {
|
||||||
|
--m_index;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator operator--(int) {
|
||||||
|
const_iterator tmp = *this;
|
||||||
|
--(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const const_iterator& other) const {
|
||||||
|
return m_owner == other.m_owner && m_index == other.m_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const const_iterator& other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator operator+(difference_type n) const {
|
||||||
|
return const_iterator(m_owner, m_index + n);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator operator-(difference_type n) const {
|
||||||
|
return const_iterator(m_owner, m_index - n);
|
||||||
|
}
|
||||||
|
|
||||||
|
difference_type operator-(const const_iterator& other) const {
|
||||||
|
return static_cast<difference_type>(m_index) -
|
||||||
|
static_cast<difference_type>(other.m_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator& operator+=(difference_type n) {
|
||||||
|
m_index += n;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator& operator-=(difference_type n) {
|
||||||
|
m_index -= n;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
reference operator[](difference_type n) const { return *(*this + n); }
|
||||||
|
|
||||||
|
bool operator<(const const_iterator& other) const {
|
||||||
|
return m_index < other.m_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>(const const_iterator& other) const {
|
||||||
|
return m_index > other.m_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<=(const const_iterator& other) const {
|
||||||
|
return m_index <= other.m_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>=(const const_iterator& other) const {
|
||||||
|
return m_index >= other.m_index;
|
||||||
|
}
|
||||||
|
friend const_iterator operator+(difference_type n,
|
||||||
|
const const_iterator& it) {
|
||||||
|
return it + n;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class U> [[nodiscard]] Handle insert(U&& value) {
|
||||||
|
uint32_t id;
|
||||||
|
if (!m_free_list.empty()) {
|
||||||
|
id = m_free_list.back();
|
||||||
|
m_free_list.pop_back();
|
||||||
|
m_data[id].emplace(std::forward<U>(value));
|
||||||
|
|
||||||
|
m_dense_index[id] = m_dense.size();
|
||||||
|
} else {
|
||||||
|
id = m_data.size();
|
||||||
|
m_data.push_back(std::forward<U>(value));
|
||||||
|
m_generation.push_back(1);
|
||||||
|
m_dense_index.emplace_back(m_dense.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dense.push_back(id);
|
||||||
|
return {id, m_generation[id]};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args> Handle emplace(Args&&... args) {
|
||||||
|
return insert(T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase(Handle h) {
|
||||||
|
|
||||||
|
if (!exists(h)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t id = h.index;
|
||||||
|
m_free_list.push_back(id);
|
||||||
|
uint32_t index = m_dense_index[id];
|
||||||
|
uint32_t last_id = m_dense.back();
|
||||||
|
m_dense[index] = last_id;
|
||||||
|
m_dense_index[last_id] = index;
|
||||||
|
|
||||||
|
m_dense.pop_back();
|
||||||
|
m_data[id].reset();
|
||||||
|
++m_generation[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
T& operator[](Handle h) {
|
||||||
|
assert(exists(h));
|
||||||
|
return m_data[h.index].value();
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& operator[](Handle h) const {
|
||||||
|
assert(exists(h));
|
||||||
|
return m_data[h.index].value();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool exists(Handle h) const {
|
||||||
|
return h.index < m_generation.size() &&
|
||||||
|
m_generation[h.index] == h.generation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reserve(size_t n) {
|
||||||
|
m_data.reserve(n);
|
||||||
|
m_generation.reserve(n);
|
||||||
|
m_dense.reserve(n);
|
||||||
|
m_dense_index.reserve(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const { return m_dense.size(); }
|
||||||
|
|
||||||
|
bool empty() const { return m_dense.empty(); }
|
||||||
|
|
||||||
|
iterator begin() { return iterator(this, 0); }
|
||||||
|
|
||||||
|
iterator end() { return iterator(this, m_dense.size()); }
|
||||||
|
|
||||||
|
const_iterator begin() const { return const_iterator(this, 0); }
|
||||||
|
|
||||||
|
const_iterator end() const { return const_iterator(this, m_dense.size()); }
|
||||||
|
|
||||||
|
const_iterator cbegin() const { return begin(); }
|
||||||
|
|
||||||
|
const_iterator cend() const { return end(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Cubed
|
||||||
130
include/Cubed/tools/threas_utils.hpp
Normal file
130
include/Cubed/tools/threas_utils.hpp
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Cubed/gameplay/world.hpp"
|
||||||
|
#include "Cubed/tools/cubed_assert.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <thread>
|
||||||
|
namespace Cubed {
|
||||||
|
namespace Tools {
|
||||||
|
|
||||||
|
constexpr size_t SERVER_RESERVED_THREADS = 3; // tick + netio + gen scheduler
|
||||||
|
constexpr size_t CLIENT_RESERVED_THREADS =
|
||||||
|
3; // main/render + netio + system reserved
|
||||||
|
|
||||||
|
constexpr size_t safe_sub(size_t a, size_t b) { return a > b ? a - b : 0; }
|
||||||
|
|
||||||
|
inline size_t get_hardware_threads() {
|
||||||
|
auto hc = std::thread::hardware_concurrency();
|
||||||
|
return hc == 0 ? 4 : static_cast<size_t>(hc);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t get_server_available_threads() {
|
||||||
|
return std::max<size_t>(
|
||||||
|
1, safe_sub(get_hardware_threads(), SERVER_RESERVED_THREADS));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t get_client_available_threads() {
|
||||||
|
return std::max<size_t>(
|
||||||
|
1, safe_sub(get_hardware_threads(), CLIENT_RESERVED_THREADS));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t get_client_threads(RunMode mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case RunMode::SERVER_ONLY:
|
||||||
|
ASSERT_MSG(false, "Server Only don't need client pool");
|
||||||
|
return 1;
|
||||||
|
case RunMode::CLIENT_ONLY: {
|
||||||
|
auto available = get_client_available_threads();
|
||||||
|
return std::clamp<size_t>(available, 1, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
case RunMode::HYBRID: {
|
||||||
|
auto available = get_client_available_threads();
|
||||||
|
return std::clamp<size_t>(available / 2, 1, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t get_server_net_pool_threads(RunMode mode) {
|
||||||
|
switch (mode) {
|
||||||
|
|
||||||
|
case RunMode::SERVER_ONLY: {
|
||||||
|
auto available = get_server_available_threads();
|
||||||
|
return std::clamp<size_t>(available / 4, 1,
|
||||||
|
std::min<size_t>(4, available));
|
||||||
|
}
|
||||||
|
|
||||||
|
case RunMode::CLIENT_ONLY:
|
||||||
|
ASSERT_MSG(false, "Client Only don't need net pool");
|
||||||
|
return 1;
|
||||||
|
case RunMode::HYBRID: {
|
||||||
|
auto available = get_server_available_threads();
|
||||||
|
return std::clamp<size_t>(available / 8, 1,
|
||||||
|
std::min<size_t>(4, available));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t get_server_compute_treads(RunMode mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case RunMode::HYBRID:
|
||||||
|
case RunMode::SERVER_ONLY: {
|
||||||
|
auto available = get_server_available_threads();
|
||||||
|
|
||||||
|
return std::clamp<size_t>(available / 4, 1,
|
||||||
|
std::min<size_t>(4, available));
|
||||||
|
}
|
||||||
|
case RunMode::CLIENT_ONLY:
|
||||||
|
ASSERT_MSG(false, "Client Only don't need update pool");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t get_server_gen_threads(RunMode mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case RunMode::SERVER_ONLY: {
|
||||||
|
auto available = get_server_available_threads();
|
||||||
|
|
||||||
|
auto net_pool = get_server_net_pool_threads(mode);
|
||||||
|
|
||||||
|
auto update_pool = get_server_compute_treads(mode);
|
||||||
|
|
||||||
|
size_t remain = available;
|
||||||
|
|
||||||
|
remain -= std::min(remain, net_pool);
|
||||||
|
|
||||||
|
remain -= std::min(remain, update_pool);
|
||||||
|
|
||||||
|
return std::max<size_t>(1, remain);
|
||||||
|
}
|
||||||
|
case RunMode::CLIENT_ONLY:
|
||||||
|
ASSERT_MSG(false, "Client Only don't need gen pool");
|
||||||
|
return 1;
|
||||||
|
case RunMode::HYBRID: {
|
||||||
|
auto available = get_server_available_threads();
|
||||||
|
|
||||||
|
auto net_pool = get_server_net_pool_threads(mode);
|
||||||
|
|
||||||
|
auto update_pool = get_server_compute_treads(mode);
|
||||||
|
|
||||||
|
auto client_pool = get_client_threads(mode);
|
||||||
|
|
||||||
|
size_t remain = available;
|
||||||
|
|
||||||
|
remain -= std::min(remain, net_pool);
|
||||||
|
|
||||||
|
remain -= std::min(remain, update_pool);
|
||||||
|
|
||||||
|
remain -= std::min(remain, client_pool);
|
||||||
|
|
||||||
|
return std::max<size_t>(1, remain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Tools
|
||||||
|
} // namespace Cubed
|
||||||
@@ -20,7 +20,7 @@ private:
|
|||||||
Label* m_item_info = nullptr;
|
Label* m_item_info = nullptr;
|
||||||
|
|
||||||
Image* m_selected_image = nullptr;
|
Image* m_selected_image = nullptr;
|
||||||
BlockType m_selected_block = 0;
|
BlockType m_selected_id = 0;
|
||||||
void update_item_info();
|
void update_item_info();
|
||||||
bool handle_mouse_button_event(const MouseButtonEvent& e) override;
|
bool handle_mouse_button_event(const MouseButtonEvent& e) override;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Cubed/gameplay/block.hpp"
|
#include "Cubed/gameplay/item.hpp"
|
||||||
#include "Cubed/ui/image.hpp"
|
#include "Cubed/ui/image.hpp"
|
||||||
#include "Cubed/ui/widget.hpp"
|
#include "Cubed/ui/widget.hpp"
|
||||||
namespace Cubed {
|
namespace Cubed {
|
||||||
@@ -13,11 +13,11 @@ public:
|
|||||||
|
|
||||||
ItemSlot& set_default_background(TextureManager& m_texture_manager);
|
ItemSlot& set_default_background(TextureManager& m_texture_manager);
|
||||||
ItemSlot& set_scale(float m_scale);
|
ItemSlot& set_scale(float m_scale);
|
||||||
ItemSlot& set_item(BlockType id, const Texture* texture);
|
ItemSlot& set_item(ItemID id, const Texture* texture);
|
||||||
float width() const override;
|
float width() const override;
|
||||||
float height() const override;
|
float height() const override;
|
||||||
bool handle_mouse_move_event(const MouseMoveEvent& e) override;
|
bool handle_mouse_move_event(const MouseMoveEvent& e) override;
|
||||||
BlockType block() const;
|
ItemID id() const;
|
||||||
bool hovered() const;
|
bool hovered() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -26,7 +26,7 @@ private:
|
|||||||
void on_update(float dt) override;
|
void on_update(float dt) override;
|
||||||
std::unique_ptr<Image> m_background;
|
std::unique_ptr<Image> m_background;
|
||||||
std::unique_ptr<Image> m_foreground;
|
std::unique_ptr<Image> m_foreground;
|
||||||
BlockType m_block_type;
|
ItemID m_id;
|
||||||
float m_scale = 1.0f;
|
float m_scale = 1.0f;
|
||||||
bool m_hovered = false;
|
bool m_hovered = false;
|
||||||
};
|
};
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user