diff --git a/godot/Main.tscn b/godot/Main.tscn index a9c8579..24b4abe 100644 --- a/godot/Main.tscn +++ b/godot/Main.tscn @@ -1,8 +1,11 @@ -[gd_scene load_steps=3 format=2] +[gd_scene load_steps=4 format=2] [ext_resource path="res://Main.gdns" type="Script" id=1] [ext_resource path="res://levels/Level2.tscn" type="PackedScene" id=2] +[ext_resource path="res://monitor/Monitor.tscn" type="PackedScene" id=3] [node name="Main" type="Node"] script = ExtResource( 1 ) level = ExtResource( 2 ) + +[node name="Monitor" parent="." instance=ExtResource( 3 )] diff --git a/godot/monitor/Monitor.gd b/godot/monitor/Monitor.gd new file mode 100644 index 0000000..88dfdfc --- /dev/null +++ b/godot/monitor/Monitor.gd @@ -0,0 +1,250 @@ +extends Node + + +export var development_url: String = "http://localhost:4050/api/v1" +var url_real: String = "https://alai.cromer.cl/api/v1" +export var use_development_url: bool = false +onready var url: String = development_url if use_development_url else url_real + +var player: Dictionary = {} +var level_id: int = 2 # PrototypeR +var os_id: int = 0 +var godot_version: Dictionary = Engine.get_version_info() +var processor_count: int = OS.get_processor_count() +var screen_count: int = OS.get_screen_count() +var screen_dpi: int = OS.get_screen_dpi() +var screen_size: Vector2 = OS.get_screen_size() +var machine_id: String = OS.get_unique_id() +var locale: String = OS.get_locale() +var game_version: String +var won: bool = false +var timestamp: int = OS.get_unix_time() +var frames: Array = [] + +var coins: int = 0 +var points: int = 0 +onready var start_time: int = OS.get_ticks_msec() +var objects: Array = [] + +const empty_object: Dictionary = { + "name": "Object Name", + "state": "Object State", + "position_x": 0, + "position_y": 0, + "velocity_x": 0, + "velocity_y": 0 +} +const empty_frame: Dictionary = { + "coins": 0, + "points": 0, + "fps": 0, + "elapsed_time": 0, + "objects": [], +} + +# The game dictionary holds all data to be sent to the server +var game: Dictionary = {} + + +func _ready() -> void: + game_version = get_parent().game_version + + player["rut"] = "23.660.457-8" + player["name"] = "Chris Cromer" + player["email"] = "chris@cromer.cl" + + var os_name = OS.get_name() + if os_name == "Android": + os_id = 1 + elif os_name == "iOS": + os_id = 2 + elif os_name == "HTML5": + os_id = 3 + elif os_name == "OSX": + os_id = 4 + elif os_name == "Server": + os_id = 5 + elif os_name == "Windows": + os_id = 6 + elif os_name == "UWP": + os_id = 7 + elif os_name == "X11": + os_id = 8 + else: + os_id = 0 + + player["rut"] = clean_rut(player["rut"]) + + game["player"] = player + game["level_id"] = level_id + game["os_id"] = os_id + game["godot_version"] = godot_version + game["processor_count"] = processor_count + game["machine_id"] = machine_id + game["locale"] = locale + game["screen_count"] = screen_count + game["screen_dpi"] = screen_dpi + game["screen_size"] = screen_size + game["game_version"] = game_version + game["won"] = won + game["timestamp"] = timestamp + game["frames"] = frames + + var err = $HTTPRequest.connect("request_completed", self, "_on_request_completed") + if err != OK: + print(err) + + +func _physics_process(_delta: float) -> void: + var frame = empty_frame.duplicate(true) + frame["coins"] = coins + frame["points"] = points + frame["fps"] = Engine.get_frames_per_second() + frame["elapsed_time"] = OS.get_ticks_msec() - start_time + + var frame_objects = objects.duplicate() + frame["objects"] = frame_objects + + frames.append(frame) + + if Input.is_action_just_pressed("Send"): + send_data() + + +func _object_created(name: String, state: String, position: Vector2, velocity: Vector2) -> void: + add_object(name, state, position, velocity) + + +func _object_updated(name: String, state: String, position: Vector2, velocity: Vector2) -> void: + remove_object(name) + add_object(name, state, position, velocity) + + +func _object_removed(name: String) -> void: + remove_object(name) + + +func add_object(name: String, state: String, position: Vector2, velocity: Vector2) -> void: + var object = empty_object.duplicate(true) + object["name"] = name + object["state"] = state + object["position_x"] = position.x + object["position_y"] = position.y + object["velocity_x"] = velocity.x + object["velocity_y"] = velocity.y + + objects.append(object) + + +func remove_object(name: String) -> void: + for i in range(0, objects.size()): + if objects[i]["name"] == name: + objects.remove(i) + + +func _on_coin_update(amount: int) -> void: + coins = coins + amount + + +func _on_request_completed(result: int, response_code: int, headers: PoolStringArray, body: PoolByteArray) -> void: + if result != HTTPRequest.RESULT_SUCCESS: + print_debug("Error: Failed to connect with error code: " + str(result)) + return + + if response_code != HTTPClient.RESPONSE_OK: + print_debug("Error: Failed response with error code: " + str(response_code)) + + print_debug(headers) + if body.size() > 0: + var json = JSON.parse(body.get_string_from_utf8()) + print_debug(JSON.print(json.result, "\t")) + + +func send_data() -> void: + var json = JSON.print(game) + var headers = ["Content-Type: application/json", "Content-Encoding: gzip", "Content-Transfer-Encoding: base64"] + + var body = compress_payload(json) + + print("JSON B: " + String(json.length())) + print("JSON MB: " + String(json.length() / pow(2, 20))) + print("Body B: " + String(body.length())) + print("Body MB: " + String(body.length() / pow(2, 20))) + + $HTTPRequest.request(url + "/game", headers, false, HTTPClient.METHOD_POST, body) + + +func compress_payload(payload: String) -> String: + var bytes = payload.to_utf8() + var compressed = bytes.compress(File.COMPRESSION_GZIP) + + var new_payload = Marshalls.raw_to_base64(compressed) + + return new_payload + + +func clean_rut(rut: String) -> String: + rut = rut.strip_escapes() + rut = rut.strip_edges(true, true) + rut = rut.to_lower() + rut = rut.replace(".", "") + rut = rut.replace("-", "") + return rut + + +func is_rut_valid(rut: String) -> bool: + rut = clean_rut(rut) + if rut.length() < 8 or rut.length() > 9: + print_debug("RUT length is invalid!") + return false + + var rutTemp: String = rut.substr(0, rut.length() - 1) + var verifier: String = rut.substr(rut.length() - 1, 1) + print("Rut: " + rutTemp) + print("Verifier: " + verifier) + + if not rutTemp.is_valid_integer(): + print_debug("RUT isn't a valid integer!") + return false + + if rutTemp.to_int() > 50000000: + print_debug("RUT is too large, that is a company!") + return false + + if verifier != generate_verifier(rut): + return false + + return true + + +func generate_verifier(rut: String) -> String: + if not rut.is_valid_integer(): + print_debug("RUT isn't a valid integer!") + return "" + + var multiplier: int = 2 + var sum: int = 0 + var remainder: int = 0 + var division: int = 0 + var rutLength: int = rut.length() + + var i: int = rutLength - 1 + while i >= 0: + sum = sum + rut.substr(i, i + 1).to_int() * multiplier + multiplier = multiplier + 1 + if multiplier == 8: + multiplier = 2 + i = i - 1 + + var tempSum: float = int(sum) + division = int(floor(tempSum / 11)) + division = division * 11 + remainder = sum - division + + if remainder != 0: + remainder = 11 - remainder + + if remainder == 10: + return "k" + else: + return String(remainder) diff --git a/godot/monitor/Monitor.tscn b/godot/monitor/Monitor.tscn index 94361cb..736faa8 100644 --- a/godot/monitor/Monitor.tscn +++ b/godot/monitor/Monitor.tscn @@ -1,5 +1,9 @@ -[gd_scene format=2] +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://monitor/Monitor.gd" type="Script" id=1] [node name="Monitor" type="Node"] +script = ExtResource( 1 ) +use_development_url = true -[node name="Sender" type="Node" parent="."] +[node name="HTTPRequest" type="HTTPRequest" parent="."] diff --git a/src/Main.cpp b/src/Main.cpp index 4f91c0c..59f5378 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -9,6 +9,7 @@ void Main::_register_methods() { register_method("_ready", &Main::_ready); register_method("_physics_process", &Main::_physics_process); + register_property("game_version", &Main::set_game_version, &Main::get_game_version, String(main::game_version.c_str())); register_property>("level", &Main::set_level, &Main::get_level, NULL, GODOT_METHOD_RPC_MODE_DISABLED, GODOT_PROPERTY_USAGE_DEFAULT, GODOT_PROPERTY_HINT_RESOURCE_TYPE, String("PackedScene")); register_property("full_screen", &Main::set_full_screen, &Main::get_full_screen, main::full_screen); register_property("window_size", &Main::set_window_size, &Main::get_window_size, main::window_size); @@ -28,6 +29,7 @@ void Main::_init() _os = OS::get_singleton(); _input = Input::get_singleton(); + game_version = String(main::game_version.c_str()); full_screen = main::full_screen; window_size = main::window_size; launch_screen = main::launch_screen; @@ -71,6 +73,16 @@ Ref Main::get_level() return this->level; } +void Main::set_game_version(String game_version) +{ + this->game_version = game_version; +} + +String Main::get_game_version() +{ + return this->game_version; +} + void Main::set_full_screen(bool full_screen) { this->full_screen = full_screen; diff --git a/src/Main.h b/src/Main.h index d89c5c9..b9270a9 100644 --- a/src/Main.h +++ b/src/Main.h @@ -1,6 +1,7 @@ #ifndef ALAI_MAIN_H #define ALAI_MAIN_H +#include #include #include #include @@ -21,6 +22,11 @@ namespace godot */ namespace main { + /** + * @brief The default value for the game version. + * + */ + const std::string game_version = "0.1.0"; /** * @brief The default value for if the game should start in full screen. * @@ -64,6 +70,11 @@ namespace godot * */ Ref level; + /** + * @brief The current version of the game. + * + */ + String game_version; /** * @brief If the window is full screen or not. * @@ -137,6 +148,20 @@ namespace godot */ Ref get_level(); + /** + * @brief Set the game version object. + * + * @param[in] game_version The new version fo the game. + */ + void set_game_version(String game_version); + + /** + * @brief Get the game version object. + * + * @return String The current version of the game. + */ + String get_game_version(); + /** * @brief Set the full screen object. * diff --git a/src/player/Player.cpp b/src/player/Player.cpp index 843043b..b820fdf 100644 --- a/src/player/Player.cpp +++ b/src/player/Player.cpp @@ -5,6 +5,7 @@ #include #include #include +#include using namespace godot; using namespace player; @@ -21,6 +22,9 @@ void Player::_register_methods() register_property("gravity", &Player::set_gravity, &Player::get_gravity, player::gravity); register_property("run_speed", &Player::set_run_speed, &Player::get_run_speed, player::run_speed); register_property("double_jump", &Player::set_double_jump, &Player::get_double_jump, player::double_jump); + register_signal("object_created", "name", GODOT_VARIANT_TYPE_STRING, "state", GODOT_VARIANT_TYPE_STRING, "position", GODOT_VARIANT_TYPE_VECTOR2, "velocity", GODOT_VARIANT_TYPE_VECTOR2); + register_signal("object_updated", "name", GODOT_VARIANT_TYPE_STRING, "state", GODOT_VARIANT_TYPE_STRING, "position", GODOT_VARIANT_TYPE_VECTOR2, "velocity", GODOT_VARIANT_TYPE_VECTOR2); + register_signal("object_removed", "name", GODOT_VARIANT_TYPE_STRING); } Player::Player() @@ -58,7 +62,6 @@ void Player::_ready() //animated_sprite->set_sprite_frames(sprite_frames); auto node = get_parent()->find_node("Middleground"); - if (node != nullptr) { auto tile_map = Object::cast_to(node); @@ -69,6 +72,27 @@ void Player::_ready() { WARN_PRINT("Middleground not found!"); } + + auto object_node = get_tree()->get_root()->get_node("Main")->find_node("Monitor"); + if (object_node != nullptr) + { + auto state = get_node("StateMachine")->get_child(0); + if (state != nullptr) + { + connect("object_created", object_node, "_object_created"); + connect("object_updated", object_node, "_object_updated"); + connect("object_removed", object_node, "_object_removed"); + emit_signal("object_created", this->get_name(), state->get_name(), get_global_position(), velocity); + } + else + { + WARN_PRINT("State not found!"); + } + } + else + { + WARN_PRINT("Data not found!"); + } } void Player::_physics_process(float delta) @@ -110,6 +134,16 @@ void Player::_physics_process(float delta) } } } + + auto state = get_node("StateMachine")->get_child(0); + if (state != nullptr) + { + emit_signal("object_updated", this->get_name(), state->get_name(), get_global_position(), velocity); + } + else + { + WARN_PRINT("State not found!"); + } } void Player::set_sprite_frames(Ref sprite_frames)