Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Is there a way to automatically assign permission to edit and view a character sheet someone is importing to my game?

August 14 (5 years ago)

I run a lot of sessions for a very large group of people, and one of the chief problems we encounter is the considerable lag we get on roll20 when, say, 50+ PC character sheets are in a single game. I've moved monster character sheets to a Bestiary game and transmog them as-needed to the campaign game, and I thought I had set up a system for handling character sheets as-needed, too, but I ran into a problem.

The original plan was to have everyone make their own game, and then come game day for them, import their sheet from their game into mine. I would assign them permissions, we run our session, and at the end, they send their character sheet back to their own game for safekeeping, and I delete their character from my game -- except, of course, that free roll20 users can't do this. I know it's possible that they could just hold their character in the Vault, but they can't edit their sheet in the Vault, and leveling up happens out of game.

The new plan was to have me, the Pro subscriber in the group, to make two games: one Character game, one Campaign game. I have a script installed that allows people to generate a character sheet that automatically assigns permissions to the sheet on generation, so I don't have to constantly be around to assign new sheets to people; they can come in, make any amount of characters they want, and then import whichever character they're playing as to the Campaign game (it's kind of a West Marches-style game). 

I do still have to assign permissions to them when they import to the Campaign game, which I am okay with -- but when they export back to the Character Host game, they don't retain their permissions on their character sheet.

ONE of my players has managed to retain permissions across games on a character sheet they made. Neither myself nor the player can figure out how this happened. So my question is, is it actually possible for that to happen consistently and purposefully, or is that a glitch?

Is there a way to automatically assign sheet permissions to a player, to allow them to automatically edit and view a character sheet they imported to my game?

August 15 (5 years ago)

Edited August 15 (5 years ago)
vÍnce
Pro
Sheet Author

Have you looked into using the CharacterSheet API script?  You can install it from the one-click API page.

CharacterSheet
Version: 1.2.1
Authors: Kevin The Barbarian,TECH
A simple and easily customizable script allowing players to create their own character sheets. Using the command '!charsheet' will generate a character sheet controlled by the user that runs the command and visible in the journal to all players.

EDIT: sorry upon actually reading your post,;-P

CharacterSheet doesn't really fit for your use.

August 15 (5 years ago)

Edited August 15 (5 years ago)
Pat S.
Forum Champion
Sheet Author

Vince that is similar to the Welcome package but it is not what he needs or wants.

The OP wants players to be able to self-assign an imported sheet to themselves instead of having to wait for him to assign the sheets to them.

As I understand it, the character vault just takes a snapshot of the sheet and allows that snapshot to be placed into another game. This means the original is still in the original game and still editable by the user and the other sheet once assigned is editable by the user. I do not think there is any direct connection between games which means means the player will have to do maintenance on both sheets to keep them identical.

August 15 (5 years ago)
vÍnce
Pro
Sheet Author


Pat S. said:

Vince that is similar to the Welcome package but it is not what he needs or wants.

The OP wants players to be able to self-assign an imported sheet to themselves instead of having to wait for him to assign the sheets to them.

My bad.  Seems like something Aaron or another Scriptomancer might be able to whip with some scripting...


August 15 (5 years ago)
Pat S.
Forum Champion
Sheet Author


Vince said:


Pat S. said:

Vince that is similar to the Welcome package but it is not what he needs or wants.

The OP wants players to be able to self-assign an imported sheet to themselves instead of having to wait for him to assign the sheets to them.

My bad.  Seems like something Aaron or another Scriptomancer might be able to whip with some scripting...



That was my first thought also.

August 16 (5 years ago)

Edited August 18 (5 years ago)
The Aaron
Roll20 Production Team
API Scripter

Sorry for the delay.. worked 60 hours this week, been super busy.

Install this in both/all games:

/* global TokenMod */
on('ready',()=>{
    const OwnerAttrName = 'OwnerRoll20IDs';
    
    const assureOwnerID = (c, p, force = false) => {
        let cb = c.get('controlledby');

        if(cb.length && ! /\ball\b/i.test(cb)) {
            let shouldUpdate = force;
            let props = {
                type: 'attribute',
                characterid: c.id,
                name: OwnerAttrName
            };

            let attr = findObjs(props)[0];
            if(!attr) {
                attr = createObj('attribute', props);
                shouldUpdate = true;
            }

            if(shouldUpdate){
                attr.set({
                    current: c.get('controlledby')
                                .split(/,/)
                                .map( id => findObjs({ type: 'player', id })[0] )
                                .filter( p => undefined !== p )
                                .map( p => p.get('d20userid') )
                                .join(',')
                });
                return 1;
            }
        }
        return 0;
    };

    const restoreOwnersOnCharacter = (c) => {
        let props = {
            type: 'attribute',
            characterid: c.id,
            name: OwnerAttrName
        };
        let attr = findObjs(props)[0];
        if(attr){
            c.set({
                controlledby: attr.get('current')
                                .split(/,/)
                                .map( id => findObjs({ type: 'player', d20userid: id})[0] )
                                .filter( p => undefined !== p )
                                .map( p => p.id)
                                .join(',')
            });
            return 1;
        }
        return 0;
    };


    const considerChangeOnToken = (t) => setTimeout( () => {
        let token = getObj('graphic',t.id);
        if(token){
            let c = getObj('character',token.get('represents'));
            if(c){
                assureOwnerID(c,null,true);
            }
        }
    }, 100);


    on('change:character:controlledby', assureOwnerID );
    on('add:character', restoreOwnersOnCharacter );

    if('undefined' !== typeof TokenMod && TokenMod.ObserveTokenChange){
        TokenMod.ObserveTokenChange(considerChangeOnToken);
    }

    on('chat:message', (msg)=>{
        if('api' === msg.type && /^!update-ownership\b/i.test(msg.content) && playerIsGM(msg.playerid) ){

            let chars = findObjs({type: 'character'});
            let updates = 0;

            sendChat('',`/w gm <div><b>Considering <code>${chars.length}</code> characters for update.</b></div>`);

            const burndown = ()=>{
                let c = chars.shift();
                if(c){
                    updates += assureOwnerID(c,null,true);
                    setTimeout(burndown,0);
                } else {
                    sendChat('',`/w gm <div><b>Updated ownership on <code>${updates}</code> characters.</b></div>`);
                }
            };

            burndown();

        }

        if('api' === msg.type && /^!update-controlledby\b/i.test(msg.content) && playerIsGM(msg.playerid) ){
            let chars = findObjs({type: 'attribute', name: OwnerAttrName})
                .map(a=>getObj('character',a.get('characterid')))
                .filter( c => undefined !== c);
            let updates = 0;

            sendChat('',`/w gm <div><b>Considering <code>${chars.length}</code> character owners for update.</b></div>`);

            const burndown = ()=>{
                let c = chars.shift();
                if(c){
                    updates += restoreOwnersOnCharacter(c);
                    setTimeout(burndown,0);
                } else {
                    sendChat('',`/w gm <div><b>Updated controlledby on <code>${updates}</code> characters.</b></div>`);
                }
            };

            burndown();

        }
    });

});

This should be mostly automatic.  You'll need to run:
!update-ownership

In the Game you're copying from initially, but whenever you change controlled by it will keep things updated.

With this running, when you create a Character and modify it's controlled by, it will create an Attribute on the Character named "OwnerRoll20IDs", with the Roll20 IDs of each controlling player.  When you add that Character to another Game, either via the Character Vault or the Transmogrifier, the script will pull up that attribute and place the matching player's player ids in the controlled by.  If the Character only has All Players on it, it won't do anything to it.

If you find that you've moved over a character and it didn't set the controlled by (possibly because the API was inactive at the time), you can run:

!update-controlledby

And it will parse all characters with that attribute and reset their controlled by field.

Let me know if you run into any issues.

August 17 (5 years ago)
vÍnce
Pro
Sheet Author

Aaron=awesome sauce

;-)

