How to Gender Filtering with Photon? - unity3d

I'm developing a multiplayer game with unity. I am using playfab and photon plugin in the game. Players choose gender when logging in and I save this selection to player data in playfab. Also, I am making a simple match system with photon. (The player presses the "match" button, joins a room randomly, if there is no room to join, player sets up a room for 2 people and waits for the other player, when the number of players joining the room is 2, they switch to the room screen.)
Here is the code file where I make the players choose their gender:
public void choosemale()
{
eseç.SetActive(true);
kseç.SetActive(false);
}
public void choosefemale()
{
eseç.SetActive(false);
kseç.SetActive(true);
}
public void SetUserDataMale()
{
PlayFabClientAPI.UpdateUserData(new UpdateUserDataRequest()
{
Data = new Dictionary<string, string>() {
{"Gender", "Male"},
},
Permission = UserDataPermission.Public
},
result => Debug.Log("Successfully updated user data"),
error => {
Debug.Log("Got error setting user data Ancestor to Male");
Debug.Log(error.GenerateErrorReport());
});
}
public void SetUserDataFemale()
{
PlayFabClientAPI.UpdateUserData(new UpdateUserDataRequest()
{
Data = new Dictionary<string, string>() {
{"Gender", "Female"},
},
Permission = UserDataPermission.Public
},
result => Debug.Log("Successfully updated user data"),
error => {
Debug.Log("Got error setting user data Ancestor to Female");
Debug.Log(error.GenerateErrorReport());
}
) ;
} void OnLoginSuccess(LoginResult result)
{
if (eseç.activeSelf == true)
SetUserDataMale();
if (kseç.activeSelf == true)
SetUserDataFemale();
}
The code file I used for the matching:
public void FindMatch()
{
PhotonNetwork.JoinRandomRoom();
Debug.Log("Eşleşme Aranıyor");
}
public void StopSearch()
{
PhotonNetwork.LeaveRoom();
}
public override void OnJoinRandomFailed(short returnCode, string message)
{
Debug.Log("Fail");
MakeRoom();
}
void MakeRoom()
{
RoomOptions roomOptions = new RoomOptions()
{
IsVisible = true,
IsOpen = true,
MaxPlayers = 2
};
PhotonNetwork.CreateRoom("Room", roomOptions, EslesLobby);
Debug.Log("oda oluşturuldu, diğer oyuncu bekleniyor");
}
public override void OnJoinedRoom()
{
if (PhotonNetwork.CurrentRoom.PlayerCount == 2 && PhotonNetwork.IsMasterClient)
{
Debug.Log(PhotonNetwork.CurrentRoom.PlayerCount + "/2 Start Watch");
onlinep.SetActive(true);
_roomsCanvases.CurrentRoomCanvas.Show();
}
}
public override void OnCreatedRoom()
{
Debug.Log("OdaKurma Başarılı");
}
public override void OnPlayerEnteredRoom(Player newPlayer)
{
if(PhotonNetwork.CurrentRoom.PlayerCount ==2 && PhotonNetwork.IsMasterClient)
{
Debug.Log(PhotonNetwork.CurrentRoom.PlayerCount+"/2 Start Watch");
onlinep.SetActive(true);
_roomsCanvases.CurrentRoomCanvas.Show();
}
}
What I want to ask is this: I have a simple filtering bar. In this bar, when the player presses the male button, I want player to randomly join one of the rooms with only male players.How can I do that. I would be very happy if you help me.
Initially I find out the gender of the player using this code:
void GetUserData(string myPlayFabeId)
{
PlayFabClientAPI.GetUserData(new GetUserDataRequest()
{
PlayFabId = myPlayFabeId,
Keys = null
}, result => {
Debug.Log("Got user data:");
if (result.Data == null || !result.Data.ContainsKey("Gender")) Debug.Log("No Gender");
else Debug.Log("Ancestor: " + result.Data["Gender"].Value);
}, (error) => {
Debug.Log("Got error retrieving user data:");
Debug.Log(error.GenerateErrorReport());
});
}

