How to initiate Python files in AlcScript?

Help bring our custom Ages to life! Share tips and tricks, as well as code samples with other developers.

How to initiate Python files in AlcScript?

Postby Egon » Sat Nov 20, 2010 10:57 am

Ok, so I have been reading a lots of materials today. Mainly: http://www.guildofwriters.com/wiki/Avatar_Animations_List

By following http://www.guildofwriters.com/wiki/Avatar_Animations_List#Callbacks:_Waiting_on_the_avatar I have been able to make avatar to do animation, followed by sound.

I also have Python script which I want to run, after sound.
Python script is working, becouse I was able to test it by launcihng it by quickscript/simpleclick.

But how do I launch Python script by pure AlcScript, inside "cmds" of responser?
Egon #2052375
Who You gonna call? Guild of Doorcallers! #5356672
Eder Tsogal/Delin Marathon
Image
User avatar
Egon
 
Posts: 284
Joined: Fri Nov 16, 2007 9:45 pm

Re: How to initiate Python files in AlcScript?

Postby D'Lanor » Sat Nov 20, 2010 11:37 am

It just so happens that I figured this out today. From a responder you can send a notify message to the Python file mod. You could call this an "undocumented feature". ;)

Code: Select all
                      - type: notifymsg
                        params:
                            receivers:
                              - pyfilemod:<pythonfile mod name>
                        waiton: 0


This would be the full AlcScript:

Code: Select all
<button name>:
    logic:
        modifiers:
          - name: <button name>
            cursor: poised
            flags:
              - localelement
            activators:
              - type: objectinvolume
                remote: <region name>
                triggers:
                  - any
            conditions:
              - type: activator
                activators:
                  - type: picking
              - type: objectinbox
                satisfied: true
            actions:
              - type: responder
                ref: :<soundresponder name>
        actions:
          - type: pythonfile
            name: <pythonfile mod name>
            pythonfile:
                file: <pythonfile name>
                parameters:
                  - type: responder
                    ref: :<soundresponder name>
          - type: responder
            name: <soundresponder name>
            responder:
                states:
                  - cmds:
                      - type: soundmsg
                        params:
                            receivers:
                              - 0011:<sound emitter name>
                            callbacks:
                              - type: eventcallbackmsg
                                params:
                                    receivers:
                                      - respondermod:<soundresponder name>
                                    user: 0
                                    event: 1
                            cmds:
                              - addcallbacks
                              - play
                        waiton: -1
                      - type: notifymsg
                        params:
                            receivers:
                              - pyfilemod:<pythonfile mod name>
                        waiton: 0
                    nextstate: 0
                    ncallbacks: 1
                    waittocmd:
                      - key: 0
                        msg: 0
                curstate: 0
                flags:
                  - detecttrigger

You have to use a callback message to make the notify message wait for the sound to finish. My actual code was longer so I hope the callback still works like this.
Then you would catch the notification in the Python code like this:

Code: Select all
respSound = ptAttribResponder(1, 'Resp: Play sound')

#skipping some stuff here

    def OnNotify(self, state, id, events):
        if (not PtWasLocallyNotified(self.key)):
            return
        if (id == respSound.id):
            print ('responder %d finished' % id)
"It is in self-limitation that a master first shows himself." - Goethe
User avatar
D'Lanor
 
Posts: 1980
Joined: Sat Sep 29, 2007 4:24 am

Re: How to initiate Python files in AlcScript?

Postby Egon » Sun Nov 21, 2010 6:15 am

D'Lanor wrote:It just so happens that I figured this out today. From a responder you can send a notify message to the Python file mod. You could call this an "undocumented feature". ;)

Ough. It was mind buggling that where was no real tutorials for such scenario. I mean: making avatar do something, then do some animation, then emit sound, then do some game logic with python, all in one run: isn't this a tipical scenario of using pythonmod?

Anyway, as everything regarding URU moding it didn't work at first time. In fact it styll not working.
I was playing with this since yesterday (lots of testing of diffrent variations) and I think that:
Code: Select all
                      - type: notifymsg
                        params:
                            receivers:
                              - pyfilemod:PythonModName
                        waiton: 1

Is not enough.

I got "waiton: 1", becouse I have couple of cmds in responder. I make avatar do animation, then after animation I play sound emiter, then I try to notify pymod, then I do avatar animation, and then again sound emieter. Everything after single player click.

My pymod script is thery simple now, no attribiutes are recived. Insted in methods I use:
Code: Select all
PtSendKIMessage(kKILocalChatStatusMsg, "OnNotify")

To write loggin messages about launching methods.
I attached the same script to the separate testing button with simpleclick.