August 17 (5 years ago)
The Aaron
Roll20 Production Team
API Scripter

Yeah, I'd been meaning to write something like this for a while. I had been handling it by setting the controlled by to all, then changing it with TokenMod, but this is cleaner and easier. The only real pickle is explaining that the GM of the source game needs to explicitly give themselves control of the character. I'll have to think about how to make that more apparent. 

August 18 (5 years ago)
The Aaron
Roll20 Production Team
API Scripter

Made a bugfix in the code around TokenMod interaction. 

August 18 (5 years ago)


The Aaron said:

Made a bugfix in the code around TokenMod interaction. 


:0!!

I'll test it out with my players ASAP and let you know how it goes, thank you!!

August 18 (5 years ago)
Pat S.
Forum Champion
Sheet Author

This might be something worthwhile to go into the stupid tricks thread.

August 18 (5 years ago)
vÍnce
Pro
Sheet Author

Pat S. said:

This might be something worthwhile to go into the stupid tricks thread.

Suggested title;

Request a new Roll20 feature/enhancement and wait for Aaron to create it in his "spare" time.

(even after his 60hr work week...)




August 18 (5 years ago)
keithcurtis
Forum Champion
Marketplace Creator
API Scripter

Aaron's script is really clever, but it's a script solution to a problem. Stupid Tricks is more about solving problems in ways (with scripts or tools) that they weren't necessarily intended for. That's why there's nothing in there like "Use Token-Mod! It's awesome!" (It is), but more about "If you want to do this thing, here's a way you can do it." And then show how Token-Mod could solve the problem, and if possible, how you might achieve the same goal without a script (though this last part isn't strictly necessary.)