You could simply split rooms into separate lists by using Photon's lobbies.

Related

How to Create an Input Name Script in Unity [duplicate]

This question already has answers here:
How to pass data (and references) between scenes in Unity
(6 answers)
Closed 2 years ago.
I have a name input script in the first scene, the plan is I want to call this input in the second scene, when I enter the name in the first scene, then the name will appear in the second scene too, how do you do that?
public class NamaUser : MonoBehaviour {
public InputField nama;
public Text teks;
public void NamaTeks () {
if (nama.text == "") {
teks.text = "Harap Isi Nama";
} else {
teks.text = "Namaku " + nama.text;
}
}
}
You can save the input's value PlayerPrefs.
Set the PlayerPrefs:
//Name of Pref in first parameter
//Value in second parameter
PlayerPrefs.SetString("value", teks.value);
Get the PlayerPref in second scene:
//Name of Pref in first parameter
//Returns value of PlayerPrefs
String a = PlayerPrefs.SetString("value");
Cons:
You can pass data not only between scenes but also between instances (game sessions).
Easy to manage since Unity handles all background process.
Can be used to store data to track highscores.
Pros:
Uses file system.
Data can easily be changed from prefs file.
Or, another way -- use Singelton and DontDestroyOnLoad()
Allows easy access to fields and saves an object between scenes.
For example use this template, to create your class.
using UnityEngine;
public class Singelton<T> : MonoBehaviour where T : Singelton<T>
{
private static T instance = null;
private bool alive = true;
public static T Instance
{
get
{
if (instance != null)
{
return instance;
}
else
{
//Find T
T[] managers = GameObject.FindObjectsOfType<T>();
if (managers != null)
{
if (managers.Length == 1)
{
instance = managers[0];
DontDestroyOnLoad(instance);
return instance;
}
else
{
if (managers.Length > 1)
{
Debug.LogError($"Have more that one {typeof(T).Name} in scene. " +
"But this is Singelton! Check project.");
for (int i = 0; i < managers.Length; ++i)
{
T manager = managers[i];
Destroy(manager.gameObject);
}
}
}
}
//create
GameObject go = new GameObject(typeof(T).Name, typeof(T));
instance = go.GetComponent<T>();
DontDestroyOnLoad(instance.gameObject);
return instance;
}
}
//Can be initialized externally
set
{
instance = value as T;
}
}
/// <summary>
/// Check flag if need work from OnDestroy or OnApplicationExit
/// </summary>
public static bool IsAlive
{
get
{
if (instance == null)
return false;
return instance.alive;
}
}
protected virtual void Awake()
{
if (instance == null)
{
DontDestroyOnLoad(gameObject);
instance = this as T;
}
else
{
Debug.LogError($"Have more that one {typeof(T).Name} in scene. " +
"But this is Singelton! Check project.");
Destroy(gameObject);
}
}
protected virtual void OnDestroy() { alive = false; }
protected virtual void OnApplicationQuit() { alive = false; }
}
Example of using:
class MyClass Settings : Singelton<Settings>
{
string param;
}

Photon, PlayFab, & Unity3D - Players not appearing to one another after joining Photon Room

