Compare commits
3 Commits
8ccbc2bc14
...
b0682d1f74
Author | SHA1 | Date | |
---|---|---|---|
b0682d1f74 | |||
995af011b7 | |||
518340ebdb |
46
xiaofang/Assets/Script/DirllInterface/bindPlayer.cs
Normal file
46
xiaofang/Assets/Script/DirllInterface/bindPlayer.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class bindPlayer : MonoBehaviour
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 创建请求头,使用最新的 token
|
||||||
|
public Dictionary<string, string> CreateHeaders()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(Global.global.loginResponse.data.access_token))
|
||||||
|
{
|
||||||
|
Debug.LogWarning("尝试创建请求头时,token 未设置。");
|
||||||
|
return new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "Authorization","Bearer "+Global.global.loginResponse.data.access_token },
|
||||||
|
{"clientId", "e5cd7e4891bf95d1d19206ce24a7b32e" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//模板玩家绑定
|
||||||
|
public async void BindPlayer(bindPlayerBody bindPlayerBody)
|
||||||
|
{
|
||||||
|
bindPlayerBody bindPlayerBody1 = new bindPlayerBody();
|
||||||
|
bindPlayerBody1 = bindPlayerBody;
|
||||||
|
|
||||||
|
string response = await web.SendRequest(web.URL + "/game/gameTemplate/player", "POST", JsonConvert.SerializeObject(bindPlayerBody1), CreateHeaders());
|
||||||
|
Debug.Log("模板玩家绑定: " + response);
|
||||||
|
BindPlayer serverData = JsonConvert.DeserializeObject<BindPlayer>(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//=====请求体====================================================================================
|
||||||
|
public class bindPlayerBody
|
||||||
|
{
|
||||||
|
string templateId;//===============必须
|
||||||
|
PlayerList[] playerList;//见createTemplate.cs第37行//=========必须
|
||||||
|
}
|
11
xiaofang/Assets/Script/DirllInterface/bindPlayer.cs.meta
Normal file
11
xiaofang/Assets/Script/DirllInterface/bindPlayer.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 87dc9f5d8174c1d4f93225552d06fe21
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
79
xiaofang/Assets/Script/DirllInterface/getRoleList.cs
Normal file
79
xiaofang/Assets/Script/DirllInterface/getRoleList.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class getRoleList : MonoBehaviour
|
||||||
|
{
|
||||||
|
|
||||||
|
// 创建请求头,使用最新的 token
|
||||||
|
public Dictionary<string, string> CreateHeaders()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(Global.global.loginResponse.data.access_token))
|
||||||
|
{
|
||||||
|
Debug.LogWarning("尝试创建请求头时,token 未设置。");
|
||||||
|
return new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "Authorization","Bearer "+Global.global.loginResponse.data.access_token },
|
||||||
|
{"clientId", "e5cd7e4891bf95d1d19206ce24a7b32e" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//角色列表
|
||||||
|
public async void queryRoleList(string secneId)
|
||||||
|
{
|
||||||
|
getRoleListBody getRoleListBody = new getRoleListBody();
|
||||||
|
getRoleListBody.sceneId = secneId;//==============================================================================
|
||||||
|
string response = await web.SendRequest(web.URL + "/game/role/list", "GET", JsonConvert.SerializeObject(getRoleListBody), CreateHeaders());
|
||||||
|
Debug.Log("查询角色列表: " + response);
|
||||||
|
RoleList serverData = JsonConvert.DeserializeObject<RoleList>(response);
|
||||||
|
|
||||||
|
// 检查反序列化结果
|
||||||
|
if (serverData == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("Failed to deserialize JSON. RoleList is null.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serverData.data == null || serverData.data.Count == 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("No role data found in the returned data.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历反序列化后的角色列表
|
||||||
|
foreach (var role in serverData.data)
|
||||||
|
{
|
||||||
|
//Debug.Log("Role ID: " + role.id);
|
||||||
|
//Debug.Log("Role Name: " + role.roleName);
|
||||||
|
//Debug.Log("Scene ID: " + role.sceneId);
|
||||||
|
//Debug.Log("Game Name: " + role.gameName);
|
||||||
|
//Debug.Log("Role Attributions: " + role.roleAttributions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//====请求体==========================================================================================
|
||||||
|
public class getRoleListBody
|
||||||
|
{
|
||||||
|
public string sceneId;//=====必须
|
||||||
|
}
|
||||||
|
//====返回值解析数据类==========================================================================================
|
||||||
|
public class RoleList
|
||||||
|
{
|
||||||
|
public int code; // 与 JSON 中的 "code" 字段对应
|
||||||
|
public string msg; // 与 JSON 中的 "msg" 字段对应
|
||||||
|
public List<RoleData> data; // 与 JSON 中的 "data" 字段对应,包含角色的列表
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RoleData
|
||||||
|
{
|
||||||
|
public string id; // 与 JSON 中的 "id" 字段对应
|
||||||
|
public string roleName; // 与 JSON 中的 "roleName" 字段对应
|
||||||
|
public string sceneId; // 与 JSON 中的 "sceneId" 字段对应
|
||||||
|
public int gameName; // 与 JSON 中的 "gameName" 字段对应,注意这里是 int 类型
|
||||||
|
public string roleAttributions; // 与 JSON 中的 "roleAttributions" 字段对应
|
||||||
|
}
|
11
xiaofang/Assets/Script/DirllInterface/getRoleList.cs.meta
Normal file
11
xiaofang/Assets/Script/DirllInterface/getRoleList.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c0c2be722e7906a4aba1cfe40098da13
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -1,6 +1,7 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
public class querySubjectList : MonoBehaviour
|
public class querySubjectList : MonoBehaviour
|
||||||
@ -24,10 +25,8 @@ public class querySubjectList : MonoBehaviour
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
//查询演练科目信息列表
|
//查询演练科目信息列表
|
||||||
public async void QueryDrillSubject()
|
public async Task<DrillSubject> QueryDrillSubject()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
string response = await web.SendRequest(web.URL + "/game/subject/list", "GET", "", CreateHeaders());
|
string response = await web.SendRequest(web.URL + "/game/subject/list", "GET", "", CreateHeaders());
|
||||||
Debug.Log("查询演练科目信息列表: " + response);
|
Debug.Log("查询演练科目信息列表: " + response);
|
||||||
|
|
||||||
@ -38,34 +37,58 @@ public class querySubjectList : MonoBehaviour
|
|||||||
if (drillSubject == null)
|
if (drillSubject == null)
|
||||||
{
|
{
|
||||||
Debug.LogError("Failed to deserialize JSON. DrillSubject is null.");
|
Debug.LogError("Failed to deserialize JSON. DrillSubject is null.");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drillSubject.data == null || drillSubject.data.Count == 0)
|
if (drillSubject.data == null || drillSubject.data.Count == 0)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("No subjects found in the returned data.");
|
Debug.LogWarning("No subjects found in the returned data.");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 遍历反序列化后的 data 列表
|
// 遍历反序列化后的 data 列表
|
||||||
foreach (var subject in drillSubject.data)
|
foreach (var subject in drillSubject.data)
|
||||||
{
|
{
|
||||||
Debug.Log("ID: " + subject.id);
|
//Debug.Log("ID: " + subject.id);
|
||||||
Debug.Log("Scene Names: " + subject.sceneNames);
|
//Debug.Log("Scene Names: " + subject.sceneNames);
|
||||||
Debug.Log("Name: " + subject.name);
|
//Debug.Log("Name: " + subject.name);
|
||||||
Debug.Log("Suit Version: " + subject.suitVersion);
|
//Debug.Log("Suit Version: " + subject.suitVersion);
|
||||||
Debug.Log("Type: " + subject.type);
|
//Debug.Log("Type: " + subject.type);
|
||||||
Debug.Log("Description: " + subject.description);
|
//Debug.Log("Description: " + subject.description);
|
||||||
Debug.Log("Price: " + subject.price);
|
//Debug.Log("Price: " + subject.price);
|
||||||
Debug.Log("Company ID: " + subject.companyId);
|
//Debug.Log("Company ID: " + subject.companyId);
|
||||||
Debug.Log("Status: " + subject.status);
|
//Debug.Log("Status: " + subject.status);
|
||||||
Debug.Log("Delete Flag: " + subject.delFlag);
|
//Debug.Log("Delete Flag: " + subject.delFlag);
|
||||||
Debug.Log("Remark: " + subject.remark);
|
//Debug.Log("Remark: " + subject.remark);
|
||||||
Debug.Log("Game Name: " + subject.gameName);
|
//Debug.Log("Game Name: " + subject.gameName);
|
||||||
Debug.Log("OSS ID: " + subject.ossId);
|
//Debug.Log("OSS ID: " + subject.ossId);
|
||||||
Debug.Log("File List: " + subject.fileList);
|
//Debug.Log("File List: " + subject.fileList);
|
||||||
// 如果需要进一步处理字段,可以在这里进行
|
// 如果需要进一步处理字段,可以在这里进行
|
||||||
// 比如,将价格转换为数字计算,或根据特定类型执行逻辑
|
// 比如,将价格转换为数字计算,或根据特定类型执行逻辑
|
||||||
}
|
}
|
||||||
|
return drillSubject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//=======================================================================================================
|
||||||
|
public class DrillSubject : Response
|
||||||
|
{
|
||||||
|
[JsonProperty("data")]
|
||||||
|
public List<QueryDrillSubjectData> data; // È·±£×Ö¶ÎÃûÓë JSON ÖеÄÆ¥Åä
|
||||||
|
}
|
||||||
|
|
||||||
|
public class QueryDrillSubjectData
|
||||||
|
{
|
||||||
|
public string id;//
|
||||||
|
public string[] sceneIds;
|
||||||
|
public string sceneNames;
|
||||||
|
public string name;
|
||||||
|
public string suitVersion;
|
||||||
|
public string type;
|
||||||
|
public string description;
|
||||||
|
public string price;
|
||||||
|
public string companyId;
|
||||||
|
public string status;
|
||||||
|
public string delFlag;
|
||||||
|
public string remark;
|
||||||
|
public string gameName;
|
||||||
|
public string ossId;
|
||||||
|
public string fileList;
|
||||||
|
}
|
@ -73,7 +73,7 @@ public class loginData
|
|||||||
//{
|
//{
|
||||||
// public string data;
|
// public string data;
|
||||||
//}
|
//}
|
||||||
//=============================================================
|
//=================================================================
|
||||||
// ¸ùÊý¾ÝÀà
|
// ¸ùÊý¾ÝÀà
|
||||||
//public class QuerySceneData
|
//public class QuerySceneData
|
||||||
//{
|
//{
|
||||||
@ -114,47 +114,47 @@ public class loginData
|
|||||||
// public string fileSuffix { get; set; }
|
// public string fileSuffix { get; set; }
|
||||||
//}
|
//}
|
||||||
//=================================================================
|
//=================================================================
|
||||||
public class DrillSubject : Response
|
//public class DrillSubject : Response
|
||||||
{
|
//{
|
||||||
[JsonProperty("data")]
|
// [JsonProperty("data")]
|
||||||
public List<QueryDrillSubjectData> data; // 确保字段名与 JSON 中的匹配
|
// public List<QueryDrillSubjectData> data; // 确保字段名与 JSON 中的匹配
|
||||||
}
|
//}
|
||||||
|
|
||||||
public class QueryDrillSubjectData
|
//public class QueryDrillSubjectData
|
||||||
{
|
//{
|
||||||
public string id;
|
// public string id;
|
||||||
public string[] sceneIds;
|
// public string[] sceneIds;
|
||||||
public string sceneNames;
|
// public string sceneNames;
|
||||||
public string name;
|
// public string name;
|
||||||
public string suitVersion;
|
// public string suitVersion;
|
||||||
public string type;
|
// public string type;
|
||||||
public string description;
|
// public string description;
|
||||||
public string price;
|
// public string price;
|
||||||
public string companyId;
|
// public string companyId;
|
||||||
public string status;
|
// public string status;
|
||||||
public string delFlag;
|
// public string delFlag;
|
||||||
public string remark;
|
// public string remark;
|
||||||
public string gameName;
|
// public string gameName;
|
||||||
public string ossId;
|
// public string ossId;
|
||||||
public string fileList;
|
// public string fileList;
|
||||||
}
|
//}
|
||||||
//===============================================================
|
//===============================================================
|
||||||
|
|
||||||
public class RoleList
|
//public class RoleList
|
||||||
{
|
//{
|
||||||
public int code; // 与 JSON 中的 "code" 字段对应
|
// public int code; // 与 JSON 中的 "code" 字段对应
|
||||||
public string msg; // 与 JSON 中的 "msg" 字段对应
|
// public string msg; // 与 JSON 中的 "msg" 字段对应
|
||||||
public List<RoleData> data; // 与 JSON 中的 "data" 字段对应,包含角色的列表
|
// public List<RoleData> data; // 与 JSON 中的 "data" 字段对应,包含角色的列表
|
||||||
}
|
//}
|
||||||
|
|
||||||
public class RoleData
|
//public class RoleData
|
||||||
{
|
//{
|
||||||
public string id; // 与 JSON 中的 "id" 字段对应
|
// public string id; // 与 JSON 中的 "id" 字段对应
|
||||||
public string roleName; // 与 JSON 中的 "roleName" 字段对应
|
// public string roleName; // 与 JSON 中的 "roleName" 字段对应
|
||||||
public string sceneId; // 与 JSON 中的 "sceneId" 字段对应
|
// public string sceneId; // 与 JSON 中的 "sceneId" 字段对应
|
||||||
public int gameName; // 与 JSON 中的 "gameName" 字段对应,注意这里是 int 类型
|
// public int gameName; // 与 JSON 中的 "gameName" 字段对应,注意这里是 int 类型
|
||||||
public string roleAttributions; // 与 JSON 中的 "roleAttributions" 字段对应
|
// public string roleAttributions; // 与 JSON 中的 "roleAttributions" 字段对应
|
||||||
}
|
//}
|
||||||
//===================================================================
|
//===================================================================
|
||||||
public class BindPlayer:Response
|
public class BindPlayer:Response
|
||||||
{
|
{
|
||||||
|
@ -177,80 +177,80 @@ public class login : MonoBehaviour
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
//查询演练科目信息列表
|
//查询演练科目信息列表
|
||||||
public async void QueryDrillSubject()
|
//public async void QueryDrillSubject()
|
||||||
{
|
//{
|
||||||
string response = await web.SendRequest(web.URL + "/game/subject/list", "GET", "", CreateHeaders());
|
// string response = await web.SendRequest(web.URL + "/game/subject/list", "GET", "", CreateHeaders());
|
||||||
Debug.Log("查询演练科目信息列表: " + response);
|
// Debug.Log("查询演练科目信息列表: " + response);
|
||||||
|
|
||||||
// 使用 Newtonsoft.Json 进行反序列化
|
// // 使用 Newtonsoft.Json 进行反序列化
|
||||||
DrillSubject drillSubject = JsonConvert.DeserializeObject<DrillSubject>(response);
|
// DrillSubject drillSubject = JsonConvert.DeserializeObject<DrillSubject>(response);
|
||||||
|
|
||||||
// 检查反序列化结果
|
// // 检查反序列化结果
|
||||||
if (drillSubject == null)
|
// if (drillSubject == null)
|
||||||
{
|
// {
|
||||||
Debug.LogError("Failed to deserialize JSON. DrillSubject is null.");
|
// Debug.LogError("Failed to deserialize JSON. DrillSubject is null.");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (drillSubject.data == null || drillSubject.data.Count == 0)
|
// if (drillSubject.data == null || drillSubject.data.Count == 0)
|
||||||
{
|
// {
|
||||||
Debug.LogWarning("No subjects found in the returned data.");
|
// Debug.LogWarning("No subjects found in the returned data.");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 遍历反序列化后的 data 列表
|
// // 遍历反序列化后的 data 列表
|
||||||
foreach (var subject in drillSubject.data)
|
// foreach (var subject in drillSubject.data)
|
||||||
{
|
// {
|
||||||
Debug.Log("ID: " + subject.id);
|
// Debug.Log("ID: " + subject.id);
|
||||||
Debug.Log("Scene Names: " + subject.sceneNames);
|
// Debug.Log("Scene Names: " + subject.sceneNames);
|
||||||
Debug.Log("Name: " + subject.name);
|
// Debug.Log("Name: " + subject.name);
|
||||||
Debug.Log("Suit Version: " + subject.suitVersion);
|
// Debug.Log("Suit Version: " + subject.suitVersion);
|
||||||
Debug.Log("Type: " + subject.type);
|
// Debug.Log("Type: " + subject.type);
|
||||||
Debug.Log("Description: " + subject.description);
|
// Debug.Log("Description: " + subject.description);
|
||||||
Debug.Log("Price: " + subject.price);
|
// Debug.Log("Price: " + subject.price);
|
||||||
Debug.Log("Company ID: " + subject.companyId);
|
// Debug.Log("Company ID: " + subject.companyId);
|
||||||
Debug.Log("Status: " + subject.status);
|
// Debug.Log("Status: " + subject.status);
|
||||||
Debug.Log("Delete Flag: " + subject.delFlag);
|
// Debug.Log("Delete Flag: " + subject.delFlag);
|
||||||
Debug.Log("Remark: " + subject.remark);
|
// Debug.Log("Remark: " + subject.remark);
|
||||||
Debug.Log("Game Name: " + subject.gameName);
|
// Debug.Log("Game Name: " + subject.gameName);
|
||||||
Debug.Log("OSS ID: " + subject.ossId);
|
// Debug.Log("OSS ID: " + subject.ossId);
|
||||||
Debug.Log("File List: " + subject.fileList);
|
// Debug.Log("File List: " + subject.fileList);
|
||||||
// 如果需要进一步处理字段,可以在这里进行
|
// // 如果需要进一步处理字段,可以在这里进行
|
||||||
// 比如,将价格转换为数字计算,或根据特定类型执行逻辑
|
// // 比如,将价格转换为数字计算,或根据特定类型执行逻辑
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
//角色列表
|
////角色列表
|
||||||
public async void queryRoleList()
|
//public async void queryRoleList()
|
||||||
{
|
//{
|
||||||
string body = "{\"sceneId\": \"1845704588547301377\"}";
|
// string body = "{\"sceneId\": \"1845704588547301377\"}";
|
||||||
string response = await web.SendRequest(web.URL + "/game/role/list", "GET", body, CreateHeaders());
|
// string response = await web.SendRequest(web.URL + "/game/role/list", "GET", body, CreateHeaders());
|
||||||
Debug.Log("查询角色列表: " + response);
|
// Debug.Log("查询角色列表: " + response);
|
||||||
RoleList serverData = JsonConvert.DeserializeObject<RoleList>(response);
|
// RoleList serverData = JsonConvert.DeserializeObject<RoleList>(response);
|
||||||
|
|
||||||
// 检查反序列化结果
|
// // 检查反序列化结果
|
||||||
if (serverData == null)
|
// if (serverData == null)
|
||||||
{
|
// {
|
||||||
Debug.LogError("Failed to deserialize JSON. RoleList is null.");
|
// Debug.LogError("Failed to deserialize JSON. RoleList is null.");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (serverData.data == null || serverData.data.Count == 0)
|
// if (serverData.data == null || serverData.data.Count == 0)
|
||||||
{
|
// {
|
||||||
Debug.LogWarning("No role data found in the returned data.");
|
// Debug.LogWarning("No role data found in the returned data.");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 遍历反序列化后的角色列表
|
// // 遍历反序列化后的角色列表
|
||||||
foreach (var role in serverData.data)
|
// foreach (var role in serverData.data)
|
||||||
{
|
// {
|
||||||
Debug.Log("Role ID: " + role.id);
|
// Debug.Log("Role ID: " + role.id);
|
||||||
Debug.Log("Role Name: " + role.roleName);
|
// Debug.Log("Role Name: " + role.roleName);
|
||||||
Debug.Log("Scene ID: " + role.sceneId);
|
// Debug.Log("Scene ID: " + role.sceneId);
|
||||||
Debug.Log("Game Name: " + role.gameName);
|
// Debug.Log("Game Name: " + role.gameName);
|
||||||
Debug.Log("Role Attributions: " + role.roleAttributions);
|
// Debug.Log("Role Attributions: " + role.roleAttributions);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
//模板玩家绑定
|
//模板玩家绑定
|
||||||
public async void BindPlayer()
|
public async void BindPlayer()
|
||||||
|
Loading…
Reference in New Issue
Block a user