This commit is contained in:
JeroenV26 2025-10-20 14:57:11 +02:00
commit 8e0d737377
16 changed files with 261 additions and 42 deletions

View file

@ -13,6 +13,8 @@ void ClientNode::enter_tree() {
if (singleton_instance) {
print_error("Attempt to create duplicate ClientNode, aborting");
abort();
} else {
singleton_instance = this;
}
}

View file

@ -0,0 +1,54 @@
#include "clue_finder.h"
#include "scene/main/node.h"
#include <core/config/engine.h>
ClueFinder *ClueFinder::singleton_instance{ nullptr };
void ClueFinder::_bind_methods() {}
void ClueFinder::enter_tree() {
if (singleton_instance == nullptr) {
singleton_instance = this;
} else {
queue_free();
}
}
void ClueFinder::exit_tree() {
if (singleton_instance == this) {
singleton_instance = nullptr;
}
}
void ClueFinder::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
switch (what) {
case NOTIFICATION_ENTER_TREE:
enter_tree();
return;
case NOTIFICATION_EXIT_TREE:
exit_tree();
return;
default:
return;
}
}
ClueFinder *ClueFinder::get_singleton() {
return singleton_instance;
}
ClueMarker *ClueFinder::find_current_clue() {
for (ClueMarker *marker : this->clue_markers) {
if (marker->is_visible()) {
return marker;
}
}
return nullptr;
}
void ClueFinder::register_clue_marker(ClueMarker *marker) {
this->clue_markers.insert(marker);
}

View file

@ -0,0 +1,24 @@
#pragma once
#include "clue_marker.h"
#include <core/templates/hash_set.h>
#include <scene/3d/node_3d.h>
class ClueFinder : public Node3D {
GDCLASS(ClueFinder, Node3D);
static void _bind_methods();
static ClueFinder *singleton_instance;
void enter_tree();
void exit_tree();
protected:
void _notification(int what);
public:
static ClueFinder *get_singleton();
ClueMarker *find_current_clue();
void register_clue_marker(ClueMarker *marker);
private:
HashSet<ClueMarker *> clue_markers{};
};

View file

@ -0,0 +1,34 @@
#include "clue_marker.h"
#include "macros.h"
#include "you_done_it/clue_finder.h"
#include "you_done_it/ydi_networking.h"
void ClueMarker::_bind_methods() {
BIND_HPROPERTY(Variant::INT, clue_id, PROPERTY_HINT_ENUM, NetworkData::ClueID_hint());
}
bool ClueMarker::is_visible() const {
Transform3D const viewpoint{ ClueFinder::get_singleton()->get_global_transform() };
Basis const basis{ viewpoint.get_basis() };
Vector3 const pos_relative{ get_global_position() - viewpoint.get_origin() };
Vector3 const pos_transformed{ basis.get_column(0).dot(pos_relative), basis.get_column(1).dot(pos_relative), basis.get_column(2).dot(pos_relative) };
if (pos_transformed.z <= 0.5f) {
return false;
}
Vector3 const transformed_dir{ pos_transformed.normalized() };
if (Math::abs(transformed_dir.signed_angle_to({ 0, 0, 1 }, { 0, 1, 0 })) > Math::PI / 4.0) {
return false;
}
if (Math::abs(transformed_dir.signed_angle_to({ 0, 0, 1 }, { 1, 0, 0 })) > Math::PI / 4.0) {
return false;
}
return true;
}
void ClueMarker::set_clue_id(NetworkData::ClueID id) {
this->id = id;
}
NetworkData::ClueID ClueMarker::get_clue_id() const {
return this->id;
}

View file

@ -0,0 +1,17 @@
#pragma once
#include "ydi_networking.h"
#include <scene/3d/node_3d.h>
class ClueMarker : public Node3D {
GDCLASS(ClueMarker, Node3D);
static void _bind_methods();
public:
bool is_visible() const;
void set_clue_id(NetworkData::ClueID id);
NetworkData::ClueID get_clue_id() const;
private:
NetworkData::ClueID id{ NetworkData::CLUE_MAX };
};

View file