I am working on a multiplayer game in Unity which is using Playfab and the Authentication and Photon which is hosting the multiplayer. I can successfully get players into the same room and I can load the scene after players 'join' the room, however, when 2 players are in the same room, they can not see each other.
This is my authentication service:
public class LoginWithCustomID : MonoBehaviour
{
private string _playFabPlayerIdCache;
private bool _isNewAccount;
private string _playerName;
// Use this to auth normally for PlayFab
void Awake()
{
PhotonNetwork.autoJoinLobby = false;
PhotonNetwork.automaticallySyncScene = true;
DontDestroyOnLoad(gameObject);
authenticateWithPlayfab();
}
private void authenticateWithPlayfab()
{
var request = new LoginWithCustomIDRequest
{
CustomId = "CustomId123",
CreateAccount = true,
InfoRequestParameters = new GetPlayerCombinedInfoRequestParams()
{
GetUserAccountInfo = true,
ProfileConstraints = new PlayerProfileViewConstraints()
{ ShowDisplayName = true }
}
};
PlayFabClientAPI.LoginWithCustomID(request, requestPhotonToken, OnLoginFailure);
}
private void requestPhotonToken(LoginResult result)
{
PlayerAccountService.loginResult = result;
_playFabPlayerIdCache = result.PlayFabId;
_playerName = result.InfoResultPayload.AccountInfo.TitleInfo.DisplayName;
if (result.NewlyCreated)
{
_isNewAccount = true;
setupNewPlayer(result);
}
PlayFabClientAPI.GetPhotonAuthenticationToken(new GetPhotonAuthenticationTokenRequest()
{
PhotonApplicationId = "photonId123"
}, AuthenticateWithPhoton, OnLoginFailure);
}
private void setupNewPlayer(LoginResult result)
{
PlayFabClientAPI.UpdateUserData(
new UpdateUserDataRequest()
{
Data = new Dictionary<string, string>()
{
{ "Level", "1" },
{ "xp", "0" }
}
}, success =>
{
Debug.Log("Set User Data");
}, failure =>
{
Debug.Log("Failed to set User Data..");
}
);
}
private void AuthenticateWithPhoton(GetPhotonAuthenticationTokenResult result)
{
Debug.Log("Photon token acquired: " + result.PhotonCustomAuthenticationToken);
var customAuth = new AuthenticationValues { AuthType = CustomAuthenticationType.Custom };
customAuth.AddAuthParameter("username", _playFabPlayerIdCache);
customAuth.AddAuthParameter("token", result.PhotonCustomAuthenticationToken);
PhotonNetwork.AuthValues = customAuth;
setNextScene();
}
private void setNextScene()
{
if(_isNewAccount || _playerName == null)
{
SceneManager.LoadSceneAsync("CreatePlayerName", LoadSceneMode.Single);
}
else
{
SceneManager.LoadSceneAsync("LandingScene", LoadSceneMode.Single);
}
}
private void OnLoginFailure(PlayFabError error)
{
Debug.LogWarning("something went wrong in auth login");
Debug.LogError("Here's some debug info:");
Debug.LogError(error.GenerateErrorReport());
}
}
}
This all works and a player is logged into PlayFab, as well as Photon I would assume if I got the Photon auth token. This brings me to my landing scene, which is essentially a place for an authenticated user to click a button to join a random room via Photon:
public static GameManager instance;
public static GameObject localPlayer;
private void Awake()
{
if (instance != null)
{
DestroyImmediate(instance);
return;
}
DontDestroyOnLoad(gameObject);
instance = this;
PhotonNetwork.automaticallySyncScene = true;
}
// Use this for initialization
void Start()
{
PhotonNetwork.ConnectUsingSettings("A_0.0.1");
}
public void JoinGame()
{
RoomOptions ro = new RoomOptions();
ro.MaxPlayers = 4;
PhotonNetwork.JoinOrCreateRoom("Test Room 2", ro, null);
}
public override void OnJoinedRoom()
{
Debug.Log("Joined Room!");
if (PhotonNetwork.isMasterClient)
{
PhotonNetwork.LoadLevel("Test_Map1");
}
}
private void OnLevelWasLoaded(int level)
{
if (!PhotonNetwork.inRoom)
return;
localPlayer = PhotonNetwork.Instantiate(
"Player",
new Vector3(0, 1f, 0),
Quaternion.identity,
0);
}
public void LeaveRoom()
{
PhotonNetwork.LeaveRoom();
SceneManager.LoadScene("LandingScene", LoadSceneMode.Single);
}
This loads the scene that I named "Test_scene1" successfully and I show within my scene, the room name and number of active players in the room. When I do a run and build, I get a user's playerPrefab to load into the room. When I run the game through unity, I can get a second player to log into the room. The problem is, the players do not see eachother and I can not figure out why that is. I am following the PLayerfab/Photon tutorials on their respective sites, but I can't find anything that I did wrong in either one.
From what I read, it looks like my instantiate method might be wrong but I'm not sure why. Below is my player Prefab showing the components attached to it:
I apologize for this huge question, I just wanted to provide as much information as I could.
This question was answered by the OP on PlayFab forums here.

