Skip to content

Commit 1ee88cd

Browse files
committed
HexMapCellIdRef: passing a cell id to GDScript
Had to add a class for wrapping HexMapCellId to pass to GDScript. There's a whole series of problems here. First of all, ClassDB::bind_method() can only bind methods that return a type that can be cast to a Variant. From some resources the only two viable options were Ref<T> or a pointer to an Object subclass[^1]. Pointer means we need to somehow manage memory that we've entirely passed up to GDScript. Instead we use Ref<T>. Second problem, you cannot use Object subclasses on the stack in godot-cpp[^2]. This means if we make HexMapCellId a subclass of godot::Object, we cannot use it on the stack, or easily construct it using an initializer. Insteat we'd have to use `memnew()` all over the place. So we're using a wrapper class `HexMapCellId < public godot::RefCounted`. It's a boiler-plate heavy approach, but it works for now. Did propose to godot-cpp to add a compiler flag to disable the guard-rail that keeps us from using `godot::Object` subclasses on the stack[^3]. [^1]: https://forum.godotengine.org/t/returning-custom-classes-from-c-gdextension/65920/18 [^2]: godotengine/godot-cpp#1446 (comment) [^3]: godotengine/godot-cpp#1446 (comment)
1 parent a9c6ddc commit 1ee88cd

File tree

9 files changed

+361
-106
lines changed

9 files changed

+361
-106
lines changed

demo/node_3d.tscn

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,34 @@
1-
[gd_scene load_steps=2 format=4 uid="uid://bt0soj2wvavie"]
1+
[gd_scene load_steps=4 format=4 uid="uid://bt0soj2wvavie"]
22

33
[ext_resource type="MeshLibrary" uid="uid://ygm46u2uobsa" path="res://tileset.tres" id="1_43pbi"]
4+
[ext_resource type="PackedScene" uid="uid://wcaukixhlbo2" path="res://RayPickerCamera/ray_picker_camera.tscn" id="1_wtynj"]
5+
6+
[sub_resource type="CapsuleMesh" id="CapsuleMesh_bq4b2"]
47

58
[node name="Node3D" type="Node3D"]
69

10+
[node name="RayPickerCamera" parent="." node_paths=PackedStringArray("hex_map", "marker") instance=ExtResource("1_wtynj")]
11+
transform = Transform3D(1, 0, 0, 0, 0.5, 0.866025, 0, -0.866025, 0.5, 0, 26.0113, 10.4268)
12+
fov = 35.0
13+
hex_map = NodePath("../HexMap")
14+
label_cells = false
15+
marker = NodePath("../GridMap/Marker")
16+
17+
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
18+
transform = Transform3D(-0.866023, -0.433016, 0.250001, 0, 0.499998, 0.866027, -0.500003, 0.749999, -0.43301, 0, 66.1477, 0)
19+
shadow_enabled = true
20+
721
[node name="GridMap" type="GridMap" parent="."]
822
mesh_library = ExtResource("1_43pbi")
923

24+
[node name="Marker" type="MeshInstance3D" parent="GridMap"]
25+
mesh = SubResource("CapsuleMesh_bq4b2")
26+
1027
[node name="HexMap" type="HexMap" parent="."]
1128
mesh_library = ExtResource("1_43pbi")
1229
cell_size = Vector3(1.154, 1, 1.154)
1330
cell_center_y = false
1431
data = {
15-
"cells": PackedByteArray("")
32+
"cells": PackedByteArray("/P8AAP7/AAAAAP3/AAD9/wAAAAD+/wAA/P8AAAAA//8AAPz/AAAAAP7/AAD9/wAAAAD9/wAA/v8AAAAA+/8AAP//AAAAAPz/AAD//wAAAAD//wAA/f8AAAAA/v8AAP7/AAAAAPv/AAAAAAAAAAD8/wAAAAAAAAAA/f8AAP//AAAAAP7/AAD//wAAAAD//wAA/v8AAAAAAAAAAP3/AAAAAAEAAAD8/wAAAAABAAAA/f8AAAAA/f8AAAAAAAAAAP//AAD//wAAAAAAAAAA/v8AAAAAAAAAAP//AAAAAP7/AAAAAAAAAAD8/wAAAQAAAAAA/f8AAAEAAAAAAP7/AAABAAAAAAD//wAAAAAAAAAA+/8AAAEAAAAAAPv/AAD+/wAAAAD6/wAAAQAAAAAA+v8AAAAAAAAAAPv/AAD9/wAAAAD8/wAA/f8AAAAA/f8AAPz/AAAAAPr/AAD//wAAAAD8/wAA/P8AAAAA/f8AAPv/AAAAAP7/AAD7/wAAAAD//wAA+/8AAAAAAAAAAPv/AAAAAAEAAAD7/wAAAAAAAAAA/P8AAAAAAgAAAPv/AAAAAAIAAAD6/wAAAAABAAAA+v8AAAAAAAAAAPr/AAAAAP//AAD6/wAAAAD+/wAA+v8AAAAA/f8AAPr/AAAAAPz/AAD7/wAAAAD7/wAA/P8AAAAA+v8AAP7/AAAAAPn/AAAAAAAAAAD5/wAAAQAAAAAA+f8AAP7/AAAAAPr/AAD9/wAAAAD5/wAA//8AAAAAAgAAAPz/AAAAAAIAAAD9/wAAAAABAAAA/v8AAAAAAgAAAP7/AAAAAAEAAAD//wAAAAAAAAAAAAAAAAAA//8AAAEAAAAAAAYAAAD6/wAAAAAFAAAA+/8AAAAABQAAAPz/AAAAAAUAAAD9/wAAAAAFAAAA/v8AAAAABgAAAP3/AAAAAAcAAAD9/wAAAAAHAAAA/P8AAAAACAAAAPz/AAAAAAgAAAD7/wAAAAAIAAAA+v8AAAAABwAAAPr/AAAAAAYAAAD8/wAAAAAHAAAA+/8AAAAABgAAAPv/AAAAAA==")
1633
}
1734
metadata/_editor_floors_ = [0, 0, 0, 0]