@ -17,4 +17,12 @@
ADD_PROPERTY(PropertyInfo(m_type, #m_property), "set_" #m_property, \
"get_" #m_property)
#define __VA_ARGS__STRING(...) String(#__VA_ARGS__)
#define GDENUM(M_Name, ...) \
enum M_Name { __VA_ARGS__ }; \
static String M_Name##_hint() { \
return __VA_ARGS__STRING(__VA_ARGS__); \
}
#endif // !GODOT_EXTRA_MACROS_H

View file

@ -1,8 +1,11 @@
#include "register_types.h"
#include "client_node.h"
#include "clue_marker.h"
#include "server_node.h"
#include "ydi_networking.h"
#include "ydi_vr_origin.h"
#include "you_done_it/clue_finder.h"
#include <core/object/class_db.h>
void initialize_you_done_it_module(ModuleInitializationLevel p_level) {
@ -12,6 +15,9 @@ void initialize_you_done_it_module(ModuleInitializationLevel p_level) {
ClassDB::register_class<ServerNode>();
ClassDB::register_class<ClientNode>();
ClassDB::register_abstract_class<NetworkData>();
ClassDB::register_class<VROrigin>();
ClassDB::register_class<ClueMarker>();
ClassDB::register_class<ClueFinder>();
}
void uninitialize_you_done_it_module(ModuleInitializationLevel p_level) {

View file

@ -17,9 +17,10 @@ void ServerNode::enter_tree() {
if (singleton_instance) {
print_error("Attempt to create duplicate ServerNode, aborting");
abort();
} else {
singleton_instance = this;
ydi::server::open();
}
singleton_instance = this;
ydi::server::open();
}
void ServerNode::process(double delta) {

View file

@ -132,7 +132,7 @@ void disconnect() {
}
NetworkData::ConnectionStatus status() {
return connection->status;
return connection ? NetworkData::ConnectionStatus(connection->status) : NetworkData::CONNECTION_DISCONNECTED;
}
namespace send {

View file

@ -3,9 +3,6 @@
#include <core/core_bind.h>
#include <core/object/class_db.h>
MAKE_TYPE_INFO(NetworkData::ClueID, Variant::INT);
MAKE_TYPE_INFO(NetworkData::ConnectionStatus, Variant::INT);
void NetworkData::_bind_methods() {
BIND_ENUM_CONSTANT(CLUE_FIRST);
BIND_ENUM_CONSTANT(CLUE_SECOND);

View file

@ -1,5 +1,6 @@
#pragma once
#include "macros.h"
#include <core/object/class_db.h>
#include <core/object/object.h>
#include <zmq.h>
@ -13,31 +14,28 @@ class NetworkData : Object {
static void _bind_methods();
public:
enum MessageType {
MSG_NONE = 0u,
// connection management messages
MSG_CONNECT = 1u,
MSG_OK,
MSG_NOK,
MSG_HEART,
MSG_BEAT,
// gameplay messages
MSG_REVEAL,
// end of messages
MSG_INVALID
};
GDENUM(MessageType,
MSG_NONE,
// connection management messages
MSG_CONNECT,
MSG_OK,
MSG_NOK,
MSG_HEART,
MSG_BEAT,
// gameplay messages
MSG_REVEAL,
// end of messages
MSG_INVALID);
enum ClueID {
CLUE_FIRST,
CLUE_SECOND,
CLUE_MAX
};
GDENUM(ClueID,
CLUE_FIRST,
CLUE_SECOND,
CLUE_MAX);
enum ConnectionStatus {
CONNECTION_DISCONNECTED,
CONNECTION_CONNECTED,
CONNECTION_AUTHENTICATED
};
GDENUM(ConnectionStatus,
CONNECTION_DISCONNECTED,
CONNECTION_CONNECTED,
CONNECTION_AUTHENTICATED);
enum NOKReason {
NOK_UNAUTHENTICATED, //!< message sender is not known by recipient.
@ -48,6 +46,9 @@ public:
};
};
MAKE_TYPE_INFO(NetworkData::ClueID, Variant::INT);
MAKE_TYPE_INFO(NetworkData::ConnectionStatus, Variant::INT);
namespace ydi {
int to_int(zmq::message_t const &msg, int failure = 0);
NetworkData::MessageType to_message_type(zmq::message_t const &msg);
@ -64,19 +65,20 @@ void extend_multipart(zmq::multipart_t &mpart, std::string_view const &strv);
void extend_multipart(zmq::multipart_t &mpart, char const *cstr);
void extend_multipart(zmq::multipart_t &mpart, int const &arg);
void extend_multipart(zmq::multipart_t &mpart, zmq::multipart_t const &right);
void extend_multipart(zmq::multipart_t &mpart);
void extend_multipart(zmq::multipart_t &mpart, std::pair<zmq::multipart_t::iterator, zmq::multipart_t::iterator> range);
void extend_multipart(zmq::multipart_t &mpart, std::pair<zmq::multipart_t::const_iterator, zmq::multipart_t::const_iterator> range);
void extend_multipart(zmq::multipart_t &mpart);
template <typename TArg>
void extend_multipart_r(zmq::multipart_t &mpart, TArg const &arg) {
void extend_multipart_recurse(zmq::multipart_t &mpart, TArg const &arg) {
extend_multipart(mpart, arg);
}
template <typename TArg, typename... TArgs>
void extend_multipart_r(zmq::multipart_t &mpart, TArg const &arg, TArgs const &...args) {
void extend_multipart_recurse(zmq::multipart_t &mpart, TArg const &arg, TArgs const &...args) {
extend_multipart(mpart, arg);
extend_multipart_r(mpart, args...);
extend_multipart_recurse(mpart, args...);
}
template <typename TArg>
@ -89,7 +91,7 @@ zmq::multipart_t multipart(TArg const &arg) {
template <typename TArg, typename... TArgs>
zmq::multipart_t multipart(TArg const &arg, TArgs const &...args) {
zmq::multipart_t mpart{ multipart(arg) };
extend_multipart_r(mpart, args...);
extend_multipart_recurse(mpart, args...);
return mpart;
}
} //namespace ydi

View file

@ -0,0 +1,43 @@
#include "ydi_vr_origin.h"
#include <core/config/engine.h>
#include <scene/main/viewport.h>
#include <servers/xr/xr_interface.h>
#include <servers/xr_server.h>
void VROrigin::_bind_methods() {}
void VROrigin::setup_vr_interface(Ref<XRInterface> with_interface) {
if (with_interface.is_valid()) {
DisplayServer::get_singleton()->window_set_vsync_mode(DisplayServer::VSYNC_DISABLED);
get_viewport()->set_use_xr(true);
}
}
void VROrigin::on_xr_interface_added(StringName interface) {
if (interface == "OpenXR") {
setup_vr_interface(XRServer::get_singleton()->find_interface(interface));
XRServer::get_singleton()->disconnect("interface_added", callable_mp(this, &self_type::on_xr_interface_added));
}
}
void VROrigin::enter_tree() {
Ref<XRInterface> xrint{ XRServer::get_singleton()->find_interface("OpenXR") };
if (xrint.is_valid()) {
setup_vr_interface(xrint);
} else {
XRServer::get_singleton()->connect("interface_added", callable_mp(this, &self_type::on_xr_interface_added));
}
}
void VROrigin::_notification(int what) {
if (Engine::get_singleton()->is_editor_hint()) {
return;
}
switch (what) {
case NOTIFICATION_ENTER_TREE:
enter_tree();
return;
default:
return;
}
}

View file

@ -0,0 +1,17 @@
#pragma once
#include <scene/3d/xr/xr_nodes.h>
#include <servers/xr/xr_interface.h>
class VROrigin : public XROrigin3D {
GDCLASS(VROrigin, XROrigin3D);
static void _bind_methods();
private:
void setup_vr_interface(Ref<XRInterface> with_interface);
void on_xr_interface_added(StringName interface);
void enter_tree();
protected:
void _notification(int what);
};

View file

@ -11,6 +11,7 @@ config_version=5
[application]
config/name="you_done_it"
run/main_scene="uid://b5m5h30gog3pu"
config/features=PackedStringArray("4.5", "Forward Plus")
config/icon="res://icon.svg"

View file

@ -28,6 +28,9 @@ glow_enabled = true
[node name="Root" type="Node3D"]
[node name="VROrigin" parent="." instance=ExtResource("2_onqr8")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0004169941, 0, -0.95417106)
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_bw6k5")
@ -41,15 +44,13 @@ light_angular_distance = 1.0
light_specular = 5.667
light_bake_mode = 1
shadow_enabled = true
shadow_bias = 0.0
shadow_normal_bias = 0.0
shadow_normal_bias = 0.1
shadow_blur = 0.75
directional_shadow_mode = 0
directional_shadow_fade_start = 0.965
directional_shadow_max_distance = 20.0
[node name="XROrigin3D" parent="." instance=ExtResource("2_onqr8")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0004169941, 0, -0.95417106)
[node name="Block Out VR" parent="." instance=ExtResource("1_w5aja")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.27989578, 0, 1.4924412)
[node name="ClueMarker" type="ClueMarker" parent="."]
clue_id = 0

View file

@ -1,13 +1,25 @@
[gd_scene format=3 uid="uid://ctf3dsro4aqon"]
[gd_scene load_steps=2 format=3 uid="uid://ctf3dsro4aqon"]
[node name="XROrigin3D" type="XROrigin3D"]
[sub_resource type="CylinderMesh" id="CylinderMesh_y71p3"]
top_radius = 0.05
bottom_radius = 0.05
height = 0.05
[node name="VROrigin" type="VROrigin"]
[node name="XRCamera3D" type="XRCamera3D" parent="."]
current = true
[node name="LeftController" type="XRController3D" parent="."]
tracker = &"left_hand"
[node name="MeshInstance3D" type="MeshInstance3D" parent="LeftController"]
mesh = SubResource("CylinderMesh_y71p3")
[node name="RightController" type="XRController3D" parent="."]
tracker = &"right_hand"
[node name="MeshInstance3D" type="MeshInstance3D" parent="RightController"]
mesh = SubResource("CylinderMesh_y71p3")
[node name="ClientNode" type="ClientNode" parent="."]