Everything seams to work, except notifying pymod from my main button.

P.S.
Should I use ptModifier class or ptResponder class, and what is difrence between them?

P.S.2
Is it possible to use DynamicBookTemplate with avatar animations? I mean that after someone clicks on linking panel in the book, I would like to lauch an animation of avatar touching the book and then link avatar out.
Egon #2052375
Who You gonna call? Guild of Doorcallers! #5356672
Eder Tsogal/Delin Marathon
Image
User avatar
Egon
 
Posts: 284
Joined: Fri Nov 16, 2007 9:45 pm

Re: How to initiate Python files in AlcScript?

Postby D'Lanor » Sun Nov 21, 2010 8:33 am

Egon wrote:Ough. It was mind buggling that where was no real tutorials for such scenario. I mean: making avatar do something, then do some animation, then emit sound, then do some game logic with python, all in one run: isn't this a tipical scenario of using pythonmod?

It is one possible scenario. There isn't any typical scenario. What I mostly do with Python is capture the message from an activator > change sdl state > react to sdl change by running responder(s) and/or script. Had I known this method before then I would probably have used less timers which are not very reliable for oneshot mods (due to their variable running times).

Egon wrote:Anyway, as everything regarding URU moding it didn't work at first time. In fact it styll not working.
I was playing with this since yesterday (lots of testing of diffrent variations) and I think that:
Code: Select all
                      - type: notifymsg
                        params:
                            receivers:
                              - pyfilemod:PythonModName
                        waiton: 1

Is not enough.

I got "waiton: 1", becouse I have couple of cmds in responder. I make avatar do animation, then after animation I play sound emiter, then I try to notify pymod, then I do avatar animation, and then again sound emieter. Everything after single player click.

If you change the position of the sound emitter in the script the whole wait to command chain has to shift as well. In your case I think the script should look like this:

Code: Select all
<button name>:
    logic:
        modifiers:
          - name: <button name>
            cursor: poised
            flags:
              - localelement
            activators:
              - type: objectinvolume
                remote: <region name>
                triggers:
                  - any
            conditions:
              - type: activator
                activators:
                  - type: picking
              - type: objectinbox
                satisfied: true
            actions:
              - type: responder
                ref: :<soundresponder name>
        actions:
          - type: pythonfile
            name: <pythonfile mod name>
            pythonfile:
                file: <pythonfile name>
                parameters:
                  - type: responder
                    ref: :<soundresponder name>
          - type: responder
            name: <soundresponder name>
            responder:
                states:
                  - cmds:
                      - type: oneshotmsg
                        params:
                            receivers:
                              - oneshotmod:<oneshotmod name>
                            callbacks:
                              - marker: <marker name>
                                receiver: respondermod:<soundresponder name>
                                user: 0
                        waiton: -1
                      - type: soundmsg
                        params:
                            receivers:
                              - 0011:<sound emitter name>
                            callbacks:
                              - type: eventcallbackmsg
                                params:
                                    receivers:
                                      - respondermod:<soundresponder name>
                                    user: 1
                                    event: 1
                            cmds:
                              - addcallbacks
                              - play
                        waiton: 0
                      - type: notifymsg
                        params:
                            receivers:
                              - pyfilemod:<pythonfile mod name>
                        waiton: 1
                      - type: oneshotmsg
                        params:
                            receivers:
                              - oneshotmod:<oneshotmod name>
                            callbacks:
                              - marker: <marker name>
                                receiver: respondermod:<soundresponder name>
                                user: 2
                        waiton: -1
                      - type: soundmsg
                        params:
                            receivers:
                              - 0011:<sound emitter name>
                            cmds:
                              - play
                        waiton: 2
                    nextstate: 0
                    ncallbacks: 3
                    waittocmd:
                      - key: 0
                        msg: 0
                      - key: 1
                        msg: 1
                      - key: 2
                        msg: 3
                curstate: 0
                flags:
                  - detecttrigger

These callbacks are hard to get right. If you want to try out just the Python notification you could place it in its own test responder with waiton set to -1. btw, is PythonModName the actual name of your pythonfile mod?

Egon wrote:P.S.
Should I use ptModifier class or ptResponder class, and what is difrence between them?

ptResponder is derived from ptModifier. The only difference is that ptResponder when it initializes sets self.sceneobject to None. This is only relevant for the BuiltIn prp file. Anywhere else pythonfile mods are attached to scene objects. So in effect it makes no difference which one you use.

Egon wrote:P.S.2
Is it possible to use DynamicBookTemplate with avatar animations? I mean that after someone clicks on linking panel in the book, I would like to lauch an animation of avatar touching the book and then link avatar out.

