Multiplayer Texture Change Problem

Hello everyone

i Have created multiplayer game and used ready Player me for the character change . But while changing the character the texture change is not working for other players . Please help me in this problem . Fell free to contact me with a reply for any additional information you need

https://playcanvas.com/project/982877/overview/finalmeta2

Hey @Tr_andreson,

I see you got the models/textures working. I was actually taking a look at your previous forum post just now. What scripts and functions would be responsible for loading other people’s models? Do you get any errors in the Chrome Web Dev Console when someone else attempts to set their own model?

Thank You for replying back . This is the script i am using for the character change . Please Check

var CustomAvatarLoader = pc.createScript('customAvatarLoader');

CustomAvatarLoader.attributes.add('css', { type: 'asset', assetType: 'css', title: 'CSS Asset' });

CustomAvatarLoader.attributes.add('html', { type: 'asset', assetType: 'html', title: 'HTML Asset' });

CustomAvatarLoader.attributes.add("LoadAvatarBtn", { type: "entity" });

CustomAvatarLoader.attributes.add("LoadingScreen", { type: "entity" });

CustomAvatarLoader.instance = null;

window.addEventListener("message", function (event) {

    if (event.origin === "https://rarerooms.readyplayer.me") {

        CustomAvatarLoader.instance.LoadNewAvatar(event.data);

    }

}, false);

// initialize code called once per entity

CustomAvatarLoader.prototype.initialize = function () {

    CustomAvatarLoader.instance = this;

    this.GlbURL = null;

    this.iframeWidth = window.innerWidth;

    this.iframeHeight = window.innerHeight;

    this.app.on("BtnManager:LoadAvatarButtonClick", this.customAvatarSelection.bind(this));

    this.on('destroy', function () {

        this.app.off("BtnManager:LoadAvatarButtonClick", this.customAvatarSelection.bind(this));

    }.bind(this));

    this.setupIframe();

    this.isMobile = false;

    if (pc.platform.mobile || pc.platform.android || pc.platform.ios) { // Mobile

        let avatarIframe = document.getElementById("avatarIframe");

        avatarIframe.style.width = this.iframeWidth + "px";

        avatarIframe.style.height = this.iframeHeight + "px";

        avatarIframe.style.border = "none";

        this.isMobile = true;

    } else { // Desktop

        let avatarIframe = document.getElementById("avatarIframe");

        avatarIframe.style.width = "900px";

        avatarIframe.style.height = "650px";

        avatarIframe.style.border = "none";

        this.isMobile = false;

    }

};

CustomAvatarLoader.prototype.LoadNewAvatar = function (data) {

    let iframe = document.getElementById('avatarIframe');

    let avatarDiv = document.getElementById('avatarDiv');

    iframe.style.display = "none";

    avatarDiv.style.display = "none";

    this.loadGLBModelFromURL(data);

};

// CustomAvatarLoader.prototype.loadGLBModelFromURL = function (modelURL) {

//     var self = this;

//     this.GlbURL = modelURL;

//     this.app.fire("LoadingMenu:SetLoading", true, "Loading Avatar..");

//     let name = "model_" + (Math.floor(Math.random() * 10000));

//     let cacheURL = modelURL + "?cacheBuster=" + (Math.floor(Math.random() * 10000));

//     this.LoadingScreen.enabled = true;

//     utils.loadGlbContainerFromUrl(cacheURL, null, name, function (err, asset) {

//         if (asset.resources[0].model)

//             this.app.root.findByName("ModelTPC").model.asset = asset.resources[0].model.id;

//         else {

//             console.log(asset.resources);

//         }

//         this.LoadAvatarBtn.enabled = true;

//         this.LoadingScreen.enabled = false;

//     }.bind(this));

// };

CustomAvatarLoader.prototype.setupIframe = function () {

    // create STYLE element

    var style = document.createElement('style');

    // append to head

    document.head.appendChild(style);

    style.innerHTML = this.css.resource || '';

    // Add the HTML

    this.div = document.createElement('div');

    this.div.id = "avatarDiv";

    this.div.classList.add('avatarContrainer');

    this.div.innerHTML = this.html.resource || '';

    this.div.style.display = "none";

    // append to body

    // can be appended somewhere else

    // it is recommended to have some container element

    // to prevent iOS problems of overfloating elements off the screen

    var canvas = document.getElementById("application-canvas");

    // canvas.style.pointerEvents = "none";

    //document.body.insertBefore(this.div,canvas);

    document.body.appendChild(this.div);

};

