To get Started, I'm sorry but I don't speak English very well.
My .h:
UFUNCTION()
void AttachToPlayer(USkeletalMeshComponent* Mesh, const FName &SocketName);
UFUNCTION(Server, Reliable, WithValidation)
void ServerAttachToPlayer(USkeletalMeshComponent* Mesh, const FName &SocketName);
virtual void ServerAttachToPlayer_Implementation(USkeletalMeshComponent* Mesh, const FName &SocketName);
virtual bool ServerAttachToPlayer_Validate(USkeletalMeshComponent* Mesh, const FName &SocketName);
My cpp:
void ABagPlayer::AttachToPlayer(USkeletalMeshComponent* Mesh, const FName &SocketName)
{
if (Role == ROLE_Authority)
{
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("TEST"));
}
else
{
ServerAttachToPlayer(Mesh, SocketName);
}
}
bool ABagPlayer::ServerAttachToPlayer_Validate(USkeletalMeshComponent* Mesh, const FName &SocketName)
{
return true;
}
void ABagPlayer::ServerAttachToPlayer_Implementation(USkeletalMeshComponent* Mesh, const FName &SocketName)
{
AttachToPlayer(Mesh, SocketName);
}
I do not understand why, when my client launches the function "AttachToPlayer ", the function ' ServerAttachToPlayer_Implementaion ' is not called.
However, if it is the server that calls "AttachToPlayer ", the function "ServerAttachToPlayer_Implementaion " is called.
I've tried a lot of things, I'm pulling my hair!
Thanks for your help
Related
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.
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.
I want to do the following.
When a player joins the room, he should receive all the gameobjects' (with a photonview) locations.
This should happen only once when the player enters the room.
How could this be implemented?
The best solution for sending only one piece of information is to use RPC messages system.
[PunRPC]
void changePos(int x, int y, int z)
{
Debug.Log("new pos =" + x + "," + y + ","+z);
}
PhotonView photonView = PhotonView.Get(this);
photonView.RPC("changePos", PhotonTargets.All, 1,1,1 );
You can read more about RPC messages here: https://doc.photonengine.com/en/pun/current/tutorials/rpcsandraiseevent
EDIT:
I'm guessing you're connecting through:
PhotonNetwork.JoinRoom(this.roomName);
So in the place resposible for connection to the server you can use:
public void OnCreatedRoom()
{
Debug.Log("OnCreatedRoom");
}
public void OnJoinedRoom()
{
Debug.Log("OnJoinedRoom");
RPCserver.Instance.AddNewPlayer(login)
}
And then, you can have a bridge to store all RPC enabled methods:
public class RPCserver : Singleton
{
public List<Player> players = new List<Player>();
public void addNewPlayer(string name)
{
Player p = new Player(name);
players.Add(p);
if( p.isNewPlayer() ) fetchOtherObjectsPositions();
}
private void fetchOtherObjectsPositions(){
// Go through all neccesery objects, and send their position via RPCserver
}
}
Is that make sense ?
I have recently been creating a game with tutorials. Unfortunately, they didn't cover a save score feature. Thanks to another user, I was able to figure out that I needed to use playerprefs. I watched tutorials online, but none of them were helpful. If you can, please help me!
Gold Per Sec Script:
using UnityEngine;
using System.Collections;
public class GoldPerSec : MonoBehaviour {
public UnityEngine.UI.Text gpsDisplay;
public Click click;
public ItemManager[] items;
void Start () {
StartCoroutine(AutoTick ());
}
void Update () {
gpsDisplay.text = GetGoldPerSec() + " Money Per Sec";
}
public float GetGoldPerSec() {
float tick = 0;
foreach (ItemManager item in items) {
tick += item.count * item.tickValue;
}
return tick;
}
public void AutoGoldPerSec() {
click.gold += GetGoldPerSec() / 10;
}
IEnumerator AutoTick() {
while (true) {
AutoGoldPerSec();
yield return new WaitForSeconds(0.10f);
}
}
}
Gold Per Click script:
using UnityEngine;
using System.Collections;
public class Click : MonoBehaviour {
public UnityEngine.UI.Text gpc;
public UnityEngine.UI.Text goldDisplay;
public float gold = 0.00f;
public int goldperclick = 1;
void Update () {
goldDisplay.text = "" + gold.ToString("F0");
gpc.text = "Money Per Click: " + goldperclick;
}
public void Clicked(){
gold += goldperclick;
}
}
My idea was for the game to save when the game is quit, and load as soon as you load the game back up. I am a complete beginner, if anyone can tell me how to do this, please tell me! Thanks! :D
You can use unity's existing functions to achieve this.
For saving data use unity's OnApplicationQuit function like this
void OnApplicationQuit() {
PlayerPrefs.SetFloat("key", value);
}
And for Restoring the values use unity's Awake function like this
void Awake(){
value = PlayerPrefs.GetFloat("key");
}
Please note that PlayerPrefs is an easy way to save data but also an very unsafe way. The player can easily manipulate his "goldValue" since it's just stored as an integer in some file on his device. PlayerPrefs should usually just be used for values the player can changed any way within in game, like volume setting etc.
EXAMPLE CODE
void Save()
{
string filename = "/filename.dat";
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath+filename);
bf.Serialize(file, goldValue); //Use can easily use e.g. a List if you want to store more date
file.Close();
}
bool Load()
{
string filename = "/filename.dat";
if (File.Exists(Application.persistentDataPath + filename))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + filename, FileMode.Open);
goldValue=(int) bf.Deserialize(file);
file.Close();
return true;
}
return false;
}
Add the following code to Click class:
void Awake()
{
LoadData();
}
void OnApplicationQuit()
{
SaveData();
}
void SaveData()
{
PlayerPrefs.SetFloat("gold",gold);
}
void LoadData()
{
gold = PlayerPrefs.GetFloat("gold",0f);
}
my project code on banking doesnt work properly. when i enter the branch and department info as i run (void department) in main .
and i display(void display) them junk values are returned,i think the values are not going in the linked list.
code made in code blocks
part of the code below:
#include<iostream>
#include<conio.h>
#include<cstdio>
#include<string.h>
#include<cstdlib>
#include<malloc.h>
using namespace std;
int code=1100;
int acc=9900;
int loan_no=3300;
int emp=10;
void createmenu();
void depositormenu();
void employee();
void loanmenu();
void operationmenu();
class branch
{
char bname[20];
int bcode;
branch *link;
public:
branch()
{
bcode=code++;
}
void input()
{
fflush(stdin);
cout<<"\nEnter Branch Name: ";
gets(bname);
}
void output()
{
cout<<"\nBranch Name: "<<bname;
cout<<"\tBranch Code: "<<bcode;
}
};
class department
{
char dname[30];
int dcode;
public:
branch *b;
department *link;
department()
{
b=new branch;
}
void input()
{
b->input();
fflush(stdin);
cout<<"Enter Department Code: ";
cin>>dcode;
fflush(stdin);
cout<<"Enter Department Name: ";
gets(dname);
}
void output()
{
b->output();
fflush(stdout);
cout<<"\nDepartment Name: "<<dname;
cout<<"\tDepartment Code: "<<dcode;
}
};
void departments(department **);
void display(department **);
department *start,*p=NULL;
void departments(department **start)
{
department *temp,*r,*temp2;
temp2=*start;
system("cls");
cout<<"\nEnter data for Departments->";
department d;
if(*start==NULL)
{
temp=(department*)malloc(sizeof(department));
d.input();
temp=&d;
temp->link=NULL;
*start=temp;
}
else
{
temp=*start;
while(temp->link!=NULL)
{
temp=temp->link;
}
r=(department*)malloc(sizeof(department));
r->input();
r->link=NULL;
temp->link=r;
}
}
void display(department **start)
{
department *temp;
temp=*start;
fflush(stdout);
if(temp==NULL)
{
cout<<"\nList not created!";
cout<<"\tPress any key to return";
getch();
}
else
{
while(temp)
{
temp->output();
temp=temp->link;
getch();
}
}
}
pls help.
thanks in advance
Since I can't see your input values and expected output values, I can't say for sure. However, since you've opted to using pointers for everything, the one thing I see is with this block of code in the departments function:
department d;
if(*start==NULL)
{
temp=(department*)malloc(sizeof(department));
d.input();
temp=&d; // you are assigning the address of a local variable to temp,
// and then assigning it to the argument pointer.
temp->link=NULL;
*start=temp;
}
If you assign the address of a local variable to an argument pointer and then reference it from outside the function, you will have lost that data.
My suggestion would be to assign the contents of the department to the start object, rather than use the local pointer address.
That is likely why you're seeing garbage data.
I'm surprised the compiler didn't say anything about that.