Yes, that has been possible from version 4 onwards.
"It is in self-limitation that a master first shows himself." - Goethe
User avatar
D'Lanor
 
Posts: 1980
Joined: Sat Sep 29, 2007 4:24 am

Re: How to initiate Python files in AlcScript?

Postby Egon » Mon Nov 22, 2010 9:11 am

D'Lanor wrote:
Egon wrote:P.S.2
Is it possible to use DynamicBookTemplate with avatar animations? I mean that after someone clicks on linking panel in the book, I would like to lauch an animation of avatar touching the book and then link avatar out.

Yes, that has been possible from version 4 onwards.

O yeah, this one worked just fine :)

D'Lanor wrote:These callbacks are hard to get right. If you want to try out just the Python notification you could place it in its own test responder with waiton set to -1. btw, is PythonModName the actual name of your pythonfile mod?

I wanted to avoid this so I would not spoil my suprise, but I see no other way.
Here is my full code regarding issue Show Spoiler
Egon #2052375
Who You gonna call? Guild of Doorcallers! #5356672
Eder Tsogal/Delin Marathon
Image
User avatar
Egon
 
Posts: 284
Joined: Fri Nov 16, 2007 9:45 pm

Re: How to initiate Python files in AlcScript?

Postby D'Lanor » Mon Nov 22, 2010 10:53 am

I see only 2 errors. A few indentation errors and a wrong msg number for the last callback key. Oh, and perhaps omitted : characters for the named refs (not sure if that is needed within the same scene object but better safe than sorry).

It would also be helpful if you could indicate where exactly it stops.

Show Spoiler

I put it between spoiler tags as well, but if you played Adrael you'd know it isn't that big a surprise. ;)

Show Spoiler
"It is in self-limitation that a master first shows himself." - Goethe
User avatar
D'Lanor
 
Posts: 1980
Joined: Sat Sep 29, 2007 4:24 am

Re: How to initiate Python files in AlcScript?

Postby Egon » Mon Nov 22, 2010 3:27 pm

So I copied You version and got the same result.

D'Lanor wrote:It would also be helpful if you could indicate where exactly it stops.


I does not. It goes all the way. Avatar does animation, then sound is heard, then nothing for a moment (which suggest that Python should be launcnhing OnNotify, but I don't see my testing message in KI), then avatar makes animation one more time, and last sound is being emited one more time.

Code: Select all
waittocmd:
                      - key: 0
                        msg: 0
                      - key: 1
                        msg: 1
                      - key: 2
                        msg: 3

Ok, I though that I understood this, but You got me lost. I though that above we should interpret as associative array, which looks like this:
waittocmd[0]=0
waittocmd[1]=1
waittocmd[2]=3
And when in callback we write:
Code: Select all
user: 0

we mean: "return waittocmd[0]"
and in waiton we write value of waittocmd[0].
I that was true, then with such waittocmd, lines:
Code: Select all
                      - type: oneshotmsg
                        params:
                            receivers:
                              - oneshotmod:InsertKIHandOneShot
                            callbacks:
                              - marker: HandIn
                                receiver: respondermod:insertKiResponder
                                user: 2
                        waiton: -1
                      - type: soundmsg
                        params:
                            receivers:
                              - 0011:InsertKIEmitter
                            cmds:
                              - play
                              - setvolume
                            volume: 0.8
                        waiton: 2

should look like this:
Code: Select all
                      - type: oneshotmsg
                        params:
                            receivers:
                              - oneshotmod:InsertKIHandOneShot
                            callbacks:
                              - marker: HandIn
                                receiver: respondermod:insertKiResponder
                                user: 2
                        waiton: -1
                      - type: soundmsg
                        params:
                            receivers:
                              - 0011:InsertKIEmitter
                            cmds:
                              - play
                              - setvolume
                            volume: 0.8
                        waiton: 3

(last waiton)

In lines:
Code: Select all
user: 1
event: 1

What "event: 1" stands for?

D'Lanor wrote:I put it between spoiler tags as well, but if you played Adrael you'd know it isn't that big a surprise. ;)

I see Your point, but I don't fully agree (what I'm saying: just wait and see ;) )

D'Lanor wrote:btw, I would use the SndHandIn marker.

Ok, why? (btw: I followed this. It needs update?)
Egon #2052375
Who You gonna call? Guild of Doorcallers! #5356672
Eder Tsogal/Delin Marathon
Image
User avatar
Egon
 
Posts: 284
Joined: Fri Nov 16, 2007 9:45 pm

Re: How to initiate Python files in AlcScript?

Postby D'Lanor » Mon Nov 22, 2010 4:05 pm