GWT Drag and Drop File Upload not working

So I have implemented a very simple drag and drop file upload widget. Basically my widget is a vertical panel with a couple of labels and a button inside. The user can either drag file into vertical panel or click button and browse for file.
My problem is that when I drag a file into the vertical panel it fires the DragLeaveEvent every time I drag the item over the space that the labels or button occupies. I want it to know that the item is in the vertical panel even when it is on top of the label or button. Im sure I am missing something simple. I provide the drag functionality by adding these dom handlers to the vertical panel:
addDomHandler(new DragEnterHandler() {
#Override
public void onDragEnter(DragEnterEvent event) {
System.out.println("drag enter");
highlight(true);
}
}, DragEnterEvent.getType());
addDomHandler(new DragLeaveHandler() {
#Override
public void onDragLeave(DragLeaveEvent event) {
System.out.println("drag leave");
highlight(false);
}
}, DragLeaveEvent.getType());
addDomHandler(new DragOverHandler() {
#Override
public void onDragOver(DragOverEvent event) {
}
}, DragOverEvent.getType());
addDomHandler(new DropHandler() {
#Override
public void onDrop(DropEvent event) {
System.out.println("drop");
// stop default behaviour
event.preventDefault();
event.stopPropagation();
// starts the fetching, reading and callbacks
if (fileUploadHandler != null) {
handleFiles(event.getDataTransfer(), fileUploadHandler);
}
highlight(false);
}
}, DropEvent.getType());
Check that the event target is a child (or grand child) of your panel, or in this case maybe rather whether the event target is exactly your panel's element:
if (verticalPanel.getElement().isOrHasChild(Node.as(event.getNativeEvent().getEventTarget()))) {
// within the panel (possibly on a child)
}
if (verticalPanel.getElement() == Node.as(event.getNativeEvent().getEventTarget())) {
// targetting exactly the panel (e.g. leaving the panel, not one of its children)
}
Through lots of research I have come to the only solution I could find. I set highlight to true in the dragover handler instead of drag enter.
panel.addDomHandler(new DragEnterHandler() {
#Override
public void onDragEnter(DragEnterEvent event) {
}
}, DragEnterEvent.getType());
panel.addDomHandler(new DragLeaveHandler() {
#Override
public void onDragLeave(DragLeaveEvent event) {
highlight(false);
}
}, DragLeaveEvent.getType());
panel.addDomHandler(new DragOverHandler() {
#Override
public void onDragOver(DragOverEvent event) {
highlight(true);
}
}, DragOverEvent.getType());
panel.addDomHandler(new DropHandler() {
#Override
public void onDrop(DropEvent event) {
// stop default behaviour
event.preventDefault();
event.stopPropagation();
// starts the fetching, reading and callbacks
handleFiles(event.getDataTransfer());
highlight(false);
}
}, DropEvent.getType());
I copy pasted your code, but also added a:
RootPanel.get().addHandler(dropHandler, DropEvent.getType());
My drophandler looks like this:
DropHandler dropHandler = new DropHandler() {
#Override
public void onDrop(DropEvent event) {
handleFiles(event.getDataTransfer(), new FileUploadHandler() {
#Override
public TYPE specifyFileType() {
return TYPE.BINARY;
}
#Override
public void handleFileContent(String fileName, String fileContent) {
// do stuff with filename and content
}
#Override
public boolean checkFileName(String fileName) {
return true;
}
});
event.preventDefault();
event.stopPropagation();
}
};
and the file-upload interface:
public interface FileUploadHandler {
static public enum TYPE {
TEXT, BINARY, DATAURL
};
// check the filename and extension and return true if you are happy with
// proceeding
// returnning false will prevent the file from being read
boolean checkFileName(String fileName);
// tell the method to use to read this file
TYPE specifyFileType();
// do your stuff here, eg upload to a server
void handleFileContent(String fileName, String fileContent);
}
and the handle files func: (note you will have to change classpath to the FileUploadHandler-interface)
// native method to make use of the HTML5 file API functionality
private final native void handleFiles(JavaScriptObject dataTransfer, FileUploadHandler fileUploadHandler) /*-{
var files = dataTransfer.files;
var i;
var file;
var reader = new FileReader();
for (i = 0; i < files.length; i++) {
file = files[i];
if (fileUploadHandler.#<classpath_to>.FileUploadHandler::checkFileName(Ljava/lang/String;)(file.name)) {
var type = fileUploadHandler.#<classpath_to>.FileUploadHandler::specifyFileType()();
reader.onload = function(e) {
fileUploadHandler.#<classpath_to>.FileUploadHandler::handleFileContent(Ljava/lang/String;Ljava/lang/String;)(file.name, e.target.result);
}
if (type == "TEXT") {
reader.readAsText(file);
} else if (type == "BINARY") {
reader.readAsBinaryString(file);
} else if (type == "DATAURL") {
reader.readAsDataURL(file);
// not supported
} else if (type == "ARRAYBUFFER") {
reader.readAsArrayBuffer(file);
} else {
}
}
}
}-*/;