CustomAvatarLoader.prototype.customAvatarSelection = function () {

    this.LoadAvatarBtn.enabled = false;

    let iframe = document.getElementById('avatarIframe');

    let avatarDiv = document.getElementById('avatarDiv');

    iframe.src = 'https://rarerooms.readyplayer.me/avatar'; // Change this to your custom subdomain

    iframe.style.display = "block";

    avatarDiv.style.display = "block";

};

// update code called every frame

CustomAvatarLoader.prototype.update = function () {

    CustomAvatarLoader.prototype.loadGLBModelFromURL = function (modelURL) {

    var self = this;

    this.GlbURL = modelURL;

    this.app.fire("LoadingMenu:SetLoading", true, "Loading Avatar..");

    let name = "model_" + (Math.floor(Math.random() * 10000));

    let cacheURL = modelURL + "?cacheBuster=" + (Math.floor(Math.random() * 10000));

    this.LoadingScreen.enabled = true;

    utils.loadGlbContainerFromUrl(cacheURL, null, name, function (err, asset) {

        if (asset.resources[0].model)

            this.app.root.findByName("ModelTPC").model.asset = asset.resources[0].model.id;

        else {

            console.log(asset.resources);

        }

        this.LoadAvatarBtn.enabled = true;

        this.LoadingScreen.enabled = false;

    }.bind(this));

};

};
1 Like

and i cannot see any error in console regarding character change

Is there any way to send character textures through network ?

As this is a fairly large script, let’s take a step back and look at it step by step what’s going on.

  1. What function within your script is responsible for loading other people’s model? Is it loadNewAvatar?
  2. How is this function called? Do we have an event that we’re subscribing the function to? Where do we subscribe to it?

Also, I should note that it might be useful to ask on the Ready Player Me Discord? It seems like the issue is more so how to correctly use their API than a problem with PlayCanvas itself?

1 .The function is right below the new avatar load glb model from url

  1. the function is called after the load new avatar function

  2. And i have also asked the ready player me in gmail . And they don’t have any particular documentation for PlayCanvas

is there any way to update textures over a socket network

CustomAvatarLoader.prototype.loadGLBModelFromURL = function (modelURL) {
    var self = this;
    this.GlbURL = modelURL;
    this.app.fire("LoadingMenu:SetLoading", true, "Loading Avatar..");
    let name = "model_" + (Math.floor(Math.random() * 10000));
    let cacheURL = modelURL + "?cacheBuster=" + (Math.floor(Math.random() * 10000));

    this.LoadingScreen.enabled = true;
    utils.loadGlbContainerFromUrl(cacheURL, null, name, function (err, asset) {
        if (asset.resources[0].model)
            this.app.root.findByName("ModelTPC").model.asset = asset.resources[0].model.id;
        else {
            console.log(asset.resources);
        }
        this.LoadAvatarBtn.enabled = true;
        this.LoadingScreen.enabled = false;
    }.bind(this));
};

I will send you the full code properly

var CustomAvatarLoader = pc.createScript('customAvatarLoader');

CustomAvatarLoader.attributes.add('css', { type: 'asset', assetType: 'css', title: 'CSS Asset' });
CustomAvatarLoader.attributes.add('html', { type: 'asset', assetType: 'html', title: 'HTML Asset' });
CustomAvatarLoader.attributes.add("LoadAvatarBtn", { type: "entity" });
CustomAvatarLoader.attributes.add("LoadingScreen", { type: "entity" });

CustomAvatarLoader.instance = null;

window.addEventListener("message", function (event) {
    if (event.origin === "https://rarerooms.readyplayer.me") {
        CustomAvatarLoader.instance.LoadNewAvatar(event.data);
    }
}, false);