demo/project.godot

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,29 @@ config_version=5
1111
[application]
1212

1313
config/name="HexGrid Demo"
14+
run/main_scene="res://node_3d.tscn"
1415
config/features=PackedStringArray("4.3", "Forward Plus")
1516
config/icon="res://icon.svg"
17+
18+
[display]
19+
20+
window/stretch/mode="viewport"
21+
window/dpi/allow_hidpi=false
22+
23+
[input]
24+
25+
zoom_in={
26+
"deadzone": 0.5,
27+
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":8,"position":Vector2(425, 26),"global_position":Vector2(444, 117),"factor":0.0300018,"button_index":4,"canceled":false,"pressed":true,"double_click":false,"script":null)
28+
]
29+
}
30+
zoom_out={
31+
"deadzone": 0.5,
32+
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":16,"position":Vector2(604, 30),"global_position":Vector2(623, 121),"factor":0.0300018,"button_index":5,"canceled":false,"pressed":true,"double_click":false,"script":null)
33+
]
34+
}
35+
place_marker={
36+
"deadzone": 0.5,
37+
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":1,"position":Vector2(177, 34),"global_position":Vector2(196, 125),"factor":1.0,"button_index":1,"canceled":false,"pressed":true,"double_click":false,"script":null)
38+
]
39+
}

demo/tileset.tres

Lines changed: 123 additions & 87 deletions
Large diffs are not rendered by default.

demo/tileset.tscn

Lines changed: 145 additions & 1 deletion
Large diffs are not rendered by default.

src/hex_map/hex_map.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,10 @@
2929
/**************************************************************************/
3030

3131
#include "hex_map.h"
32-
#include "godot_cpp/variant/basis.hpp"
33-
#include "godot_cpp/variant/utility_functions.hpp"
3432
#include "hex_map_cell_id.h"
3533
#include "tile_orientation.h"
3634

35+
#include "godot_cpp/variant/basis.hpp"
3736
#include <godot_cpp/classes/array_mesh.hpp>
3837
#include <godot_cpp/classes/main_loop.hpp>
3938
#include <godot_cpp/classes/material.hpp>
@@ -114,8 +113,6 @@ bool HexMap::_set(const StringName &p_name, const Variant &p_value) {
114113
cell.cell = cells.decode_u32(offset);
115114
offset += 4;
116115

117-
UtilityFunctions::print("loaded one cell");
118-
119116
cell_map[key] = cell;
120117
}
121118
}
@@ -571,6 +568,19 @@ static inline Vector3i oddr_to_axial(Vector3i oddr) {
571568
return Vector3i(q, oddr.y, oddr.z);
572569
}
573570

