mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
Compare commits
2 Commits
322fb2fea0
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1baa2d6672 | ||
|
|
236e7c0433 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,6 +14,7 @@
|
||||
*.pch
|
||||
*.sbr
|
||||
build/
|
||||
build_debug/
|
||||
Build/
|
||||
bin/
|
||||
Debug/
|
||||
|
||||
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
|
||||
harfbuzz::harfbuzz
|
||||
Opus::Opus
|
||||
assimp::assimp
|
||||
$<$<PLATFORM_ID:Windows>:ws2_32>
|
||||
|
||||
)
|
||||
|
||||
@@ -8,5 +8,4 @@ is_passable = true
|
||||
is_transitional = false
|
||||
is_transparent = true
|
||||
name = 'air'
|
||||
name_key = 'block.air'
|
||||
roughness = 1.0
|
||||
@@ -8,5 +8,4 @@ is_passable = false
|
||||
is_transitional = true
|
||||
is_transparent = false
|
||||
name = 'dirt'
|
||||
name_key = 'block.dirt'
|
||||
roughness = 1.0
|
||||
@@ -8,5 +8,4 @@ is_passable = true
|
||||
is_transitional = false
|
||||
is_transparent = true
|
||||
name = 'grass'
|
||||
name_key = 'block.grass'
|
||||
roughness = 0.90000000000000002
|
||||
@@ -8,5 +8,4 @@ is_passable = false
|
||||
is_transitional = true
|
||||
is_transparent = false
|
||||
name = 'grass_block'
|
||||
name_key = 'block.grass_block'
|
||||
roughness = 0.90000000000000002
|
||||
@@ -8,5 +8,4 @@ is_passable = false
|
||||
is_transitional = false
|
||||
is_transparent = true
|
||||
name = 'leaf'
|
||||
name_key = 'block.leaf'
|
||||
roughness = 0.69999999999999996
|
||||
@@ -8,5 +8,4 @@ is_passable = false
|
||||
is_transitional = false
|
||||
is_transparent = false
|
||||
name = 'log'
|
||||
name_key = 'block.log'
|
||||
roughness = 0.69999999999999996
|
||||
@@ -8,5 +8,4 @@ is_passable = false
|
||||
is_transitional = true
|
||||
is_transparent = false
|
||||
name = 'sand'
|
||||
name_key = 'block.sand'
|
||||
roughness = 0.80000000000000004
|
||||
@@ -8,5 +8,4 @@ is_passable = false
|
||||
is_transitional = true
|
||||
is_transparent = false
|
||||
name = 'snowy_grass_block'
|
||||
name_key = 'block.snowy_grass_block'
|
||||
roughness = 0.90000000000000002
|
||||
@@ -8,5 +8,4 @@ is_passable = false
|
||||
is_transitional = true
|
||||
is_transparent = false
|
||||
name = 'stone'
|
||||
name_key = 'block.stone'
|
||||
roughness = 0.75
|
||||
@@ -9,4 +9,3 @@ is_discard = false
|
||||
is_blend = false
|
||||
is_transitional = false
|
||||
roughness = 1.0
|
||||
name_key = "block.template"
|
||||
|
||||
@@ -8,5 +8,4 @@ is_passable = true
|
||||
is_transitional = false
|
||||
is_transparent = true
|
||||
name = 'water'
|
||||
name_key = 'block.water'
|
||||
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"
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
"menu.main.join_game": "Join Game",
|
||||
"menu.main.credits": "Credits",
|
||||
"menu.main.quit": "Quit",
|
||||
"menu.screenshot": "Screenshots",
|
||||
"menu.main.player_name": "Player: {name}",
|
||||
"menu.main.cubed_version": "Cubed: {version}",
|
||||
"menu.pause.pause_menu": "Pause Menu",
|
||||
@@ -36,14 +37,20 @@
|
||||
"joingame.server_ip": "Server Ip",
|
||||
"joingame.join_world": "Join World",
|
||||
"error.disable_voice": "Server Disable Voice Chat",
|
||||
"block.air": "air",
|
||||
"block.dirt": "dirt",
|
||||
"block.grass_block": "grass block",
|
||||
"block.grass": "grass",
|
||||
"block.leaf": "leaf",
|
||||
"block.log": "log",
|
||||
"block.sand": "sand",
|
||||
"block.snowy_grass_block": "snowy grass block",
|
||||
"block.stone": "stone",
|
||||
"block.water": "water"
|
||||
"item.air.name": "air",
|
||||
"item.dirt.name": "dirt",
|
||||
"item.grass_block.name": "grass block",
|
||||
"item.grass.name": "grass",
|
||||
"item.leaf.name": "leaf",
|
||||
"item.log.name": "log",
|
||||
"item.sand.name": "sand",
|
||||
"item.snowy_grass_block.name": "snowy grass block",
|
||||
"item.stone.name": "stone",
|
||||
"item.water.name": "water",
|
||||
"item.pig_spawn_egg.name": "pig spawn egg",
|
||||
"screenshot.no_screenshot": "No Screenshot",
|
||||
"button.show_in_file_manager": "Show In File Manager",
|
||||
"file.sort_type": "File Sort Type: {type}",
|
||||
"file.newest_first": "Newest First",
|
||||
"file.oldest_first": "Oldest First"
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
"menu.main.join_game": "加入游戏",
|
||||
"menu.main.credits": "制作人员",
|
||||
"menu.main.quit": "退出",
|
||||
"menu.screenshot": "屏幕截图",
|
||||
"menu.main.player_name": "玩家:{name}",
|
||||
"menu.main.cubed_version": "Cubed:{version}",
|
||||
"menu.pause.pause_menu": "暂停菜单",
|
||||
@@ -36,14 +37,20 @@
|
||||
"joingame.server_ip": "服务器IP",
|
||||
"joingame.join_world": "加入世界",
|
||||
"error.disable_voice": "服务器已禁用语音聊天",
|
||||
"block.air": "空气",
|
||||
"block.dirt": "泥土",
|
||||
"block.grass_block": "草方块",
|
||||
"block.grass": "草",
|
||||
"block.leaf": "树叶",
|
||||
"block.log": "原木",
|
||||
"block.sand": "沙子",
|
||||
"block.snowy_grass_block": "覆雪草方块",
|
||||
"block.stone": "石头",
|
||||
"block.water": "水"
|
||||
"item.air.name": "空气",
|
||||
"item.dirt.name": "泥土",
|
||||
"item.grass_block.name": "草方块",
|
||||
"item.grass.name": "草",
|
||||
"item.leaf.name": "树叶",
|
||||
"item.log.name": "原木",
|
||||
"item.sand.name": "沙子",
|
||||
"item.snowy_grass_block.name": "覆雪草方块",
|
||||
"item.stone.name": "石头",
|
||||
"item.water.name": "水",
|
||||
"item.pig_spawn_egg.name": "猪猪刷怪蛋",
|
||||
"screenshot.no_screenshot": "没有截图",
|
||||
"button.show_in_file_manager": "在文件管理器中显示",
|
||||
"file.sort_type": "文件排序方式:{type}",
|
||||
"file.newest_first": "最新在前",
|
||||
"file.oldest_first": "最旧在前"
|
||||
}
|
||||
33
assets/model/creature/pig/animation.json
Normal file
33
assets/model/creature/pig/animation.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"walk": {
|
||||
"speed": 6.0,
|
||||
"amplitude": 25.0
|
||||
},
|
||||
"run": {
|
||||
"speed": 12.0,
|
||||
"amplitude": 40.0
|
||||
},
|
||||
"body_bob": 0.03,
|
||||
"head": {
|
||||
"node": "Head",
|
||||
"amplitude": 4.0
|
||||
},
|
||||
"legs": [
|
||||
{
|
||||
"node": "Foot_FL",
|
||||
"phase": 0.0
|
||||
},
|
||||
{
|
||||
"node": "Foot_FR",
|
||||
"phase": 3.14159
|
||||
},
|
||||
{
|
||||
"node": "Foot_HL",
|
||||
"phase": 3.14159
|
||||
},
|
||||
{
|
||||
"node": "Foot_HR",
|
||||
"phase": 0.0
|
||||
}
|
||||
]
|
||||
}
|
||||
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.
16
assets/model/creature/player/collision.json
Normal file
16
assets/model/creature/player/collision.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"boxes": [
|
||||
{
|
||||
"center": [
|
||||
0,
|
||||
0.9,
|
||||
0
|
||||
],
|
||||
"half": [
|
||||
0.3,
|
||||
0.9,
|
||||
0.3
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
assets/model/creature/player/player.glb
Normal file
BIN
assets/model/creature/player/player.glb
Normal file
Binary file not shown.
13
assets/shaders/depth_model_instance_vert.glsl
Normal file
13
assets/shaders/depth_model_instance_vert.glsl
Normal file
@@ -0,0 +1,13 @@
|
||||
#version 460
|
||||
|
||||
layout (location = 0) in vec3 pos;
|
||||
layout (location = 1) in vec2 texCoord;
|
||||
layout (location = 3) in mat4 modelMatrix;
|
||||
uniform mat4 lightSpaceMatrix;
|
||||
|
||||
out vec2 tc;
|
||||
|
||||
void main() {
|
||||
tc = texCoord;
|
||||
gl_Position = lightSpaceMatrix * modelMatrix * vec4(pos, 1.0);
|
||||
}
|
||||
@@ -7,7 +7,6 @@ uniform mat4 lightSpaceMatrix;
|
||||
uniform mat4 modelMatrix;
|
||||
|
||||
out vec2 tc;
|
||||
flat out int tex_layer;
|
||||
|
||||
void main() {
|
||||
tc = texCoord;
|
||||
14
assets/shaders/depth_model_vert.glsl
Normal file
14
assets/shaders/depth_model_vert.glsl
Normal file
@@ -0,0 +1,14 @@
|
||||
#version 460
|
||||
|
||||
layout (location = 0) in vec3 pos;
|
||||
layout (location = 1) in vec2 texCoord;
|
||||
|
||||
uniform mat4 lightSpaceMatrix;
|
||||
uniform mat4 modelMatrix;
|
||||
|
||||
out vec2 tc;
|
||||
|
||||
void main() {
|
||||
tc = texCoord;
|
||||
gl_Position = lightSpaceMatrix * modelMatrix * vec4(pos, 1.0);
|
||||
}
|
||||
26
assets/shaders/model_instance_vert.glsl
Normal file
26
assets/shaders/model_instance_vert.glsl
Normal file
@@ -0,0 +1,26 @@
|
||||
#version 460
|
||||
|
||||
layout (location = 0) in vec3 pos;
|
||||
layout (location = 1) in vec2 texCoord;
|
||||
layout (location = 2) in vec3 aNormal;
|
||||
layout (location = 3) in mat4 modelMatrix;
|
||||
uniform mat4 view_matrix;
|
||||
uniform mat4 proj_matrix;
|
||||
uniform mat4 lightSpaceMatrix;
|
||||
out vec4 FragPosLightSpace;
|
||||
out vec3 normal;
|
||||
out vec2 tc;
|
||||
out vec3 vert_pos;
|
||||
|
||||
|
||||
void main() {
|
||||
vec4 worldPos = modelMatrix * vec4(pos, 1.0);
|
||||
FragPosLightSpace = lightSpaceMatrix * worldPos;
|
||||
mat4 mv_matrix= view_matrix * modelMatrix;
|
||||
mat4 norm_matrix = transpose(inverse(mv_matrix));
|
||||
vec4 viewPos = mv_matrix * vec4(pos, 1.0);
|
||||
tc = texCoord;
|
||||
vert_pos = pos;
|
||||
normal = normalize(mat3(norm_matrix) * aNormal);
|
||||
gl_Position = proj_matrix * viewPos;
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
layout (location = 0) in vec3 pos;
|
||||
layout (location = 1) in vec2 texCoord;
|
||||
layout (location = 2) in vec3 aNormal;
|
||||
layout (location = 3) in vec3 aTangent;
|
||||
|
||||
uniform mat4 mv_matrix;
|
||||
uniform mat4 proj_matrix;
|
||||
BIN
assets/sound/creature/pig/call.mp3
Normal file
BIN
assets/sound/creature/pig/call.mp3
Normal file
Binary file not shown.
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(SDL3 REQUIRED)
|
||||
find_package(Opus REQUIRED)
|
||||
|
||||
find_package(assimp REQUIRED)
|
||||
# Third-party libraries
|
||||
|
||||
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;
|
||||
|
||||
TextureManager m_texture_manager;
|
||||
|
||||
AudioEngine m_audio;
|
||||
|
||||
Renderer m_renderer;
|
||||
|
||||
@@ -13,5 +13,6 @@ struct Argument {
|
||||
std::optional<int> log_level;
|
||||
std::optional<bool> enable_filelog;
|
||||
std::optional<bool> enable_consolelog;
|
||||
std::optional<bool> direct_enter;
|
||||
};
|
||||
} // namespace Cubed
|
||||
@@ -62,7 +62,7 @@ private:
|
||||
OpusDecoder* m_decoder{nullptr};
|
||||
AudioRecording m_recording;
|
||||
std::weak_ptr<NetworkClient> m_client;
|
||||
glm::vec3 listener_pos;
|
||||
glm::vec3 listener_pos{0.0f};
|
||||
std::unique_ptr<AudioSource> m_bgm;
|
||||
FadeMap m_fade_map;
|
||||
SoundManager m_sounds;
|
||||
|
||||
@@ -49,6 +49,6 @@ private:
|
||||
ALuint m_source = 0;
|
||||
float m_target_volume = 1.0f;
|
||||
float m_duration = 0.0f;
|
||||
bool m_using;
|
||||
bool m_using = false;
|
||||
};
|
||||
} // namespace Cubed
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace Cubed {
|
||||
|
||||
class ClientPlayer;
|
||||
class LocalPlayer;
|
||||
|
||||
class Camera {
|
||||
private:
|
||||
@@ -18,12 +18,12 @@ private:
|
||||
THIRD_PERSON_FRONT,
|
||||
};
|
||||
|
||||
ClientPlayer* m_player;
|
||||
float m_last_mouse_x, m_last_mouse_y;
|
||||
glm::vec3 m_camera_pos;
|
||||
LocalPlayer* m_player = nullptr;
|
||||
float m_last_mouse_x = 0.0f, m_last_mouse_y = 0.0f;
|
||||
glm::vec3 m_camera_pos{0.0f};
|
||||
bool m_under_water = false;
|
||||
Perspective m_perspective = Perspective::FIRST_PERSON;
|
||||
glm::vec3 m_front;
|
||||
glm::vec3 m_front{0.0f};
|
||||
glm::vec3 camera_collision(glm::vec3 start, glm::vec3 end,
|
||||
float radius = 0.2f);
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
|
||||
void update_move_camera();
|
||||
|
||||
void camera_init(ClientPlayer* player);
|
||||
void camera_init(LocalPlayer* player);
|
||||
void hot_reload();
|
||||
void update_cursor_position_camera(float offset_x, float offset_y);
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
void change_perspective();
|
||||
bool is_first_person() const;
|
||||
bool handle_event(const Event& e);
|
||||
ClientPlayer* player();
|
||||
LocalPlayer* player();
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
namespace Cubed {
|
||||
|
||||
class WorldScene;
|
||||
class ClientPlayer;
|
||||
class LocalPlayer;
|
||||
class App;
|
||||
class DevPanel {
|
||||
struct ConfigView {
|
||||
@@ -42,7 +42,7 @@ private:
|
||||
WorldScene& m_world_scene;
|
||||
Config& m_config;
|
||||
ConfigView m_config_view;
|
||||
ClientPlayer* m_player;
|
||||
LocalPlayer* m_player = nullptr;
|
||||
PlayerProfile m_player_profile;
|
||||
bool m_need_save_config = false;
|
||||
bool m_gen_thread_running = true;
|
||||
|
||||
@@ -22,7 +22,7 @@ struct Block : public BlockTexture {};
|
||||
|
||||
struct BlockRenderData {
|
||||
std::vector<bool> draw_face;
|
||||
unsigned block_id;
|
||||
unsigned block_id = 0;
|
||||
BlockRenderData() = default;
|
||||
BlockRenderData(const BlockRenderData&) = default;
|
||||
BlockRenderData& operator=(const BlockRenderData&) = default;
|
||||
@@ -42,7 +42,6 @@ struct LookBlock {
|
||||
|
||||
struct BlockData {
|
||||
std::string name;
|
||||
std::string name_key;
|
||||
BlockType id = 0;
|
||||
|
||||
bool is_liquid = false;
|
||||
@@ -56,42 +55,14 @@ struct BlockData {
|
||||
bool is_blend = false;
|
||||
bool is_transitional = false;
|
||||
float roughness = 1.0f;
|
||||
BlockData(std::string_view b_name, std::string_view name_k, BlockType b_id,
|
||||
bool liquid, bool passable, bool cross_plane, bool transparent,
|
||||
bool gas, bool discard, bool blend, bool transitional, float r)
|
||||
: name(b_name), name_key(name_k), id(b_id), is_liquid(liquid),
|
||||
is_gas(gas), is_passable(passable), is_cross_plane(cross_plane),
|
||||
BlockData(std::string_view b_name, BlockType b_id, bool liquid,
|
||||
bool passable, bool cross_plane, bool transparent, bool gas,
|
||||
bool discard, bool blend, bool transitional, float r)
|
||||
: name(b_name), id(b_id), is_liquid(liquid), is_gas(gas),
|
||||
is_passable(passable), is_cross_plane(cross_plane),
|
||||
is_transparent(transparent), is_discard(discard), is_blend(blend),
|
||||
is_transitional(transitional), roughness(r) {}
|
||||
};
|
||||
|
||||
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;
|
||||
BlockData() { name = ""; }
|
||||
};
|
||||
|
||||
} // 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_river();
|
||||
|
||||
void spawn_creature();
|
||||
|
||||
private:
|
||||
static inline std::atomic<bool> is_init{false};
|
||||
static inline unsigned m_generator_seed{0};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "Cubed/constants.hpp"
|
||||
#include "Cubed/gameplay/biome.hpp"
|
||||
#include "Cubed/gameplay/block.hpp"
|
||||
#include "Cubed/gameplay/chunk.hpp"
|
||||
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||
#include "Cubed/gameplay/vertex_data.hpp"
|
||||
#include "world/chunk_data.pb.h"
|
||||
@@ -13,20 +14,20 @@
|
||||
namespace Cubed {
|
||||
class ClientWorld;
|
||||
struct ChunkRenderSnapshot {
|
||||
GLuint normal_vao;
|
||||
size_t normal_vertices_count;
|
||||
GLuint cross_vao;
|
||||
size_t cross_vertices_count;
|
||||
GLuint normal_discard_vao;
|
||||
size_t normal_discard_vertices_count;
|
||||
GLuint normal_blend_vao;
|
||||
size_t normal_blend_vertices_count;
|
||||
GLuint water_vao;
|
||||
size_t water_vertices_count;
|
||||
glm::vec3 center;
|
||||
glm::vec3 half_extents;
|
||||
GLuint normal_vao = 0;
|
||||
size_t normal_vertices_count = 0;
|
||||
GLuint cross_vao = 0;
|
||||
size_t cross_vertices_count = 0;
|
||||
GLuint normal_discard_vao = 0;
|
||||
size_t normal_discard_vertices_count = 0;
|
||||
GLuint normal_blend_vao = 0;
|
||||
size_t normal_blend_vertices_count = 0;
|
||||
GLuint water_vao = 0;
|
||||
size_t water_vertices_count = 0;
|
||||
glm::vec3 center{0.0f};
|
||||
glm::vec3 half_extents{0.0f};
|
||||
};
|
||||
class ClientChunk {
|
||||
class ClientChunk : public Chunk {
|
||||
public:
|
||||
ClientChunk(ClientWorld& world);
|
||||
~ClientChunk();
|
||||
@@ -35,17 +36,6 @@ public:
|
||||
ClientChunk(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;
|
||||
ChunkPos get_chunk_pos() const;
|
||||
const std::vector<BlockType>& get_chunk_blocks() const;
|
||||
@@ -108,7 +98,7 @@ private:
|
||||
std::atomic<bool> m_is_on_gen_vertex_data{false};
|
||||
std::atomic<BiomeType> m_biome = BiomeType::PLAIN;
|
||||
std::mutex m_vertexs_data_mutex;
|
||||
ChunkPos m_chunk_pos;
|
||||
ChunkPos m_chunk_pos{0, 0};
|
||||
ClientWorld& m_world;
|
||||
// the index is a array of block id
|
||||
std::vector<BlockType> m_blocks;
|
||||
@@ -121,7 +111,7 @@ private:
|
||||
*/
|
||||
std::vector<VertexData> m_vertex_data;
|
||||
|
||||
ChunkRenderSnapshot m_render_snapshot;
|
||||
ChunkRenderSnapshot m_render_snapshot{};
|
||||
|
||||
unsigned m_seed = 0;
|
||||
void clear_dirty();
|
||||
|
||||
82
include/Cubed/gameplay/client_entity_manager.hpp
Normal file
82
include/Cubed/gameplay/client_entity_manager.hpp
Normal file
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/ecs/entity.hpp"
|
||||
#include "Cubed/gameplay/gait.hpp"
|
||||
#include "Cubed/tools/cubed_random.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(float dt);
|
||||
void init();
|
||||
|
||||
void receive_entity_create(S2CEntityCreate& msg);
|
||||
void receive_entity_destory(EntityID id);
|
||||
void receive_entity_update(const S2CEntityUpdate& msg);
|
||||
void receive_entity_update(S2CEntityUpdateBatch& msg);
|
||||
void destory(EntityID id);
|
||||
void create(std::string_view name, const glm::vec3& pos);
|
||||
|
||||
const entt::registry& get_registry() const;
|
||||
|
||||
void player_sound(float dt);
|
||||
|
||||
private:
|
||||
struct EntityCreateElement {
|
||||
EntityID id;
|
||||
std::string name;
|
||||
glm::vec3 pos;
|
||||
};
|
||||
|
||||
struct UpdateInfo {
|
||||
EntityID id;
|
||||
glm::vec3 pos;
|
||||
glm::vec3 direction;
|
||||
Gait gait;
|
||||
};
|
||||
|
||||
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;
|
||||
Random m_random;
|
||||
void handle_task(float dt);
|
||||
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, float dt);
|
||||
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,36 @@
|
||||
#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 <glm/glm.hpp>
|
||||
#include <optional>
|
||||
#include <shared_mutex>
|
||||
#include "Cubed/gameplay/ecs/animation.hpp"
|
||||
#include "Cubed/gameplay/ecs/identity.hpp"
|
||||
#include "Cubed/gameplay/ecs/transform.hpp"
|
||||
|
||||
#include <deque>
|
||||
namespace Cubed {
|
||||
|
||||
class ClientWorld;
|
||||
class ClientPlayer {
|
||||
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>;
|
||||
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;
|
||||
struct ClientPlayerSnapshot {
|
||||
double time_ms = 0.0f;
|
||||
glm::vec3 pos{0.0f};
|
||||
float yaw = 0.0f;
|
||||
float pitch = 0.0f;
|
||||
};
|
||||
struct ClientPlayerState {
|
||||
std::deque<ClientPlayerSnapshot> value;
|
||||
};
|
||||
struct ClientPlayer {
|
||||
Position pos{};
|
||||
EntityInfo entity{};
|
||||
WalkPose walk{};
|
||||
Orientation angle{};
|
||||
Position render_pos{};
|
||||
Orientation render_angle{};
|
||||
ClientPlayerState history{};
|
||||
};
|
||||
|
||||
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/chunk_pos.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/local_player.hpp"
|
||||
#include "Cubed/gameplay/network_client.hpp"
|
||||
#include "Cubed/gameplay/world.hpp"
|
||||
#include "Cubed/input/event.hpp"
|
||||
#include "Cubed/tools/cubed_random.hpp"
|
||||
#include "Cubed/tools/priority_thread_pool.hpp"
|
||||
@@ -19,46 +22,26 @@
|
||||
#include <tbb/concurrent_unordered_map.h>
|
||||
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 ClientWorld {
|
||||
class ClientWorld : public World {
|
||||
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();
|
||||
void init(std::string_view player_name,
|
||||
std::shared_ptr<NetworkClient> client);
|
||||
void update(float delta_time);
|
||||
std::shared_ptr<NetworkClient> client, RunMode mode);
|
||||
void update(float dt);
|
||||
bool handle_event(const Event& e);
|
||||
const std::optional<LookBlock>& get_look_block_pos() const;
|
||||
ClientPlayer& get_player();
|
||||
const ClientPlayer& get_player() const;
|
||||
int get_block(const glm::ivec3& block_pos) const;
|
||||
bool is_solid(const glm::ivec3& block_pos) const;
|
||||
bool can_pass_block(const glm::ivec3& block_pos) const;
|
||||
BlockType get_block_tpye(const glm::ivec3& block_pos) const;
|
||||
LocalPlayer& get_player();
|
||||
const LocalPlayer& get_player() const;
|
||||
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;
|
||||
|
||||
void rebuild_world();
|
||||
|
||||
@@ -71,7 +54,6 @@ public:
|
||||
void receive_block_change(const BlockChangeRsp& rsp);
|
||||
void receive_time(const UpdateTime& rsp);
|
||||
|
||||
void receive_remote_player(const PlayerInfoRsp& rsp);
|
||||
void receive_player_logout(const LogoutRsp& rsp);
|
||||
void receive_player_water_sound(const PlayerWaterSound& rsp);
|
||||
void send_player_water_sound(bool underwater, const glm::vec3& pos);
|
||||
@@ -90,8 +72,6 @@ public:
|
||||
void reset_key_status();
|
||||
std::vector<glm::vec4>& planes();
|
||||
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;
|
||||
bool sphere_collide_world(glm::vec3 center, float radius) const;
|
||||
@@ -99,29 +79,35 @@ public:
|
||||
void request_exit();
|
||||
bool is_receive_exit();
|
||||
int chunk_size() const;
|
||||
static AABB get_block_aabb(const glm::ivec3& pos);
|
||||
|
||||
AudioEngine& get_audio();
|
||||
const AudioEngine& get_audio() const;
|
||||
Config& get_config();
|
||||
WorldScene& world_scene();
|
||||
ClientPlayerManager& player_manager();
|
||||
ClientEntityManager& entity_manager();
|
||||
std::shared_ptr<NetworkClient> get_client() const;
|
||||
void set_direct_exit();
|
||||
|
||||
void receive_chat_message(ChatMsg& msg);
|
||||
void send_chat_message(ChatMessage& message);
|
||||
void receive_voice_message(VoiceMsg& msg);
|
||||
bool enable_voice_chat() const;
|
||||
int get_per_tick_time() const override;
|
||||
|
||||
bool is_render(const glm::vec3& pos) const;
|
||||
|
||||
template <typename Fn>
|
||||
void register_ticktimer(std::string_view id, TickType threshold, Fn&& f) {
|
||||
m_ticktimers.emplace(
|
||||
std::piecewise_construct, std::forward_as_tuple(std::string(id)),
|
||||
std::forward_as_tuple(threshold, std::forward<Fn>(f)));
|
||||
void register_timer(std::string_view id, float threshold, Fn&& f) {
|
||||
m_timers.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(std::string(id)),
|
||||
std::forward_as_tuple(threshold, std::forward<Fn>(f)));
|
||||
}
|
||||
|
||||
private:
|
||||
struct VoiceMessage {
|
||||
std::string data;
|
||||
glm::vec3 pos;
|
||||
glm::vec3 pos{0.0f};
|
||||
};
|
||||
|
||||
std::atomic<bool> m_is_pending_delete_queue_free{false};
|
||||
@@ -136,27 +122,24 @@ private:
|
||||
ChunkPos::TBBHash>;
|
||||
using ChunkPosSet = absl::flat_hash_set<ChunkPos, ChunkPos::Hash>;
|
||||
using ChunkPosVector = std::vector<ChunkPos>;
|
||||
using OtherPlayerHashMap = std::unordered_map<std::string, PlayerInfo>;
|
||||
using chunk_acc = ChunkHashMap::accessor;
|
||||
using chunk_cacc = ChunkHashMap::const_accessor;
|
||||
|
||||
struct PendingSound {
|
||||
std::string sound;
|
||||
glm::vec3 sound_pos;
|
||||
glm::vec3 sound_pos{0.0f};
|
||||
};
|
||||
|
||||
static constexpr int WORLD_EXIT_TIMEOUT = 200;
|
||||
static constexpr int MAX_UPLOAD_CHUNK_SUM = 16;
|
||||
ClientPlayer m_player;
|
||||
OtherPlayerHashMap m_player_info;
|
||||
std::atomic<RunMode> m_runmode = RunMode::HYBRID;
|
||||
ClientEntityManager m_entity_manager;
|
||||
ClientPlayerManager m_player_manager;
|
||||
ChunkHashMap m_chunks;
|
||||
AudioEngine& m_audio;
|
||||
Config& m_config;
|
||||
WorldScene& m_world_scene;
|
||||
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<ChunkPos> m_dirty_chunk_queue;
|
||||
@@ -166,9 +149,7 @@ private:
|
||||
|
||||
std::deque<ChunkPos> m_dirty_queue;
|
||||
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::atomic<bool> m_exit_direct{false};
|
||||
std::atomic<bool> m_game_running{false};
|
||||
@@ -176,6 +157,7 @@ private:
|
||||
std::atomic<int> m_rendering_distance{24};
|
||||
std::atomic<TickType> m_game_ticks{0};
|
||||
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_is_rebuilding{false};
|
||||
std::atomic<int> m_chunk_task_id{0};
|
||||
@@ -187,10 +169,6 @@ private:
|
||||
|
||||
Random m_random;
|
||||
|
||||
void client_run(std::stop_token token);
|
||||
|
||||
void report_player_info();
|
||||
|
||||
void set_block(const glm::ivec3& pos, unsigned id);
|
||||
|
||||
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/gait.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
|
||||
31
include/Cubed/gameplay/ecs/client_entity.hpp
Normal file
31
include/Cubed/gameplay/ecs/client_entity.hpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/ecs/animation.hpp"
|
||||
#include "Cubed/gameplay/ecs/transform.hpp"
|
||||
#include "Cubed/gameplay/model.hpp"
|
||||
|
||||
#include <deque>
|
||||
namespace Cubed {
|
||||
struct BaseClientCreature {
|
||||
|
||||
Transform transform{};
|
||||
|
||||
WalkPose pose{};
|
||||
|
||||
ModelID model = 0;
|
||||
};
|
||||
|
||||
struct SoundTime {
|
||||
float next_call_time = 0.0f;
|
||||
};
|
||||
|
||||
struct ClientEntitySnapshot {
|
||||
double time_ms = 0.0;
|
||||
glm::vec3 pos{0.0f};
|
||||
glm::vec3 dir{0.0f};
|
||||
};
|
||||
|
||||
struct ClientEntityState {
|
||||
std::deque<ClientEntitySnapshot> history;
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
14
include/Cubed/gameplay/ecs/entity.hpp
Normal file
14
include/Cubed/gameplay/ecs/entity.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
namespace Cubed {
|
||||
using EntityID = uint64_t;
|
||||
|
||||
enum class EntityType { CREATURE, ITEM };
|
||||
|
||||
struct Entity {
|
||||
EntityID id;
|
||||
EntityType type;
|
||||
Entity(EntityID id, EntityType type) : id(id), type(type) {}
|
||||
};
|
||||
|
||||
} // 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
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace Cubed {
|
||||
enum class Gait { STOP = 0, WALK = 1, RUN = 2 };
|
||||
constexpr int get_gait_id(Gait gait) { return std::to_underlying(gait); }
|
||||
@@ -17,5 +18,4 @@ inline Gait get_gait_from_id(int id) {
|
||||
throw std::runtime_error("Unknown Gait");
|
||||
}
|
||||
}
|
||||
|
||||
} // 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
|
||||
#include "Cubed/gameplay/block.hpp"
|
||||
#include "Cubed/gameplay/item.hpp"
|
||||
namespace Cubed {
|
||||
|
||||
struct ItemStack {
|
||||
BlockType type = 0;
|
||||
ItemID id = 0;
|
||||
size_t sum = 0;
|
||||
};
|
||||
} // namespace Cubed
|
||||
|
||||
161
include/Cubed/gameplay/local_player.hpp
Normal file
161
include/Cubed/gameplay/local_player.hpp
Normal file
@@ -0,0 +1,161 @@
|
||||
#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/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();
|
||||
|
||||
// Run in another thread after initialization is complete
|
||||
void start_server(int port);
|
||||
void start_server();
|
||||
void start_server(int port, RunMode mode);
|
||||
int port() const;
|
||||
ServerWorld& server_world();
|
||||
|
||||
|
||||
@@ -51,18 +51,28 @@ enum class PacketEnum : uint16_t {
|
||||
LOGIN_RSP = 1002,
|
||||
LOGOUT_REQ = 1003,
|
||||
LOGOUT_RSP = 1004,
|
||||
|
||||
PLAYER_INFO = 2001,
|
||||
C2S_PLAYER_INFO = 2002,
|
||||
PLAYER_INFO_RSP = 2003,
|
||||
PLAYER_WATER_SOUND = 2004,
|
||||
|
||||
CHUNK_DATA_REQ = 3001,
|
||||
CHUNK_DATA_RSP = 3002,
|
||||
BLOCK_CHANGE_REQ = 3003,
|
||||
BLOCK_CHANGE_RSP = 3004,
|
||||
S2C_CLEAR_ALL_CHUNKS = 3005,
|
||||
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,
|
||||
S2C_ENTITY_UPDATE_BATCH = 3012,
|
||||
|
||||
CHAT_MSG = 4001,
|
||||
VOICE_MSG = 4002,
|
||||
|
||||
PING = 9001,
|
||||
PONG = 9002
|
||||
|
||||
@@ -111,6 +121,18 @@ template <> constexpr uint16_t get_packet_id<BlockChangeRsp>() {
|
||||
template <> constexpr uint16_t get_packet_id<S2C_ClearAllChunks>() {
|
||||
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>() {
|
||||
return std::to_underlying(PacketEnum::UPDATE_TIME);
|
||||
}
|
||||
@@ -129,6 +151,12 @@ template <> constexpr uint16_t get_packet_id<ChatMsg>() {
|
||||
template <> constexpr uint16_t get_packet_id<VoiceMsg>() {
|
||||
return std::to_underlying(PacketEnum::VOICE_MSG);
|
||||
}
|
||||
template <> constexpr uint16_t get_packet_id<S2CEntityUpdate>() {
|
||||
return std::to_underlying(PacketEnum::S2C_ENTITY_UPDATE);
|
||||
}
|
||||
template <> constexpr uint16_t get_packet_id<S2CEntityUpdateBatch>() {
|
||||
return std::to_underlying(PacketEnum::S2C_ENTITY_UPDATE_BATCH);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires std::derived_from<T, google::protobuf::Message>
|
||||
@@ -180,6 +208,12 @@ Packet make_packet(const T& msg) {
|
||||
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) {
|
||||
if (header.size() < HEADER_LEN)
|
||||
throw std::runtime_error("Invalid header");
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "Cubed/constants.hpp"
|
||||
#include "Cubed/gameplay/biome.hpp"
|
||||
#include "Cubed/gameplay/block.hpp"
|
||||
#include "Cubed/gameplay/chunk.hpp"
|
||||
#include "Cubed/gameplay/chunk_generator.hpp"
|
||||
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||
|
||||
@@ -11,7 +12,7 @@
|
||||
#include <tuple>
|
||||
namespace Cubed {
|
||||
class ServerWorld;
|
||||
class ServerChunk {
|
||||
class ServerChunk : public Chunk {
|
||||
public:
|
||||
ServerChunk(ServerWorld& world, ChunkPos chunk_pos,
|
||||
bool temp_chunk = false);
|
||||
@@ -66,7 +67,7 @@ private:
|
||||
|
||||
ChunkPos m_chunk_pos;
|
||||
ServerWorld& m_world;
|
||||
HeightMapArray m_heightmap;
|
||||
HeightMapArray m_heightmap{};
|
||||
// the index is a array of block id
|
||||
std::vector<BlockType> m_blocks;
|
||||
OptionalBlockVectorArray m_neightbor_blocks;
|
||||
|
||||
81
include/Cubed/gameplay/server_entity_manager.hpp
Normal file
81
include/Cubed/gameplay/server_entity_manager.hpp
Normal file
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/ecs/entity.hpp"
|
||||
#include "Cubed/gameplay/gait.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>
|
||||
#include <variant>
|
||||
namespace Cubed {
|
||||
class ServerWorld;
|
||||
class Session;
|
||||
class ServerEntityManager {
|
||||
public:
|
||||
static constexpr size_t PER_CREATURE_LIMITS = 100;
|
||||
|
||||
ServerEntityManager(ServerWorld& world);
|
||||
|
||||
void init();
|
||||
void update();
|
||||
void add_creature(std::string_view name, const glm::vec3& world_pos);
|
||||
void destory(EntityID id);
|
||||
void handle_player_login(std::shared_ptr<Session> session);
|
||||
|
||||
size_t max_creature_sum() const;
|
||||
size_t creature_sum() const;
|
||||
size_t entity_sum() const;
|
||||
|
||||
private:
|
||||
enum class Command { CREATE, SEND_ALL_ENTITIES, DESTORY };
|
||||
struct EntityCreateElement {
|
||||
std::string name;
|
||||
glm::vec3 pos;
|
||||
};
|
||||
|
||||
struct EntitySendData {
|
||||
EntityID id;
|
||||
glm::vec3 pos;
|
||||
glm::vec3 dir;
|
||||
Gait gait;
|
||||
};
|
||||
|
||||
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;
|
||||
std::atomic<size_t> m_creature_sum{0};
|
||||
std::atomic<size_t> m_entity_sum{0};
|
||||
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<EntitySendData>& 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
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||
#include "Cubed/gameplay/gait.hpp"
|
||||
#include "Cubed/gameplay/game_time.hpp"
|
||||
#include "Cubed/gameplay/player.hpp"
|
||||
|
||||
#include <absl/container/flat_hash_set.h>
|
||||
#include <atomic>
|
||||
@@ -59,7 +59,7 @@ private:
|
||||
std::atomic<int> m_chunk_task_id{0};
|
||||
std::atomic<float> m_yaw{0.0f};
|
||||
std::atomic<float> m_pitch{0.0f};
|
||||
std::atomic<Gait> m_gait;
|
||||
std::atomic<Gait> m_gait{Gait::STOP};
|
||||
mutable std::shared_mutex m_chunk_pos_mutex;
|
||||
ChunkPosSet m_player_chunk_pos_set;
|
||||
};
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
#include "Cubed/gameplay/packet.hpp" // IWYU pragma: keep
|
||||
#include "Cubed/gameplay/river_worm.hpp"
|
||||
#include "Cubed/gameplay/server_chunk.hpp"
|
||||
#include "Cubed/gameplay/server_entity_manager.hpp"
|
||||
#include "Cubed/gameplay/server_player.hpp"
|
||||
#include "Cubed/gameplay/world.hpp"
|
||||
#include "Cubed/tools/priority_thread_pool.hpp"
|
||||
#include "Cubed/tools/recent_queue.hpp"
|
||||
#include "Cubed/tools/sensitive_filter.hpp"
|
||||
@@ -20,19 +22,20 @@
|
||||
#include <tbb/concurrent_hash_map.h>
|
||||
#include <tbb/concurrent_queue.h>
|
||||
#include <tbb/concurrent_unordered_map.h>
|
||||
#include <tbb/concurrent_vector.h>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
namespace Cubed {
|
||||
class Session;
|
||||
class ServerWorld {
|
||||
class ServerWorld : public World {
|
||||
public:
|
||||
enum class ThreadPoolKind { NET, GEN };
|
||||
ServerWorld(Config& config);
|
||||
~ServerWorld();
|
||||
void stop();
|
||||
void handle_player_exit(const std::string& uuid);
|
||||
void init_world();
|
||||
void init_world(RunMode mode);
|
||||
void need_gen(std::string uuid);
|
||||
void update();
|
||||
void hot_reload();
|
||||
@@ -84,7 +87,24 @@ public:
|
||||
|
||||
void handle_chat_message(ChatMsg& msg);
|
||||
void handle_voice_message(VoiceMsg& msg);
|
||||
|
||||
void handle_entity_create(C2SEntityCreateRequest& req);
|
||||
void handle_entity_destory(C2SEntityDestoryRequest& req);
|
||||
|
||||
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();
|
||||
size_t player_sum() const;
|
||||
|
||||
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>
|
||||
void register_timer(std::string_view id, TickType threshold, Fn&& f) {
|
||||
m_timers.emplace(std::piecewise_construct,
|
||||
@@ -95,9 +115,29 @@ public:
|
||||
private:
|
||||
enum class ChunkState { NONE, GENERATING, READY, PENDING_DELETE };
|
||||
struct ChunkEntity {
|
||||
ChunkState state;
|
||||
ChunkState state = ChunkState::NONE;
|
||||
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 };
|
||||
@@ -119,13 +159,14 @@ private:
|
||||
using PlayerUUIDMap = tbb::concurrent_hash_map<std::string, std::string>;
|
||||
|
||||
using chunk_acc = ChunkHashMap::accessor;
|
||||
using chunk_caac = ChunkHashMap::const_accessor;
|
||||
using chunk_cacc = ChunkHashMap::const_accessor;
|
||||
|
||||
using uuid_acc = PlayerUUIDMap::accessor;
|
||||
using uuid_cacc = PlayerUUIDMap::const_accessor;
|
||||
|
||||
Config& m_config;
|
||||
|
||||
std::atomic<RunMode> m_runmode{RunMode::HYBRID};
|
||||
ServerEntityManager m_entity_manager;
|
||||
// key = uuid
|
||||
PlayerHashMap m_players;
|
||||
ChunkHashMap m_chunks;
|
||||
@@ -146,8 +187,9 @@ private:
|
||||
std::atomic<bool> m_init{false};
|
||||
std::atomic<bool> m_stopped{false};
|
||||
std::atomic<int> m_rendering_distance{24};
|
||||
std::atomic<int> m_gen_pool_threads{0};
|
||||
std::atomic<int> m_net_pool_threads{0};
|
||||
std::atomic<int> m_gen_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<size_t> m_player_sum{0};
|
||||
std::atomic<TickType> m_game_ticks{0};
|
||||
@@ -155,7 +197,7 @@ private:
|
||||
std::atomic<bool> m_tick_running{true};
|
||||
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::condition_variable_any m_gen_cv;
|
||||
|
||||
@@ -163,6 +205,7 @@ private:
|
||||
|
||||
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_compute_thread_pool;
|
||||
|
||||
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 {
|
||||
|
||||
struct MoveState {
|
||||
bool forward = false;
|
||||
bool back = false;
|
||||
bool left = false;
|
||||
bool right = false;
|
||||
bool down = false;
|
||||
bool up = false;
|
||||
};
|
||||
|
||||
struct MouseState {
|
||||
bool left = false;
|
||||
bool right = false;
|
||||
|
||||
46
include/Cubed/render/model_manager.hpp
Normal file
46
include/Cubed/render/model_manager.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#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);
|
||||
void load_anim_config(ModelNode& node, const std::string& path);
|
||||
};
|
||||
} // namespace Cubed
|
||||
79
include/Cubed/render/model_node.hpp
Normal file
79
include/Cubed/render/model_node.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#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>
|
||||
#include <string_view>
|
||||
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 NodeAnimRule {
|
||||
enum class Role { NONE, LEG, HEAD };
|
||||
std::string node;
|
||||
Role role = Role::NONE;
|
||||
float phase = 0.0f;
|
||||
};
|
||||
|
||||
struct ModelAnimConfig {
|
||||
float walk_speed = 6.0f;
|
||||
float walk_amp = 25.0f;
|
||||
float run_speed = 12.0f;
|
||||
float run_amp = 40.0f;
|
||||
float body_bob = 0.05f;
|
||||
float head_amp = 4.0f;
|
||||
std::vector<NodeAnimRule> nodes;
|
||||
|
||||
const NodeAnimRule* rule_for(std::string_view name) const {
|
||||
for (const auto& r : nodes) {
|
||||
if (r.node == name) {
|
||||
return &r;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool has_role(NodeAnimRule::Role role) const {
|
||||
for (const auto& r : nodes) {
|
||||
if (r.role == role) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
struct ModelNode {
|
||||
std::string name;
|
||||
glm::mat4 transform{1.0f};
|
||||
|
||||
std::vector<Mesh> meshes;
|
||||
std::vector<ModelNode> children;
|
||||
ModelAnimConfig anim;
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
55
include/Cubed/render/model_renderer.hpp
Normal file
55
include/Cubed/render/model_renderer.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cubed/gameplay/ecs/animation.hpp"
|
||||
#include "Cubed/gameplay/model.hpp"
|
||||
#include "Cubed/render/model_node.hpp"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <span>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
namespace Cubed {
|
||||
class Renderer;
|
||||
class Camera;
|
||||
class ModelRender {
|
||||
public:
|
||||
struct InstanceData {
|
||||
glm::vec3 pos{0.0f};
|
||||
float yaw = 0.0f;
|
||||
WalkPose pose;
|
||||
};
|
||||
|
||||
struct DrawEntry {
|
||||
const Mesh* mesh = nullptr;
|
||||
size_t node_slot = 0;
|
||||
};
|
||||
|
||||
struct ModelBatch {
|
||||
size_t node_count = 0;
|
||||
size_t capacity = 0;
|
||||
std::vector<DrawEntry> entries;
|
||||
std::vector<glm::mat4> instance_matrices;
|
||||
std::unique_ptr<VertexBuffer> instance_vbo;
|
||||
};
|
||||
|
||||
ModelRender(Renderer& renderer);
|
||||
|
||||
void render_instance(ModelID id, size_t sum, const Camera& camera,
|
||||
bool shadow);
|
||||
void build_vertices(ModelID id, std::span<const InstanceData> instances);
|
||||
|
||||
private:
|
||||
Renderer& m_renderer;
|
||||
|
||||
std::unordered_map<ModelID, ModelBatch> m_batches;
|
||||
|
||||
size_t collect_matrices(const ModelNode& node, const glm::mat4& parent,
|
||||
const WalkPose& pose, const ModelAnimConfig& cfg,
|
||||
std::vector<glm::mat4>& out, size_t slot);
|
||||
glm::mat4 pose_node(const ModelNode& node, const ModelAnimConfig& cfg,
|
||||
const WalkPose& pose);
|
||||
|
||||
ModelBatch& get_batch(ModelID id, const ModelNode& root);
|
||||
size_t flatten_nodes(const ModelNode& node, size_t slot, ModelBatch& batch);
|
||||
};
|
||||
} // namespace Cubed
|
||||
@@ -13,9 +13,7 @@ public:
|
||||
PlayerRenderer(Renderer& renderer);
|
||||
~PlayerRenderer();
|
||||
void init();
|
||||
void render(const Shader& shader, ClientWorld& world);
|
||||
void shadow_render(const Shader& shader, glm::mat4& light_matrix,
|
||||
ClientWorld& world);
|
||||
void render(const Shader& shader, ClientWorld& world, bool shadow_render);
|
||||
|
||||
private:
|
||||
struct PlayerVertex {
|
||||
@@ -26,8 +24,8 @@ private:
|
||||
float tx = 0.0f, ty = 0.0f, tz = 0.0f;
|
||||
};
|
||||
Renderer& m_renderer;
|
||||
std::array<GLuint, BODY_PART_NUM> m_vao;
|
||||
std::array<GLuint, BODY_PART_NUM> m_vbo;
|
||||
std::array<GLuint, BODY_PART_NUM> m_vao{};
|
||||
std::array<GLuint, BODY_PART_NUM> m_vbo{};
|
||||
bool m_inited{false};
|
||||
std::array<std::vector<PlayerVertex>, BODY_PART_NUM> m_vertices;
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Cubed/constants.hpp"
|
||||
#include "Cubed/input/event.hpp"
|
||||
#include "Cubed/primitive_data.hpp"
|
||||
#include "Cubed/render/model_renderer.hpp"
|
||||
#include "Cubed/render/player_renderer.hpp"
|
||||
#include "Cubed/render/shader_manager.hpp"
|
||||
#include "Cubed/render/vertex_array.hpp"
|
||||
@@ -19,11 +20,12 @@
|
||||
namespace Cubed {
|
||||
class TextureManager;
|
||||
class ClientWorld;
|
||||
class ModelManager;
|
||||
class DevPanel;
|
||||
class Renderer {
|
||||
public:
|
||||
constexpr static int NUM_VAO = 7;
|
||||
|
||||
constexpr static const char* SCREENSHOT_PATH = "./screenshot";
|
||||
Renderer(TextureManager& texture_manager, Config& config);
|
||||
~Renderer();
|
||||
void reload_config();
|
||||
@@ -79,9 +81,12 @@ public:
|
||||
|
||||
bool handle_event(const Event& e);
|
||||
|
||||
ModelRender& model_renderer();
|
||||
|
||||
void save_screenshot();
|
||||
|
||||
private:
|
||||
TextureManager& m_texture_manager;
|
||||
|
||||
bool m_init = false;
|
||||
|
||||
float m_aspect = 0.0f;
|
||||
@@ -95,7 +100,9 @@ private:
|
||||
float m_window_width = 0.0f;
|
||||
float m_window_height = 0.0f;
|
||||
|
||||
glm::mat4 m_world_proj_matrix;
|
||||
bool m_save_screenshot = false;
|
||||
|
||||
glm::mat4 m_world_proj_matrix{0.0f};
|
||||
|
||||
std::unique_ptr<VertexBuffer> m_sky_vbo;
|
||||
std::unique_ptr<VertexBuffer> m_outline_indices_vbo;
|
||||
@@ -104,7 +111,7 @@ private:
|
||||
std::unique_ptr<VertexBuffer> m_player_vbo;
|
||||
std::unique_ptr<VertexBuffer> m_quad_vbo;
|
||||
|
||||
glm::mat4 m_ui_proj_matrix;
|
||||
glm::mat4 m_ui_proj_matrix{0.0f};
|
||||
ShaderManager m_shaders;
|
||||
|
||||
/*
|
||||
@@ -118,6 +125,7 @@ private:
|
||||
std::vector<Vertex2D> m_ui;
|
||||
|
||||
WorldRenderer m_world_renderer;
|
||||
ModelRender m_model_renderer;
|
||||
Config& m_config;
|
||||
|
||||
bool handle_window_resize_event(const WindowResizeEvent& e);
|
||||
@@ -125,6 +133,7 @@ private:
|
||||
void updata_framebuffer(int width, int height);
|
||||
void init_quad();
|
||||
void init_text();
|
||||
void handle_screenshot();
|
||||
};
|
||||
|
||||
} // namespace Cubed
|
||||
@@ -38,9 +38,11 @@ enum TextureFormat : GLenum {
|
||||
R8 = GL_R8,
|
||||
RGB = GL_RGB,
|
||||
RGBA8 = GL_RGBA8,
|
||||
BGRA = GL_BGRA
|
||||
|
||||
};
|
||||
|
||||
// You need to set the texture scaling method, otherwise it will render as
|
||||
// black.
|
||||
class Texture {
|
||||
public:
|
||||
explicit Texture(TextureType type);
|
||||
|
||||
@@ -19,6 +19,7 @@ public:
|
||||
|
||||
void attribute(GLuint index, GLint size, GLenum type, GLsizei stride,
|
||||
const void* ptr, bool normalized = false) const;
|
||||
void divisor(GLuint index, GLuint divisor = 1);
|
||||
|
||||
private:
|
||||
GLuint m_vao = 0;
|
||||
|
||||
@@ -26,6 +26,8 @@ public:
|
||||
GLuint id() const;
|
||||
void buffer_data(const void* data, GLsizeiptr size,
|
||||
BufferUsage usage = BufferUsage::STATIC_DRAW) const;
|
||||
void buffer_sub_data(const void* data, GLsizeiptr size,
|
||||
GLintptr offset) const;
|
||||
|
||||
private:
|
||||
GLuint m_vbo = 0;
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/model.hpp"
|
||||
#include "Cubed/render/frame_buffer.hpp"
|
||||
#include "Cubed/render/model_renderer.hpp"
|
||||
#include "Cubed/render/player_renderer.hpp"
|
||||
#include "Cubed/render/texture.hpp"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
namespace Cubed {
|
||||
class Renderer;
|
||||
class ClientWorld;
|
||||
@@ -12,6 +16,8 @@ class TextureManager;
|
||||
class Camera;
|
||||
class WorldRenderer {
|
||||
public:
|
||||
using InstanceDataMap =
|
||||
std::unordered_map<ModelID, std::vector<ModelRender::InstanceData>>;
|
||||
struct ParallelLight {
|
||||
glm::vec3 sundir; // direction from sun to vertex
|
||||
glm::vec3 lightdir;
|
||||
@@ -83,8 +89,8 @@ private:
|
||||
std::unique_ptr<FrameBuffer> m_depth_map_fbo;
|
||||
std::unique_ptr<Texture> m_depth_map_texture;
|
||||
|
||||
glm::vec3 m_blend_from_lightdir;
|
||||
glm::vec3 m_blend_to_lightdir;
|
||||
glm::vec3 m_blend_from_lightdir{0.0f};
|
||||
glm::vec3 m_blend_to_lightdir{0.0f};
|
||||
float m_blend_t = 1.0f;
|
||||
bool m_blend_initialized = false;
|
||||
static constexpr float BLEND_DURATION = 0.15f;
|
||||
@@ -119,7 +125,7 @@ private:
|
||||
ParallelLight m_parallel_light;
|
||||
SkyUniform m_sky_uniform;
|
||||
|
||||
glm::mat4 view_matrix;
|
||||
glm::mat4 view_matrix{0.0f};
|
||||
|
||||
const TextureManager& m_texture_manager;
|
||||
void day_night_calculation(ClientWorld& world);
|
||||
@@ -128,11 +134,13 @@ private:
|
||||
|
||||
void render_world(ClientWorld& world);
|
||||
|
||||
void shadow_map_generate(ClientWorld& world);
|
||||
void shadow_map_generate(ClientWorld& world, const InstanceDataMap& map);
|
||||
|
||||
void render_underwater(ClientWorld& world);
|
||||
void render_outline(ClientWorld& world);
|
||||
void render_player(ClientWorld& world);
|
||||
void shadow_entity(ClientWorld& world, const glm::mat4& light_matrix,
|
||||
const InstanceDataMap& map);
|
||||
void render_entity(ClientWorld& world, const InstanceDataMap& map);
|
||||
|
||||
void render_normal_block(const glm::mat4& model_mat,
|
||||
const glm::mat4& mv_mat, const glm::mat4& norm_mat,
|
||||
@@ -146,5 +154,6 @@ private:
|
||||
float angle_step_deg) const;
|
||||
glm::vec3 get_smoothed_shadow_lightdir(const glm::vec3& raw_shadow_sundir,
|
||||
float dt);
|
||||
InstanceDataMap entity_build(ClientWorld& world);
|
||||
};
|
||||
} // namespace Cubed
|
||||
@@ -9,7 +9,8 @@ enum class SceneType {
|
||||
CREDITS,
|
||||
SETTINGS,
|
||||
HOST_GAME,
|
||||
JOIN_GAME
|
||||
JOIN_GAME,
|
||||
SCREENSHOT
|
||||
};
|
||||
|
||||
class Scene {
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
|
||||
App& app();
|
||||
WorldSceneParam& world_scene_param();
|
||||
void push(SceneType type);
|
||||
|
||||
private:
|
||||
enum class OperationType { PUSH, POP, CHANGE };
|
||||
@@ -51,7 +52,7 @@ private:
|
||||
std::stack<std::unique_ptr<Scene>> m_scenes;
|
||||
void process_operation();
|
||||
void change(SceneType type);
|
||||
void push(SceneType type);
|
||||
|
||||
void pop(bool re_enter = true);
|
||||
|
||||
std::unique_ptr<Scene> create_scene(SceneType);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user