Wicket ListMultipleChoice and ajax

I have a question about the ListMultipleChoice, is there anyway to get the selected items before the submit by an ajax link for example because i wouldn't refresh my page every time.
Thanks!
// Liste des partenaires de l'offre.
final ListMultipleChoice partenairesSelec =
new ListMultipleChoice("partenairesSelec", new Model((Serializable) partenairesSelected), new PropertyModel(
offre,
"partenaires"), renderer);
// Liste des domaines.
final DropDownChoice makes = new DropDownChoice("domaines", new PropertyModel(this, "selectedMake"), makeChoices) {
#Override
protected CharSequence getDefaultChoice(Object selected) {
return new ArrayList<String>(modelsMap.keySet()).get(0);
}
};
// Liste des partenaires disponibles.
final ListMultipleChoice partenairesChoice =
new ListMultipleChoice("partenaires", new Model((Serializable) partenairesSelection), modelChoices, renderer);
// Action associé au changement du domaine.
makes.add(new AjaxFormComponentUpdatingBehavior("onchange") {
#Override
protected void onUpdate(AjaxRequestTarget target) {
target.addComponent(partenairesChoice);
}
});
// Bouton ajouter.
Button ajout = new Button("ajout") {
#Override
public void onSubmit() {
if (partenairesSelection.size() != 0) {
for (Partenaire p : partenairesSelection) {
if (!partenairesSelected.contains(p)) {
offre.getPartenaires().add(p);
modelsMap.get(selectedMake).remove(p);
}
}
offre.setPartenaires(sortPartenaireList(offre.getPartenaires()));
}
}
};
// Bouton supprimer.
Button suppr = new Button("suppr") {
#Override
public void onSubmit() {
List<Partenaire> tmp = new ArrayList<Partenaire>();
if (partenairesSelected.size() != 0) {
for (Partenaire p : partenairesSelected) {
if (!partenairesSelection.contains(p)) {
Long id = p.getPartnerDomainId();
tmp.add(p);
for (String key : modelsMap.keySet()) {
if (modelsMap.get(key).size() > 0 && modelsMap.get(key).get(0).getPartnerDomainId() == id) {
modelsMap.get(key).add(p);
}
}
}
}
for (Partenaire p : tmp) {
offre.getPartenaires().remove(p);
}
offre.setPartenaires(sortPartenaireList(offre.getPartenaires()));
}
}
};
AjaxFormChoiceComponentUpdatingBehavior is the class designed to do just that. Attach it to your component and you'll get AJAX updates wherever the selection changes.
AjaxFormChoiceComponentUpdatingBehavior does not work for ListMultipleChoice!
I also searched for a good working solution and after a while I found a really good tutorial facing exactly a situation with two ListMultipleChoice elements and add/remove buttons to exchange contents between the two multiple select boxes:
http://blog.xebia.com/2008/03/25/wicket-and-list-choice-transfers/
They use AjaxButtons for doing this without submitting the form.