Let me explain it this way. "key" counts the messages with a callback starting from 0. So this is always sequential. "msg" counts all the messages including those without a callback. Since the notify message does not contain a callback key you actually skip one message and so callback key 2 resides in message 3.

"user" should always match the key. "event" remains the same throughout the responder.

I don't really understand the logic behind all of this. I just figured it out though trial and error, but I do know that it works. I must have written thousands of AlcScript lines based on this. :shock:

Wait, are you using that PtSendKIMessage for debugging? In that case does your Python file import PlasmaKITypes? If not it will throw an error. What does your Python.0.elf log file say?

That avatar animation has two markers. SndHandIn is specifically for the sound and kicks in earlier than HandIn. So which one you would use depends on what you want. I guess the wiki does need updating.
"It is in self-limitation that a master first shows himself." - Goethe
User avatar
D'Lanor
 
Posts: 1980
Joined: Sat Sep 29, 2007 4:24 am

Re: How to initiate Python files in AlcScript?

Postby Egon » Tue Nov 23, 2010 1:03 am

D'Lanor wrote:Let me explain it this way. "key" counts the messages with a callback starting from 0. So this is always sequential. "msg" counts all the messages including those without a callback. Since the notify message does not contain a callback key you actually skip one message and so callback key 2 resides in message 3.

"user" should always match the key. "event" remains the same throughout the responder.

I don't really understand the logic behind all of this. I just figured it out though trial and error, but I do know that it works. I must have written thousands of AlcScript lines based on this. :shock:

Ok. I see a some wiki updates in the future :geek:

D'Lanor wrote:Wait, are you using that PtSendKIMessage for debugging? In that case does your Python file import PlasmaKITypes? If not it will throw an error. What does your Python.0.elf log file say?

Yes it does. Like I sad: I have attached the same Python file to another button with simpleclick, for testing purposes, and it works on the testing button.

I knew I should give python code also:
Code: Select all
from Plasma import *
from PlasmaTypes import *
from PlasmaKITypes import *
from PlasmaNetConstants import *
import PlasmaControlKeys
import xLocalization

#respSound = ptAttribResponder(1, 'Resp: Play sound')

class NexusStation(ptModifier,):
    __module__ = __name__

    def __init__(self):
        ptModifier.__init__(self)
        self.id = 10673
        self.version = 1


    def OnNotify(self, state, id, events):
        print ('OnNotify');
        PtSendKIMessage(kKILocalChatStatusMsg, "OnNotify")
        #if (not PtWasLocallyNotified(self.key)):
        #    return
        #if (id == respSound.id):
        #    print ('responder %d finished' % id)
            #PtSendKIMessage(kKILocalChatStatusMsg, xLocalization.xKI.xKIStatusNexusLinkAdded)       


    def OnFirstUpdate(self):
        print ('OnFirstUpdate');
        PtSendKIMessage(kKILocalChatStatusMsg, "OnFirstUpdate")
        pass


    def OnServerInitComplete(self):
        pass


    def OnSDLNotify(self, VARname, SDLname, playerID, tag):
        pass




glue_cl = None
glue_inst = None
glue_params = None
glue_paramKeys = None
try:
    x = glue_verbose
except NameError:
    glue_verbose = 0

def glue_getClass():
    global glue_cl
    if (glue_cl == None):
        try:
            cl = eval(glue_name)
            if issubclass(cl, ptModifier):
                glue_cl = cl
            elif glue_verbose:
                print ('Class %s is not derived from modifier' % cl.__name__)
        except NameError:
            if glue_verbose:
                try:
                    print ('Could not find class %s' % glue_name)
                except NameError:
                    print 'Filename/classname not set!'
    return glue_cl



def glue_getInst():
    global glue_inst
    if (type(glue_inst) == type(None)):
        cl = glue_getClass()
        if (cl != None):
            glue_inst = cl()
    return glue_inst



def glue_delInst():
    global glue_inst
    global glue_cl
    global glue_paramKeys
    global glue_params
    if (type(glue_inst) != type(None)):
        del glue_inst
    glue_cl = None
    glue_params = None
    glue_paramKeys = None



def glue_getVersion():
    inst = glue_getInst()
    ver = inst.version
    glue_delInst()
    return ver



def glue_findAndAddAttribs(obj, glue_params):
    if isinstance(obj, ptAttribute):
        if glue_params.has_key(obj.id):
            if glue_verbose:
                print 'WARNING: Duplicate attribute ids!'
                print ('%s has id %d which is already defined in %s' % (obj.name,
                 obj.id,
                 glue_params[obj.id].name))
        else:
            glue_params[obj.id] = obj
    elif (type(obj) == type([])):
        for o in obj:
            glue_findAndAddAttribs(o, glue_params)

    elif (type(obj) == type({})):
        for o in obj.values():
            glue_findAndAddAttribs(o, glue_params)

    elif (type(obj) == type(())):
        for o in obj:
            glue_findAndAddAttribs(o, glue_params)