571+
HexMapCellId HexMap::local_to_cell_id(const Vector3 &local_position) const {
572+
Vector3 unit_pos = local_position / cell_size;
573+
return HexMapCellId::from_unit_point(unit_pos);
574+
}
575+
576+
Ref<HexMapCellIdRef> HexMap::_local_to_cell_id(
577+
const Vector3 &p_local_position) const {
578+
Ref<HexMapCellIdRef> ref;
579+
ref.instantiate();
580+
ref->set(local_to_cell_id(p_local_position));
581+
return ref;
582+
}
583+
574584
HexMap::CellId HexMap::local_to_map(const Vector3 &p_local_position) const {
575585
// convert x/z point into axial hex coordinates
576586
// https://www.redblobgames.com/grids/hexagons/#pixel-to-hex
@@ -1458,6 +1468,9 @@ void HexMap::_bind_methods() {
14581468
D_METHOD("local_region_to_map", "local_point_a", "local_point_b"),
14591469
&HexMap::_local_region_to_map);
14601470

1471+
ClassDB::bind_method(D_METHOD("local_to_cell_id", "local_position"),
1472+
&HexMap::_local_to_cell_id);
1473+
14611474
#ifndef DISABLE_DEPRECATED
14621475
ClassDB::bind_method(D_METHOD("resource_changed", "resource"),
14631476
&HexMap::resource_changed);

src/hex_map/hex_map.h

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ using namespace godot;
5454
#define RS RenderingServer
5555

5656
class HexMapCellId;
57+
class HexMapCellIdRef;
5758

5859
class HexMap : public Node3D {
5960
GDCLASS(HexMap, Node3D);
@@ -195,13 +196,6 @@ class HexMap : public Node3D {
195196

196197
void _recreate_octant_data();
197198

198-
struct BakeLight {
199-
RS::LightType type = RS::LightType::LIGHT_DIRECTIONAL;
200-
Vector3 pos;
201-
Vector3 dir;
202-
float param[RS::LIGHT_PARAM_MAX] = {};
203-
};
204-
205199
_FORCE_INLINE_ Vector3 _octant_get_offset(const OctantKey &p_key) const {
206200
return Vector3(p_key.x, p_key.y, p_key.z) * cell_size * octant_size;
207201
}
@@ -313,6 +307,11 @@ class HexMap : public Node3D {
313307
Basis get_basis_with_orthogonal_index(int p_index) const;
314308
TypedArray<Vector3i> get_cell_neighbors(const Vector3i p_cell) const;
315309

310+
HexMapCellId local_to_cell_id(const Vector3 &local_position) const;
311+
Ref<HexMapCellIdRef> _local_to_cell_id(
312+
const Vector3 &local_position) const;
313+
Vector3 cell_id_to_local(const HexMapCellId &cell_id) const;
314+
316315
CellId local_to_map(const Vector3 &p_local_position) const;
317316
Vector3 map_to_local(const Vector3i &p_map_position) const;
318317
// Vector3 map_to_local(const HexMapCellId &p_cell_id) const;

src/hex_map/hex_map_cell_id.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ HexMapCellId::operator String() const {
6161
// clang-format off
6262
return (String)"{ .q = " + itos(q) +
6363
", .r = " + itos(r) +
64+
", .s = " + itos(s()) +
6465
", .y = " + itos(y) + "}";
6566
// clang-format on
6667
}
@@ -75,3 +76,5 @@ std::ostream &operator<<(std::ostream &os, const HexMapCellId &value) {
7576
os << " }";
7677
return os;
7778
}
79+
80+
String HexMapCellIdRef::_to_string() { return (String)this->cell_id; }

src/hex_map/hex_map_cell_id.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include "godot_cpp/classes/ref_counted.hpp"
4+
#include "godot_cpp/classes/wrapped.hpp"
35
#include "godot_cpp/variant/vector3.hpp"
46
#include "hex_map.h"
57

@@ -58,3 +60,20 @@ class HexMapCellId {
5860

5961
// added for testing
6062
std::ostream &operator<<(std::ostream &os, const HexMapCellId &value);
63+
64+
// wrapper to return a HexMapCellId to GDscript
65+
class HexMapCellIdRef : public RefCounted {
66+
GDCLASS(HexMapCellIdRef, RefCounted)
67+
68+
HexMapCellId cell_id;
69+
70+
public:
71+
const HexMapCellId &operator*() const { return cell_id; }
72+
HexMapCellId &operator*() { return cell_id; }
73+
void set(const HexMapCellId &other) { cell_id = other; };
74+
75+
String _to_string();
76+
77+
protected:
78+
static void _bind_methods() {};
79+
};

src/register_types.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,15 @@
3636

3737
#include "hex_map/editor/hex_map_editor_plugin.h"
3838
#include "hex_map/hex_map.h"
39+
#include "hex_map/hex_map_cell_id.h"
3940
#include "test_node.h"
4041
#include "test_node_editor_plugin.h"
4142

4243
using namespace godot;
4344

4445
void initialize_hexmap_module(ModuleInitializationLevel p_level) {
4546
if (p_level == godot::MODULE_INITIALIZATION_LEVEL_SCENE) {
47+
ClassDB::register_class<HexMapCellIdRef>();
4648
ClassDB::register_class<HexMap>();
4749
ClassDB::register_class<TestNode>();
4850
}
@@ -66,14 +68,12 @@ void uninitialize_hexmap_module(ModuleInitializationLevel p_level) {
6668

6769
extern "C" {
6870
// Initialization.
69-
GDExtensionBool GDE_EXPORT
70-
hexmap_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address,
71+
GDExtensionBool GDE_EXPORT hexmap_library_init(
72+
GDExtensionInterfaceGetProcAddress p_get_proc_address,
7173
const GDExtensionClassLibraryPtr p_library,
7274
GDExtensionInitialization *r_initialization) {
7375
godot::GDExtensionBinding::InitObject init_obj(
74-
p_get_proc_address,
75-
p_library,
76-
r_initialization);
76+
p_get_proc_address, p_library, r_initialization);
7777

7878
init_obj.register_initializer(initialize_hexmap_module);
7979
init_obj.register_terminator(uninitialize_hexmap_module);

0 commit comments

Comments
 (0)