diff --git a/autoloads/ngio.gd b/autoloads/ngio.gd index 426f3c2..46bf13b 100644 --- a/autoloads/ngio.gd +++ b/autoloads/ngio.gd @@ -2,10 +2,19 @@ extends Node const GATEWAY_URI: String = "https://newgrounds.io/gateway_v3.php" +const SESSION_FILE: String = "user://ngio.pr" +const EMPTY_SESSION: Dictionary = { + expired = true, + id = "", + passport_url = "", + remember = false, + user = null, +} var app_id: String = "" # app id on newgrounds var aes_key := PoolByteArray([]) # AES-128/Base64 encryption key +var session: Dictionary = EMPTY_SESSION var keys_loaded: bool = false # whether id and key have been loaded from ini file var http := HTTPRequest.new() # http request node @@ -27,6 +36,7 @@ func _ready() -> void: if app_id == "": push_error("Failed to load ngio data. Will not be able to access scoreboards.") keys_loaded = false + return else: keys_loaded = true @@ -41,15 +51,77 @@ func _ready() -> void: # initialize rng for encryption rng.randomize() + + # try to load saved session + if not yield(load_saved_session(), "completed"): + yield(start_new_session(), "completed") -func _test_http() -> void: - print(yield(request_execute("Gateway.getDatetime"), "completed")) +## attempts to load a saved newgrounds.io session +## returns true if the loaded session is valid +func load_saved_session() -> bool: + var ini = ConfigFile.new() + var err = ini.load(SESSION_FILE) + # fail if can't load ngio.pr + if err != OK: + session = EMPTY_SESSION + session.id = ini.get_value("ngio", "session_id", "") + # check session is valid + var response = yield(request_execute("App.checkSession"), "completed") + if has_result(response): + var result = response.result + if result.data.success and not result.data.session.expired: + session = result.data.session + return true + session = EMPTY_SESSION + ini.set_value("ngio", "session_id", "") + ini.save(SESSION_FILE) + return false + + +## start new session +func start_new_session() -> bool: + var response = yield(request_execute("App.startSession"), "completed") + if has_result(response): + var result = response.result + if result.data.success and not result.data.session.expired: + session = result.data.session + return true + session = EMPTY_SESSION + return false + + +## repeatedly checks session until it is logged in or cancelled +func passport_check() -> bool: + # attempt for maximum of 5 minutes + var attempts = 60 + while attempts > 0: + attempts -= 1 + yield(get_tree().create_timer(5.0), "timeout") + var response = yield(request_execute("App.checkSession"), "completed") + if has_result(response): + var result = response.result + if result.data.success: + if result.data.session.user: + session = result.data.session + if session.remember: + var ini = ConfigFile.new() + ini.set_value("ngio", "session_id", session.id) + ini.save(SESSION_FILE) + return true + else: + return false + return false + + +## checks if a response is valid and succeeded +func has_result(response: Dictionary) -> bool: + return "success" in response and response.success ## requests the provided component be executed, do not call async :/ # may call with either single or multiple components -func request_execute(component: String, parameters: Dictionary = {}, session_id: String = "", echo: String = "", encrypt: bool = false) -> Dictionary: +func request_execute(component: String, parameters: Dictionary = {}, echo: String = "", encrypt: bool = false) -> Dictionary: # build request headers var headers = [ "Content-Type: application/x-www-form-urlencoded", @@ -88,7 +160,7 @@ func request_execute(component: String, parameters: Dictionary = {}, session_id: # compose request body var request = { app_id = app_id, - session_id = session_id, + session_id = session.id, execute = execute, } var body = "input=" + to_json(request).percent_encode() @@ -98,6 +170,7 @@ func request_execute(component: String, parameters: Dictionary = {}, session_id: yield(http, "request_completed") return _response + ## called when the HTTPRequest gets a responce func _http_request_completed(result: int, response_code: int, headers: PoolStringArray, body: PoolByteArray) -> void: if response_code == 200: diff --git a/menus/newgrounds_login.gd b/menus/newgrounds_login.gd new file mode 100644 index 0000000..6cfff72 --- /dev/null +++ b/menus/newgrounds_login.gd @@ -0,0 +1,43 @@ +extends Control + +onready var tab_container: TabContainer = $"%TabContainer" + +func _ready() -> void: + visible = false + Fade.fade_out(0.4) + yield(Fade, "fade_finished") + visible = true + yield(get_tree(), "idle_frame") + grab_focus() + Fade.fade_in(0.4) + if not Ngio.keys_loaded: + tab_container.current_tab = 2 + return + if Ngio.session.user == null and not Ngio.session.passport_url.empty(): + var passport_url = Ngio.session.passport_url + # try to open in browser + OS.shell_open(passport_url) + # try to copy to clipboard + OS.clipboard = passport_url + if OS.has_clipboard(): + $"%Clipboard".modulate.a = 1.0 + _await_result() + elif Ngio.session.user != null: + tab_container.current_tab = 1 + else: + tab_container.current_tab = 2 + +func _gui_input(event: InputEvent) -> void: + if event.is_action_pressed("ui_cancel"): + if tab_container.current_tab == 0: + Ngio.request_execute("App.endSession") + queue_free() + elif event.is_action_pressed("ui_accept") and tab_container.current_tab != 0: + queue_free() + +func _await_result() -> void: + var success = yield(Ngio.passport_check(), "completed") + if success: + tab_container.current_tab = 1 + else: + tab_container.current_tab = 2 diff --git a/menus/newgrounds_login.tscn b/menus/newgrounds_login.tscn new file mode 100644 index 0000000..b6e5a1e --- /dev/null +++ b/menus/newgrounds_login.tscn @@ -0,0 +1,95 @@ +[gd_scene load_steps=8 format=2] + +[ext_resource path="res://shaders/ska_plane.gdshader" type="Shader" id=1] +[ext_resource path="res://menus/newgrounds_login.gd" type="Script" id=2] +[ext_resource path="res://ui/theme.tres" type="Theme" id=3] +[ext_resource path="res://ui/2ndpuberty_scholar_outline.fnt" type="BitmapFont" id=4] +[ext_resource path="res://shaders/wibble_wobble.gdshader" type="Shader" id=5] + +[sub_resource type="ShaderMaterial" id=1] +shader = ExtResource( 1 ) +shader_param/color_1 = Color( 1, 0.709804, 0.054902, 1 ) +shader_param/color_2 = Color( 1, 0.945098, 0.478431, 1 ) +shader_param/checker_size = Vector2( 24, 12 ) +shader_param/pan_speed = Vector2( 0, 0 ) +shader_param/cycle_speed = Vector2( 8, -8 ) +shader_param/cycle_alternation = Vector2( 0, 1 ) +shader_param/uv_transform = Transform2D( 1, 1, 1, 1, 0, 0 ) + +[sub_resource type="ShaderMaterial" id=2] +shader = ExtResource( 5 ) +shader_param/speed = Vector2( 8, 4 ) +shader_param/ammount = Vector2( 12, 24 ) +shader_param/offset = Vector2( 0, 0 ) +shader_param/delay = Vector2( 0, 0 ) + +[node name="NewgroundsLogin" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +focus_mode = 2 +script = ExtResource( 2 ) + +[node name="Background" type="ColorRect" parent="."] +material = SubResource( 1 ) +anchor_right = 1.0 +anchor_bottom = 1.0 + +[node name="CenterContainer" type="CenterContainer" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +theme = ExtResource( 3 ) + +[node name="TabContainer" type="TabContainer" parent="CenterContainer"] +unique_name_in_owner = true +margin_left = 23.0 +margin_top = 43.0 +margin_right = 233.0 +margin_bottom = 148.0 +tabs_visible = false + +[node name="Loading" type="VBoxContainer" parent="CenterContainer/TabContainer"] +anchor_right = 1.0 +anchor_bottom = 1.0 +rect_pivot_offset = Vector2( -174, -77 ) + +[node name="Label" type="Label" parent="CenterContainer/TabContainer/Loading"] +margin_right = 210.0 +margin_bottom = 10.0 +custom_fonts/font = ExtResource( 4 ) +text = "Log into newgrounds in browser" +align = 1 + +[node name="LoadingGraphic" type="Label" parent="CenterContainer/TabContainer/Loading"] +material = SubResource( 2 ) +margin_top = 14.0 +margin_right = 210.0 +margin_bottom = 78.0 +rect_min_size = Vector2( 0, 64 ) +text = "ยง" +align = 1 +valign = 1 + +[node name="Clipboard" type="Label" parent="CenterContainer/TabContainer/Loading"] +unique_name_in_owner = true +modulate = Color( 1, 1, 1, 0 ) +margin_top = 82.0 +margin_right = 210.0 +margin_bottom = 105.0 +custom_fonts/font = ExtResource( 4 ) +text = "If browser didn't open, +url copied to clipboard" +align = 1 + +[node name="Success" type="Label" parent="CenterContainer/TabContainer"] +visible = false +anchor_right = 1.0 +anchor_bottom = 1.0 +custom_fonts/font = ExtResource( 4 ) +text = "Success!" + +[node name="Failure" type="Label" parent="CenterContainer/TabContainer"] +visible = false +anchor_right = 1.0 +anchor_bottom = 1.0 +custom_fonts/font = ExtResource( 4 ) +text = "Failure :("