def glue_getParamDict():
    global glue_paramKeys
    global glue_params
    if (type(glue_params) == type(None)):
        glue_params = {}
        gd = globals()
        for obj in gd.values():
            glue_findAndAddAttribs(obj, glue_params)

        glue_paramKeys = glue_params.keys()
        glue_paramKeys.sort()
        glue_paramKeys.reverse()
    return glue_params



def glue_getClassName():
    cl = glue_getClass()
    if (cl != None):
        return cl.__name__
    if glue_verbose:
        print ('Class not found in %s.py' % glue_name)
    return None



def glue_getBlockID():
    inst = glue_getInst()
    if (inst != None):
        return inst.id
    if glue_verbose:
        print ('Instance could not be created in %s.py' % glue_name)
    return None



def glue_getNumParams():
    pd = glue_getParamDict()
    if (pd != None):
        return len(pd)
    if glue_verbose:
        print ('No attributes found in %s.py' % glue_name)
    return 0



def glue_getParam(number):
    pd = glue_getParamDict()
    if (pd != None):
        if (type(glue_paramKeys) == type([])):
            if ((number >= 0) and (number < len(glue_paramKeys))):
                return pd[glue_paramKeys[number]].getdef()
            else:
                print ('glue_getParam: Error! %d out of range of attribute list' % number)
        else:
            pl = pd.values()
            if ((number >= 0) and (number < len(pl))):
                return pl[number].getdef()
            elif glue_verbose:
                print ('glue_getParam: Error! %d out of range of attribute list' % number)
    if glue_verbose:
        print 'GLUE: Attribute list error'
    return None



def glue_setParam(id, value):
    pd = glue_getParamDict()
    if (pd != None):
        if pd.has_key(id):
            try:
                pd[id].__setvalue__(value)
            except AttributeError:
                if isinstance(pd[id], ptAttributeList):
                    try:
                        if (type(pd[id].value) != type([])):
                            pd[id].value = []
                    except AttributeError:
                        pd[id].value = []
                    pd[id].value.append(value)
                else:
                    pd[id].value = value
        elif glue_verbose:
            print "setParam: can't find id=",
            print id
    else:
        print 'setParma: Something terribly has gone wrong. Head for the cover.'



def glue_isNamedAttribute(id):
    pd = glue_getParamDict()
    if (pd != None):
        try:
            if isinstance(pd[id], ptAttribNamedActivator):
                return 1
            if isinstance(pd[id], ptAttribNamedResponder):
                return 2
        except KeyError:
            if glue_verbose:
                print ('Could not find id=%d attribute' % id)
    return 0



def glue_isMultiModifier():
    inst = glue_getInst()
    if isinstance(inst, ptMultiModifier):
        return 1
    return 0



def glue_getVisInfo(number):
    pd = glue_getParamDict()
    if (pd != None):
        if (type(glue_paramKeys) == type([])):
            if ((number >= 0) and (number < len(glue_paramKeys))):
                return pd[glue_paramKeys[number]].getVisInfo()
            else:
                print ('glue_getVisInfo: Error! %d out of range of attribute list' % number)
        else:
            pl = pd.values()
            if ((number >= 0) and (number < len(pl))):
                return pl[number].getVisInfo()
            elif glue_verbose:
                print ('glue_getVisInfo: Error! %d out of range of attribute list' % number)
    if glue_verbose:
        print 'GLUE: Attribute list error'
    return None


Python.0.elf says nothing. I mean: It has printed "OnFirstUpdate" (twice. I assume it's becouse I use this file twice.) but no "OnNotify".
Egon #2052375
Who You gonna call? Guild of Doorcallers! #5356672
Eder Tsogal/Delin Marathon
Image
User avatar
Egon
 
Posts: 284
Joined: Fri Nov 16, 2007 9:45 pm

Re: How to initiate Python files in AlcScript?

Postby D'Lanor » Tue Nov 23, 2010 4:38 am

You have commented out the ptAttribResponder line. I highly doubt Python could accept a notification from a responder it does not know about.
"It is in self-limitation that a master first shows himself." - Goethe
User avatar
D'Lanor
 
Posts: 1980
Joined: Sat Sep 29, 2007 4:24 am

Next

Return to Scripting

Who is online

Users browsing this forum: No registered users and 0 guests

cron