// initialize code called once per entity
CustomAvatarLoader.prototype.initialize = function () {
    CustomAvatarLoader.instance = this;
    this.GlbURL = null;
    this.iframeWidth = window.innerWidth;
    this.iframeHeight = window.innerHeight;
    this.app.on("BtnManager:LoadAvatarButtonClick", this.customAvatarSelection.bind(this));

    this.on('destroy', function () {
        this.app.off("BtnManager:LoadAvatarButtonClick", this.customAvatarSelection.bind(this));
    }.bind(this));

    this.setupIframe();
    this.isMobile = false;

    if (pc.platform.mobile || pc.platform.android || pc.platform.ios) { // Mobile
        let avatarIframe = document.getElementById("avatarIframe");
        avatarIframe.style.width = this.iframeWidth + "px";
        avatarIframe.style.height = this.iframeHeight + "px";
        avatarIframe.style.border = "none";
        this.isMobile = true;
    } else { // Desktop
        let avatarIframe = document.getElementById("avatarIframe");
        avatarIframe.style.width = "900px";
        avatarIframe.style.height = "650px";
        avatarIframe.style.border = "none";
        this.isMobile = false;
    }
};

CustomAvatarLoader.prototype.LoadNewAvatar = function (data) {
    let iframe = document.getElementById('avatarIframe');
    let avatarDiv = document.getElementById('avatarDiv');
    iframe.style.display = "none";
    avatarDiv.style.display = "none";
    this.loadGLBModelFromURL(data);
};

CustomAvatarLoader.prototype.loadGLBModelFromURL = function (modelURL) {
    var self = this;
    this.GlbURL = modelURL;
    this.app.fire("LoadingMenu:SetLoading", true, "Loading Avatar..");
    let name = "model_" + (Math.floor(Math.random() * 10000));
    let cacheURL = modelURL + "?cacheBuster=" + (Math.floor(Math.random() * 10000));

    this.LoadingScreen.enabled = true;
    utils.loadGlbContainerFromUrl(cacheURL, null, name, function (err, asset) {
        if (asset.resources[0].model)
            this.app.root.findByName("ModelTPC").model.asset = asset.resources[0].model.id;
        else {
            console.log(asset.resources);
        }
        this.LoadAvatarBtn.enabled = true;
        this.LoadingScreen.enabled = false;
    }.bind(this));
};

CustomAvatarLoader.prototype.setupIframe = function () {
    // create STYLE element
    var style = document.createElement('style');

    // append to head
    document.head.appendChild(style);
    style.innerHTML = this.css.resource || '';

    // Add the HTML
    this.div = document.createElement('div');
    this.div.id = "avatarDiv";
    this.div.classList.add('avatarContrainer');
    this.div.innerHTML = this.html.resource || '';
    this.div.style.display = "none";
    // append to body
    // can be appended somewhere else
    // it is recommended to have some container element
    // to prevent iOS problems of overfloating elements off the screen
    var canvas = document.getElementById("application-canvas");
    // canvas.style.pointerEvents = "none";
    //document.body.insertBefore(this.div,canvas);
    document.body.appendChild(this.div);
};

CustomAvatarLoader.prototype.customAvatarSelection = function () {
    this.LoadAvatarBtn.enabled = false;
    let iframe = document.getElementById('avatarIframe');
    let avatarDiv = document.getElementById('avatarDiv');

    iframe.src = 'https://rarerooms.readyplayer.me/avatar'; // Change this to your custom subdomain
    iframe.style.display = "block";
    avatarDiv.style.display = "block";
};

// update code called every frame
CustomAvatarLoader.prototype.update = function () {
};

Hi @Tr_andreson,

You still haven’t added the proposed correction from this topic, avoid creating new threads for the same topic. Just post on the same.

Actually i have solved that previous problem for the character update . This is the new problem

Got it, try replying to the previous thread as solved and if possible share your solution to the problem for other users.

Okay … i"ll do

1 Like

This is a single player example project, you will have to code multiplayer functionality from scratch

This can be done in a very simple way,
Sending the model trough socket is a no go

You already have ‘modelURL’
Add a new property to player entity that holds model url and broadcast it trought socket

The property itself should be set to something like ‘Default’
When player loads a new avatar set the property to modelURL

if playerModel !== Default
Load a model from that URL
Do some other checks…

You get the idea

1 Like

Thank you so much for your response . I have already made it multiplayer . I got your point thanks for your suggestion