mirror of
https://github.com/godotengine/godot-demo-projects.git
synced 2026-01-06 07:50:22 +01:00
Code cleanup
This commit is contained in:
@@ -5,18 +5,18 @@ var from_player
|
||||
|
||||
# Called from the animation
|
||||
func explode():
|
||||
if (not is_network_master()):
|
||||
if not is_network_master():
|
||||
# But will call explosion only on master
|
||||
return
|
||||
for p in in_area:
|
||||
if (p.has_method("exploded")):
|
||||
if p.has_method("exploded"):
|
||||
p.rpc("exploded", from_player) # Exploded has a master keyword, so it will only be received by the master
|
||||
|
||||
func done():
|
||||
queue_free()
|
||||
|
||||
func _on_bomb_body_enter(body):
|
||||
if (not body in in_area):
|
||||
if not body in in_area:
|
||||
in_area.append(body)
|
||||
|
||||
func _on_bomb_body_exit(body):
|
||||
|
||||
@@ -27,8 +27,8 @@ func _player_connected(id):
|
||||
|
||||
# Callback from SceneTree
|
||||
func _player_disconnected(id):
|
||||
if (get_tree().is_network_server()):
|
||||
if (has_node("/root/world")): # Game is in progress
|
||||
if get_tree().is_network_server():
|
||||
if has_node("/root/world"): # Game is in progress
|
||||
emit_signal("game_error", "Player " + players[id] + " disconnected")
|
||||
end_game()
|
||||
else: # Game is not in progress
|
||||
@@ -57,7 +57,7 @@ func _connected_fail():
|
||||
# Lobby management functions
|
||||
|
||||
remote func register_player(id, new_player_name):
|
||||
if (get_tree().is_network_server()):
|
||||
if get_tree().is_network_server():
|
||||
# If we are the server, let everyone know about the new player
|
||||
rpc_id(id, "register_player", 1, player_name) # Send myself to new dude
|
||||
for p_id in players: # Then, for each remote player
|
||||
@@ -88,7 +88,7 @@ remote func pre_start_game(spawn_points):
|
||||
player.position=spawn_pos
|
||||
player.set_network_master(p_id) #set unique id as master
|
||||
|
||||
if (p_id == get_tree().get_network_unique_id()):
|
||||
if p_id == get_tree().get_network_unique_id():
|
||||
# If node for this peer id, set name
|
||||
player.set_player_name(player_name)
|
||||
else:
|
||||
@@ -102,7 +102,7 @@ remote func pre_start_game(spawn_points):
|
||||
for pn in players:
|
||||
world.get_node("score").add_player(pn, players[pn])
|
||||
|
||||
if (not get_tree().is_network_server()):
|
||||
if not get_tree().is_network_server():
|
||||
# Tell server we are ready to start
|
||||
rpc_id(1, "ready_to_start", get_tree().get_network_unique_id())
|
||||
elif players.size() == 0:
|
||||
@@ -116,10 +116,10 @@ var players_ready = []
|
||||
remote func ready_to_start(id):
|
||||
assert(get_tree().is_network_server())
|
||||
|
||||
if (not id in players_ready):
|
||||
if not id in players_ready:
|
||||
players_ready.append(id)
|
||||
|
||||
if (players_ready.size() == players.size()):
|
||||
if players_ready.size() == players.size():
|
||||
for p in players:
|
||||
rpc_id(p, "post_start_game")
|
||||
post_start_game()
|
||||
@@ -159,7 +159,7 @@ func begin_game():
|
||||
pre_start_game(spawn_points)
|
||||
|
||||
func end_game():
|
||||
if (has_node("/root/world")): # Game is in progress
|
||||
if has_node("/root/world"): # Game is in progress
|
||||
# End it
|
||||
get_node("/root/world").queue_free()
|
||||
|
||||
|
||||
@@ -9,31 +9,31 @@ func _ready():
|
||||
gamestate.connect("game_error", self, "_on_game_error")
|
||||
|
||||
func _on_host_pressed():
|
||||
if (get_node("connect/name").text == ""):
|
||||
get_node("connect/error_label").text="Invalid name!"
|
||||
if get_node("connect/name").text == "":
|
||||
get_node("connect/error_label").text = "Invalid name!"
|
||||
return
|
||||
|
||||
get_node("connect").hide()
|
||||
get_node("players").show()
|
||||
get_node("connect/error_label").text=""
|
||||
get_node("connect/error_label").text = ""
|
||||
|
||||
var player_name = get_node("connect/name").text
|
||||
gamestate.host_game(player_name)
|
||||
refresh_lobby()
|
||||
|
||||
func _on_join_pressed():
|
||||
if (get_node("connect/name").text == ""):
|
||||
get_node("connect/error_label").text="Invalid name!"
|
||||
if get_node("connect/name").text == "":
|
||||
get_node("connect/error_label").text = "Invalid name!"
|
||||
return
|
||||
|
||||
var ip = get_node("connect/ip").text
|
||||
if (not ip.is_valid_ip_address()):
|
||||
get_node("connect/error_label").text="Invalid IPv4 address!"
|
||||
if not ip.is_valid_ip_address():
|
||||
get_node("connect/error_label").text = "Invalid IPv4 address!"
|
||||
return
|
||||
|
||||
get_node("connect/error_label").text=""
|
||||
get_node("connect/host").disabled=true
|
||||
get_node("connect/join").disabled=true
|
||||
get_node("connect/host").disabled = true
|
||||
get_node("connect/join").disabled = true
|
||||
|
||||
var player_name = get_node("connect/name").text
|
||||
gamestate.join_game(ip, player_name)
|
||||
@@ -44,15 +44,15 @@ func _on_connection_success():
|
||||
get_node("players").show()
|
||||
|
||||
func _on_connection_failed():
|
||||
get_node("connect/host").disabled=false
|
||||
get_node("connect/join").disabled=false
|
||||
get_node("connect/host").disabled = false
|
||||
get_node("connect/join").disabled = false
|
||||
get_node("connect/error_label").set_text("Connection failed.")
|
||||
|
||||
func _on_game_ended():
|
||||
show()
|
||||
get_node("connect").show()
|
||||
get_node("players").hide()
|
||||
get_node("connect/host").disabled=false
|
||||
get_node("connect/host").disabled = false
|
||||
get_node("connect/join").disabled
|
||||
|
||||
func _on_game_error(errtxt):
|
||||
@@ -67,7 +67,7 @@ func refresh_lobby():
|
||||
for p in players:
|
||||
get_node("players/list").add_item(p)
|
||||
|
||||
get_node("players/start").disabled=not get_tree().is_network_server()
|
||||
get_node("players/start").disabled = not get_tree().is_network_server()
|
||||
|
||||
func _on_start_pressed():
|
||||
gamestate.begin_game()
|
||||
|
||||
@@ -11,7 +11,7 @@ export var stunned = false
|
||||
sync func setup_bomb(bomb_name, pos, by_who):
|
||||
var bomb = preload("res://bomb.tscn").instance()
|
||||
bomb.set_name(bomb_name) # Ensure unique name for the bomb
|
||||
bomb.position=pos
|
||||
bomb.position = pos
|
||||
bomb.from_player = by_who
|
||||
# No need to set network mode to bomb, will be owned by master by default
|
||||
get_node("../..").add_child(bomb)
|
||||
@@ -23,23 +23,23 @@ var bomb_index = 0
|
||||
func _physics_process(delta):
|
||||
var motion = Vector2()
|
||||
|
||||
if (is_network_master()):
|
||||
if (Input.is_action_pressed("move_left")):
|
||||
if is_network_master():
|
||||
if Input.is_action_pressed("move_left"):
|
||||
motion += Vector2(-1, 0)
|
||||
if (Input.is_action_pressed("move_right")):
|
||||
if Input.is_action_pressed("move_right"):
|
||||
motion += Vector2(1, 0)
|
||||
if (Input.is_action_pressed("move_up")):
|
||||
if Input.is_action_pressed("move_up"):
|
||||
motion += Vector2(0, -1)
|
||||
if (Input.is_action_pressed("move_down")):
|
||||
if Input.is_action_pressed("move_down"):
|
||||
motion += Vector2(0, 1)
|
||||
|
||||
var bombing = Input.is_action_pressed("set_bomb")
|
||||
|
||||
if (stunned):
|
||||
if stunned:
|
||||
bombing = false
|
||||
motion = Vector2()
|
||||
|
||||
if (bombing and not prev_bombing):
|
||||
if bombing and not prev_bombing:
|
||||
var bomb_name = get_name() + str(bomb_index)
|
||||
var bomb_pos = position
|
||||
rpc("setup_bomb", bomb_name, bomb_pos, get_tree().get_network_unique_id())
|
||||
@@ -49,36 +49,36 @@ func _physics_process(delta):
|
||||
rset("slave_motion", motion)
|
||||
rset("slave_pos", position)
|
||||
else:
|
||||
position=slave_pos
|
||||
position = slave_pos
|
||||
motion = slave_motion
|
||||
|
||||
var new_anim = "standing"
|
||||
if (motion.y < 0):
|
||||
if motion.y < 0:
|
||||
new_anim = "walk_up"
|
||||
elif (motion.y > 0):
|
||||
elif motion.y > 0:
|
||||
new_anim = "walk_down"
|
||||
elif (motion.x < 0):
|
||||
elif motion.x < 0:
|
||||
new_anim = "walk_left"
|
||||
elif (motion.x > 0):
|
||||
elif motion.x > 0:
|
||||
new_anim = "walk_right"
|
||||
|
||||
if (stunned):
|
||||
if stunned:
|
||||
new_anim = "stunned"
|
||||
|
||||
if (new_anim != current_anim):
|
||||
if new_anim != current_anim:
|
||||
current_anim = new_anim
|
||||
get_node("anim").play(current_anim)
|
||||
|
||||
# FIXME: Use move_and_slide
|
||||
move_and_slide(motion*MOTION_SPEED)
|
||||
if (not is_network_master()):
|
||||
move_and_slide(motion * MOTION_SPEED)
|
||||
if not is_network_master():
|
||||
slave_pos = position # To avoid jitter
|
||||
|
||||
slave func stun():
|
||||
stunned = true
|
||||
|
||||
master func exploded(by_who):
|
||||
if (stunned):
|
||||
if stunned:
|
||||
return
|
||||
rpc("stun") # Stun slaves
|
||||
stun() # Stun master - could use sync to do both at once
|
||||
|
||||
@@ -4,11 +4,11 @@ var player_labels = {}
|
||||
|
||||
func _process(delta):
|
||||
var rocks_left = get_node("../rocks").get_child_count()
|
||||
if (rocks_left == 0):
|
||||
if rocks_left == 0:
|
||||
var winner_name = ""
|
||||
var winner_score = 0
|
||||
for p in player_labels:
|
||||
if (player_labels[p].score > winner_score):
|
||||
if player_labels[p].score > winner_score:
|
||||
winner_score = player_labels[p].score
|
||||
winner_name = player_labels[p].name
|
||||
|
||||
|
||||
@@ -1,72 +1,68 @@
|
||||
|
||||
extends Area2D
|
||||
|
||||
const DEFAULT_SPEED=80
|
||||
const DEFAULT_SPEED = 80
|
||||
|
||||
var direction = Vector2(1,0)
|
||||
var direction = Vector2(1, 0)
|
||||
var ball_speed = DEFAULT_SPEED
|
||||
var stopped=false
|
||||
|
||||
var stopped = false
|
||||
|
||||
|
||||
onready var screen_size = get_viewport_rect().size
|
||||
|
||||
|
||||
sync func _reset_ball(for_left):
|
||||
|
||||
position = screen_size /2
|
||||
if (for_left):
|
||||
direction = Vector2(-1,0)
|
||||
if for_left:
|
||||
direction = Vector2(-1, 0)
|
||||
else:
|
||||
direction = Vector2( 1,0)
|
||||
direction = Vector2(1, 0)
|
||||
|
||||
ball_speed = DEFAULT_SPEED
|
||||
|
||||
sync func stop():
|
||||
stopped=true
|
||||
|
||||
func _process(delta):
|
||||
|
||||
sync func stop():
|
||||
stopped = true
|
||||
|
||||
|
||||
func _process(delta):
|
||||
# ball will move normally for both players
|
||||
# even if it's sightly out of sync between them
|
||||
# so each player sees the motion as smooth and not jerky
|
||||
|
||||
if (not stopped):
|
||||
if not stopped:
|
||||
translate( direction * ball_speed * delta )
|
||||
|
||||
# check screen bounds to make ball bounce
|
||||
|
||||
var ball_pos = position
|
||||
if ((ball_pos.y < 0 and direction.y < 0) or (ball_pos.y > screen_size.y and direction.y > 0)):
|
||||
if (ball_pos.y < 0 and direction.y < 0) or (ball_pos.y > screen_size.y and direction.y > 0):
|
||||
direction.y = -direction.y
|
||||
|
||||
if (is_network_master()):
|
||||
if is_network_master():
|
||||
# only master will decide when the ball is out in the left side (it's own side)
|
||||
# this makes the game playable even if latency is high and ball is going fast
|
||||
# otherwise ball might be out in the other player's screen but not this one
|
||||
|
||||
if (ball_pos.x < 0 ):
|
||||
get_parent().rpc("update_score",false)
|
||||
rpc("_reset_ball",false)
|
||||
if ball_pos.x < 0:
|
||||
get_parent().rpc("update_score", false)
|
||||
rpc("_reset_ball", false)
|
||||
else:
|
||||
# only the slave will decide when the ball is out in the right side (it's own side)
|
||||
# this makes the game playable even if latency is high and ball is going fast
|
||||
# otherwise ball might be out in the other player's screen but not this one
|
||||
|
||||
if (ball_pos.x > screen_size.x):
|
||||
get_parent().rpc("update_score",true)
|
||||
rpc("_reset_ball",true)
|
||||
if ball_pos.x > screen_size.x:
|
||||
get_parent().rpc("update_score", true)
|
||||
rpc("_reset_ball", true)
|
||||
|
||||
|
||||
sync func bounce(left,random):
|
||||
|
||||
sync func bounce(left, random):
|
||||
#using sync because both players can make it bounce
|
||||
if (left):
|
||||
if left:
|
||||
direction.x = abs(direction.x)
|
||||
else:
|
||||
direction.x = -abs(direction.x)
|
||||
|
||||
ball_speed *= 1.1
|
||||
direction.y = random*2.0 - 1
|
||||
direction.y = random * 2.0 - 1
|
||||
direction = direction.normalized()
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
extends Control
|
||||
|
||||
const DEFAULT_PORT = 8910 # some random number, pick your port properly
|
||||
@@ -9,14 +8,14 @@ const DEFAULT_PORT = 8910 # some random number, pick your port properly
|
||||
func _player_connected(id):
|
||||
#someone connected, start the game!
|
||||
var pong = load("res://pong.tscn").instance()
|
||||
pong.connect("game_finished",self,"_end_game",[],CONNECT_DEFERRED) # connect deferred so we can safely erase it from the callback
|
||||
pong.connect("game_finished", self, "_end_game", [], CONNECT_DEFERRED) # connect deferred so we can safely erase it from the callback
|
||||
|
||||
get_tree().get_root().add_child(pong)
|
||||
hide()
|
||||
|
||||
func _player_disconnected(id):
|
||||
|
||||
if (get_tree().is_network_server()):
|
||||
if get_tree().is_network_server():
|
||||
_end_game("Client disconnected")
|
||||
else:
|
||||
_end_game("Server disconnected")
|
||||
@@ -42,7 +41,7 @@ func _server_disconnected():
|
||||
##### Game creation functions ######
|
||||
|
||||
func _end_game(with_error=""):
|
||||
if (has_node("/root/pong")):
|
||||
if has_node("/root/pong"):
|
||||
#erase pong scene
|
||||
get_node("/root/pong").free() # erase immediately, otherwise network might show errors (this is why we connected deferred above)
|
||||
show()
|
||||
@@ -52,11 +51,11 @@ func _end_game(with_error=""):
|
||||
get_node("panel/join").set_disabled(false)
|
||||
get_node("panel/host").set_disabled(false)
|
||||
|
||||
_set_status(with_error,false)
|
||||
_set_status(with_error, false)
|
||||
|
||||
func _set_status(text,isok):
|
||||
func _set_status(text, isok):
|
||||
#simple way to show status
|
||||
if (isok):
|
||||
if isok:
|
||||
get_node("panel/status_ok").set_text(text)
|
||||
get_node("panel/status_fail").set_text("")
|
||||
else:
|
||||
@@ -64,11 +63,10 @@ func _set_status(text,isok):
|
||||
get_node("panel/status_fail").set_text(text)
|
||||
|
||||
func _on_host_pressed():
|
||||
|
||||
var host = NetworkedMultiplayerENet.new()
|
||||
host.set_compression_mode(NetworkedMultiplayerENet.COMPRESS_RANGE_CODER)
|
||||
var err = host.create_server(DEFAULT_PORT,1) # max: 1 peer, since it's a 2 players game
|
||||
if (err!=OK):
|
||||
var err = host.create_server(DEFAULT_PORT, 1) # max: 1 peer, since it's a 2 players game
|
||||
if err != OK:
|
||||
#is another server running?
|
||||
_set_status("Can't host, address in use.",false)
|
||||
return
|
||||
@@ -76,31 +74,29 @@ func _on_host_pressed():
|
||||
get_tree().set_network_peer(host)
|
||||
get_node("panel/join").set_disabled(true)
|
||||
get_node("panel/host").set_disabled(true)
|
||||
_set_status("Waiting for player..",true)
|
||||
_set_status("Waiting for player..", true)
|
||||
|
||||
func _on_join_pressed():
|
||||
|
||||
var ip = get_node("panel/address").get_text()
|
||||
if (not ip.is_valid_ip_address()):
|
||||
_set_status("IP address is invalid",false)
|
||||
if not ip.is_valid_ip_address():
|
||||
_set_status("IP address is invalid", false)
|
||||
return
|
||||
|
||||
var host = NetworkedMultiplayerENet.new()
|
||||
host.set_compression_mode(NetworkedMultiplayerENet.COMPRESS_RANGE_CODER)
|
||||
host.create_client(ip,DEFAULT_PORT)
|
||||
host.create_client(ip, DEFAULT_PORT)
|
||||
get_tree().set_network_peer(host)
|
||||
|
||||
_set_status("Connecting..",true)
|
||||
|
||||
_set_status("Connecting..", true)
|
||||
|
||||
|
||||
### INITIALIZER ####
|
||||
|
||||
func _ready():
|
||||
# connect all the callbacks related to networking
|
||||
get_tree().connect("network_peer_connected",self,"_player_connected")
|
||||
get_tree().connect("network_peer_disconnected",self,"_player_disconnected")
|
||||
get_tree().connect("connected_to_server",self,"_connected_ok")
|
||||
get_tree().connect("connection_failed",self,"_connected_fail")
|
||||
get_tree().connect("server_disconnected",self,"_server_disconnected")
|
||||
get_tree().connect("network_peer_connected", self, "_player_connected")
|
||||
get_tree().connect("network_peer_disconnected", self, "_player_disconnected")
|
||||
get_tree().connect("connected_to_server", self, "_connected_ok")
|
||||
get_tree().connect("connection_failed", self, "_connected_fail")
|
||||
get_tree().connect("server_disconnected", self, "_server_disconnected")
|
||||
|
||||
|
||||
@@ -5,62 +5,51 @@ export var left=false
|
||||
const MOTION_SPEED=150
|
||||
|
||||
var motion = 0
|
||||
var you_hidden=false
|
||||
var you_hidden = false
|
||||
|
||||
onready var screen_size = get_viewport_rect().size
|
||||
|
||||
#synchronize position and speed to the other peers
|
||||
slave func set_pos_and_motion(p_pos,p_motion):
|
||||
position=p_pos
|
||||
motion=p_motion
|
||||
slave func set_pos_and_motion(p_pos, p_motion):
|
||||
position = p_pos
|
||||
motion = p_motion
|
||||
|
||||
func _hide_you_label():
|
||||
you_hidden=true
|
||||
you_hidden = true
|
||||
get_node("you").hide()
|
||||
|
||||
func _process(delta):
|
||||
|
||||
#is the master of the paddle
|
||||
if (is_network_master()):
|
||||
|
||||
if is_network_master():
|
||||
motion = 0
|
||||
if (Input.is_action_pressed("move_up")):
|
||||
if Input.is_action_pressed("move_up"):
|
||||
motion -= 1
|
||||
elif (Input.is_action_pressed("move_down")):
|
||||
elif Input.is_action_pressed("move_down"):
|
||||
motion += 1
|
||||
|
||||
if (not you_hidden and motion!=0):
|
||||
if not you_hidden and motion != 0:
|
||||
_hide_you_label()
|
||||
|
||||
|
||||
motion*=MOTION_SPEED
|
||||
|
||||
motion *= MOTION_SPEED
|
||||
|
||||
#using unreliable to make sure position is updated as fast as possible, even if one of the calls is dropped
|
||||
rpc_unreliable("set_pos_and_motion",position,motion)
|
||||
rpc_unreliable("set_pos_and_motion", position, motion)
|
||||
|
||||
else:
|
||||
if (not you_hidden):
|
||||
if not you_hidden:
|
||||
_hide_you_label()
|
||||
|
||||
|
||||
|
||||
translate( Vector2(0,motion*delta) )
|
||||
|
||||
# set screen limits
|
||||
|
||||
var pos = position
|
||||
|
||||
if (pos.y < 0 ):
|
||||
position = Vector2( pos.x, 0)
|
||||
elif (pos.y > screen_size.y):
|
||||
position = Vector2( pos.x, screen_size.y)
|
||||
|
||||
if pos.y < 0:
|
||||
position = Vector2(pos.x, 0)
|
||||
elif pos.y > screen_size.y:
|
||||
position = Vector2(pos.x, screen_size.y)
|
||||
|
||||
|
||||
func _on_paddle_area_enter( area ):
|
||||
|
||||
if (is_network_master()):
|
||||
area.rpc("bounce",left,randf()) #random for new direction generated on each peer
|
||||
|
||||
|
||||
|
||||
|
||||
if is_network_master():
|
||||
area.rpc("bounce", left, randf()) #random for new direction generated on each peer
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
|
||||
extends Node2D
|
||||
|
||||
const SCORE_TO_WIN=10
|
||||
const SCORE_TO_WIN = 10
|
||||
|
||||
var score_left = 0
|
||||
var score_right = 0
|
||||
@@ -9,25 +8,24 @@ var score_right = 0
|
||||
signal game_finished()
|
||||
|
||||
sync func update_score(add_to_left):
|
||||
if (add_to_left):
|
||||
|
||||
score_left+=1
|
||||
get_node("score_left").set_text( str(score_left) )
|
||||
if add_to_left:
|
||||
score_left += 1
|
||||
get_node("score_left").set_text(str(score_left))
|
||||
else:
|
||||
|
||||
score_right+=1
|
||||
get_node("score_right").set_text( str(score_right) )
|
||||
score_right += 1
|
||||
get_node("score_right").set_text(str(score_right))
|
||||
|
||||
var game_ended = false
|
||||
|
||||
if (score_left==SCORE_TO_WIN):
|
||||
if score_left == SCORE_TO_WIN:
|
||||
get_node("winner_left").show()
|
||||
game_ended=true
|
||||
elif (score_right==SCORE_TO_WIN):
|
||||
game_ended = true
|
||||
elif score_right == SCORE_TO_WIN:
|
||||
get_node("winner_right").show()
|
||||
game_ended=true
|
||||
game_ended = true
|
||||
|
||||
if (game_ended):
|
||||
if game_ended:
|
||||
get_node("exit_game").show()
|
||||
get_node("ball").rpc("stop")
|
||||
|
||||
@@ -35,11 +33,9 @@ func _on_exit_game_pressed():
|
||||
emit_signal("game_finished")
|
||||
|
||||
func _ready():
|
||||
|
||||
# by default, all nodes in server inherit from master
|
||||
# while all nodes in clients inherit from slave
|
||||
|
||||
if (get_tree().is_network_server()):
|
||||
if get_tree().is_network_server():
|
||||
#if in the server, get control of player 2 to the other peeer, this function is tree recursive by default
|
||||
get_node("player2").set_network_master(get_tree().get_network_connected_peers()[0])
|
||||
else:
|
||||
@@ -47,6 +43,6 @@ func _ready():
|
||||
get_node("player2").set_network_master(get_tree().get_network_unique_id())
|
||||
|
||||
#let each paddle know which one is left, too
|
||||
get_node("player1").left=true
|
||||
get_node("player2").left=false
|
||||
print("unique id: ",get_tree().get_network_unique_id())
|
||||
get_node("player1").left = true
|
||||
get_node("player2").left = false
|
||||
print("unique id: ", get_tree().get_network_unique_id())
|
||||
|
||||
Reference in New Issue
Block a user