GWT CEll Browser Real Time Update

has someone been able to correctly to update a cell browser at runtime, i.e. when u remove a node or add a node, the change is reflected immediately in the CEll Browser, because I am using a List and when i am making a change it is not being updated on the spot
You can use ListDataProvider setList(...) method for dynamic updates. Here is an example how I update cell browser via RPC:
private void loadAllData(final ListDataProvider<Data> dataProvider) {
dBservice.getAllData(new AsyncCallback<List<Data>>() {
public void onSuccess(List<Data> result) {
dataProvider.setList(result);
}
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
});
}
to refresh a cellBrowser you have to close all the child on the root node.
anyway something like this
for (int i = 0; i < cellBrowser.getRootTreeNode().getChildCount(); i++) {
cellBrowser.getRootTreeNode().setChildOpen(i, false);
}
the AsyncDataProvider calls refreshes data
private final class Model implements TreeViewModel{
private List<ZonaProxy> zonaList = null;
private List<CategoriaProxy> categoriaList = null;
public void setCategoriaList(List<CategoriaProxy> categoriaList) {
this.categoriaList = categoriaList;
}
public void setListZona(List<ZonaProxy> zonaList) {
this.zonaList = zonaList;
}
#SuppressWarnings({ "unchecked", "rawtypes" })
public <T> NodeInfo<?> getNodeInfo(T value) {
CategoryDataProvider dataProvider1 = new CategoryDataProvider();
return new DefaultNodeInfo(dataProvider1, new CategoriaCell());
}
/**
* Check if the specified value represents a leaf node. Leaf nodes cannot be
* opened.
*/
public boolean isLeaf(Object value) {
if (value instanceof CategoriaProxy){
if (((CategoriaProxy) value).getLivello() == 3) {
return true;
}
}
return false;
}
}
private class CategoryDataProvider extends AsyncDataProvider<CategoriaProxy>
{
#Override
protected void onRangeChanged(HasData<CategoriaProxy> display)
{
requests.categoriaRequest().findAllCategorias(0, 8).with().fire(new Receiver<List<CategoriaProxy>>() {
#Override
public void onSuccess(List<CategoriaProxy> values) {
updateRowCount(values.size(), true);
updateRowData(0, values);
}
});
}
}
it Works.
Apparently it is not enough to change the data provider and refresh it.
You need also to force the affected cell to close and reopen it, as in this example
public void updateCellBrowser(String id) {
TreeNode node = getNode(cellBrowser.getRootTreeNode(),id);
if(node != null && ! node.isDestroyed()) {
TreeNode parent = node.getParent();
int index = node.getIndex();
parent.setChildOpen(index, false,true);
parent.setChildOpen(index, true, true);
}
}
In my particular example the cell ids are pathnames hence the following
implementation of getNode().
private TreeNode getNode(TreeNode node, String id) {
for(int i=0; i < node.getChildCount(); i++)
if(node.isChildOpen(i)) {
Object value = node.getChildValue(i);
if(value instanceof String) {
String nodeId = ((String) value);
if(id.equals(nodeId))
return node.setChildOpen(i, true);
if(id.startsWith(nodeId))
getNode(node.setChildOpen(i, true),id);
}
}
return null;
}