Escher's Relativity is doable

If you feel like you're up to the challenge of building your own Ages in Blender or 3ds Max, this is the place for you!

Re: Escher's Relativity is doable

Postby tachzusamm » Sat Sep 24, 2011 10:27 am

Some news again. 8-)

I've been able to manage First-Person camera handling.
So from now on, it's also possible to switch using F1 to a pseudo-FP mode (not the real FP mode, because this still gives a rotated view), while you are in a SubWorld.
So, actually everywhere.
Technically: Because it was not possible to redirect F1 presses to Python(AFAIK), I did this by polling FP mode - and as soon as this gets activated, I switch to a FP-style camera. May sound stupid, but it was the only way. Gives short glitches for second's fraction, because real FP is shown first, but no way around it.
This pseudo-cam has still exchanged X and Z axis on panning, so I reduced the panning to Z only, so we can only pan up and down - looking around in X direction can be done with rotating yourself (the avatar). Allowing X also for panning was too confusing.
Still a bit unusual, but better than nothing.

Oh, and: Multiplayer-mode already works fine. :D

A final problem:
When a player links out using his Relto book while occupying a Transporter, this Transporter keeps blocked (until the player returns and re-enables it, or all others left the age and return).
(Quitting the game or crashes of a player's client are already handled. Well, at least the code is ready; thanks to AvatarPage(). But this seems to not detects links.)

Does somebody know how it can be detected in Python if a player has linked out?


Edit: Oh, by the way... I'm not sure if I should ask Diafero to upload the current version to Deep Island for some, umm, Beta-Testing this weekend, with more players.
So, should I? Or do we better add gardens first?
User avatar
tachzusamm
 
Posts: 575
Joined: Thu May 29, 2008 2:03 am
Location: Germany

Re: Escher's Relativity is doable

Postby Karkadann » Sat Sep 24, 2011 10:59 am

It would definitely be great as is but I was hoping to use this as an example of what can be accomplished with a collaboration, as I said before the some of the best age's I have seen are the work of several people all skilled in one particular area. At the same time too many cooks spoil the broth, If we can balance the two we can make something Magical.

Posting the finished product would definitely increase the WOW factor and may inspire others
The Optimist see's the glass half full, The Pessimist see's the glass half empty.
Its the Realist who see's the glass is half full with air, half full with water
User avatar
Karkadann
 
Posts: 1223
Joined: Sun Aug 02, 2009 10:04 am
Location: Earth

Re: Escher's Relativity is doable

Postby Sirius » Sat Sep 24, 2011 11:28 am

Awesome work :shock: .


Detecting links (and other actions from the avatar, as jumping) is a bit complicated.
You must use
Code: Select all
PtGetLocalAvatar().avatar.registerForBehaviorNotify(self.key)
on your avatar.
"self.key" is the key of your Python file (you can also set the key of another Python script if you want 8-) ).

The receiving script should have this method:
Code: Select all
def OnBehaviorNotify(self, type, id, state):
    if ((type == PtBehaviorTypes.kBehaviorTypeLinkIn) and (not (state))):
        # some Python command
That's from the Cleft python file, I don't really know what "state" is (maybe to indicate if the avatar is starting or stopping his action ?). "id" should be the id of the avatar. IIRC you can find back the avatar thanks to PtGetAvatarKeyFromClientID(id)).

However, beware that it might receive a LOT of notifies. Everytime the avatar starts doing something, it will be send to the script.
All the possible messages:
Code: Select all
kBehaviorTypeIdle = 32
kBehaviorTypeStandingJump = 1
kBehaviorTypeWalkingJump = 2
kBehaviorTypeSidestepRight = 4096
kBehaviorTypeRunningJump = 4
kBehaviorTypeTurnRight = 1024
kBehaviorTypeAnyJump = 7
kBehaviorTypeRunningImpact = 8
kBehaviorTypeWalk = 64
kBehaviorTypeRun = 128
kBehaviorTypeWalkBack = 256
kBehaviorTypeMovingTurnLeft = 16384
kBehaviorTypeGroundImpact = 16
kBehaviorTypeFall = 8192
kBehaviorTypeTurnLeft = 512
kBehaviorTypeAnyImpact = 24
kBehaviorTypeLinkOut = 131072
kBehaviorTypeMovingTurnRight = 32768
kBehaviorTypeLinkIn = 65536
kBehaviorTypeSidestepLeft = 2048


Don't forget this once your avatar linked out:
Code: Select all
PtGetLocalAvatar().avatar.unRegisterForBehaviorNotify(self.key)


Hope it helps.
You might want to check the Gira/Kemo python files, they use it a lot for fireflies.

EDIT: for your first-person cam glitch, you might try to use this:
- disable first person and de-activate first person override
- use PtEnableControlKeyEvents(self.key) to tell the Python script to be notified of key hit/release
- add OnControlKeyEvent(self, controlKey, activeFlag) in your Python file - controlKey is the id of the key (see PlasmaControlKeys.py), activeFlag tells if it was pressed or released.
- if the player hits F1, the camera won't be automatically switched as you disabled it. This is where you add your function to switch you cams ;)
- beware: once again it will receive a LOT of notifies, as Mouse Drag (might be useful to pan the camera on the X-axis? ...)
- reactivate first person override on linking out, and use PtDisableControlKeyEvents(self.key) on your script.
I used control key events a lot for a script these past few days, and that's really useful.
User avatar
Sirius
 
Posts: 1506
Joined: Mon Jul 26, 2010 4:46 am
Location: France

Re: Escher's Relativity is doable

Postby D'Lanor » Sat Sep 24, 2011 4:48 pm

Yes, OnBehaviorNotify would work though I usually prefer BeginAgeUnload. Both methods can only be detected by the player who links out. However you want to let the remaining players know that the operator has gone AWOL. Therefore you have to use an SDL variable which keeps track of the operator ID (if you are not doing that already).

For example:
Code: Select all
    def BeginAgeUnLoad(self, avatar):
        # Only works when operator links out.
        # Can be detected by operator only who must reset SDL before leaving.
        ageSDL = PtGetAgeSDL()
        avID = PtGetClientIDFromAvatarKey(avatar.getKey())
        if (avID == ageSDL[stringVarName.value][0]):
            PtDebugPrint('BeginAgeUnLoad: Operator paging out, reset SDL before I go...')
            ageSDL[stringVarName.value] = (-1,)


Then you can do your correction stuff under OnSDLNotify. I have successfully used this in one of my test ages.

Edit: AvatarPage btw fails because when the operator links out the client ID always returns -1 instead of the actual ID (presumably because the operator is registered to another age by then?). So as an alternative you could listen for ID -1 and then check if the operator recorded in the SDL is still present in the age. This method I have also used successfully.
"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: Escher's Relativity is doable

Postby tachzusamm » Sun Sep 25, 2011 1:13 am

Again lots of useful tipps, Sirius. Thank you very much. :)
I think I will test some of the methods you mentioned, sounds promising.
Especially PtEnableControlKeyEvents(self.key) was something I did get working before - must have missed something. That would be great if I can avoid allowing FP mode and switching it back off if detected.

Sirius wrote:I used control key events a lot for a script these past few days, and that's really useful.

Seems you dive deeply into the Plasmy Python API and have fun trying everything out. That's a good thing. ;)


D'Lanor wrote:Yes, OnBehaviorNotify would work though I usually prefer BeginAgeUnload.

Hey, that sounds good !
I somehow missed that such a method exists - although I think I must hav read the Plasma Python API now about five times top to bottom and up to top again. lol.

D'Lanor wrote:However you want to let the remaining players know that the operator has gone AWOL. Therefore you have to use an SDL variable which keeps track of the operator ID (if you are not doing that already).

Yeah, doing that already.

D'Lanor wrote:Then you can do your correction stuff under OnSDLNotify. I have successfully used this in one of my test ages.

I'm sure you have, and I'm wondering how many test ages you already made... *grin*

D'Lanor wrote:AvatarPage btw fails because when the operator links out the client ID always returns -1 instead of the actual ID (presumably because the operator is registered to another age by then?). So as an alternative you could listen for ID -1 and then check if the operator recorded in the SDL is still present in the age. This method I have also used successfully.

Aha. That describes why it fails. Nice trick to listen for -1 - could be used as a last-chance trap.


Thanks a lot !
User avatar
tachzusamm
 
Posts: 575
Joined: Thu May 29, 2008 2:03 am
Location: Germany

Re: Escher's Relativity is doable

Postby diafero » Sun Sep 25, 2011 1:34 pm

As for catching events like linking out or key presses, have a look at the xUserKI files from the Offline KI (the source code is available at http://www.the-deep-island.de/uru-ages/ ... src.tar.gz ). Check the handler you are interested in, and then look in xKI to see where and how it is called.
I prefer e-mails to "diafero arcor de" (after adding the at and the dot) over PMs.

"Many people's horizon is a circle with a radius of zero. They call it their point of view."

Deep Island Shard | Offline KI
diafero
Deep Island Admin
 
Posts: 2966
Joined: Mon May 05, 2008 5:50 am
Location: Germany

Re: Escher's Relativity is doable

Postby tachzusamm » Mon Sep 26, 2011 11:39 am

This ugly Plasma SDL handling is going to drive me crazy. :o

First, BeginAgeUnload() seems to be never called (at least offline, the platform I use for rapid testing); well, does not matter, because I got OnBehaviorNotify() working and do the job.

It works as expected as I can see (and I can see that the Transporter chains stops as soon as my avatar touches the Relto book).

BUT: When I enter the Age again, the chain runs again, so the SDL state gets NOT stored.

To explain it more briefly, here's what happens (lets omit OperatorID and such stuff to simplify, I will just talk about True/False, 1/0):
- When I set SDL to 0 on leaving a region, it's still 0 on re-enter. Okay so far.
- When I set SDL to 0 in OnBehaviorNotify() (short time before leaving), I can see it happening, because it passes to OnSDLNotify(), where it gets the correct state (0) detected, which makes the animation stop - which I can see a moment before avatar and Age fades out. (And logging actions reveals that everything goes okay, looking at the log)
- But on re-entering, SDL is again 1. What's up with THAT?

Having a deeper look into it with VaultShop, I found that the SDL variable is correctly set in the VAULT after paging out (so it's 0 in the vault), but under saves, there's an additional "AgeSDLHook" object - and in THAT object the variable is still 1. Seems AgeSDLHook works for early SDL changes (leaving a region), but when set shortly before I link out, the value does not make it to AgeSDLHook, but to the vault only. (By the way, OperatorID and such behave the same).

Hmmm..

So what is the recommended method for reading correct SDL values back, or setting them correctly?
In other words, how can I read from the vault instead of AgeSDLHook - IF this is recommended?
Or, should I ignore this because there's a chance that it behaves different online?


By the way, avoiding glitches using ControlKey events worked very well. :)
Looks much better now. Thanks again for the hints.

(Sirius, did you really manage to get Mouse drags captured? If yes, how? I was only able to detect key presses.)
User avatar
tachzusamm
 
Posts: 575
Joined: Thu May 29, 2008 2:03 am
Location: Germany

Re: Escher's Relativity is doable

Postby D'Lanor » Mon Sep 26, 2011 12:57 pm

If simple state variables fail there is usually a fundamental error in the way the AgeSDLHook is set up. You could start looking there. The fact that BeginAgeUnload is not called is also very strange (unless you are using global prp files or something like that).

About the vault SDL, you should not use it unless you need to change SDL variables across ages. But whatever you do, never use both because offline (and in Alcugs) they are not synched. If you switch over from one to the other now the age might become "confused" even more than it already is.

These things are always tough to troubleshoot. Once you checked the AgeSDLHook you could try deleting the sav file and see if that makes any difference.
"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: Escher's Relativity is doable

Postby tachzusamm » Mon Sep 26, 2011 1:24 pm

D'Lanor wrote:If simple state variables fail there is usually a fundamental error in the way the AgeSDLHook is set up.

AgeSDLHook setup? Umm, I assume you mean a block in OnFirstUpdate() like this?
Code: Select all
        global TID
        TID = "0"+str(intTransID.value)    # unique Transporter ID
        ageSDL = PtGetAgeSDL()
        ageSDL.setFlags("boolOperated"+TID,1,1)
        ageSDL.setFlags("TravellerID"+TID,1,1)
        ageSDL.setFlags("ChainRunning"+TID,1,1)
       
        ageSDL.sendToClients("boolOperated"+TID)
        ageSDL.sendToClients("TravellerID"+TID)
        ageSDL.sendToClients("ChainRunning"+TID)
       
        # register for notification of age SDL var changes
        ageSDL.setNotify(self.key,"ChainRunning"+TID,0.0)

        # (boolOperated / TravellerID do not need notification because those are queried when needed)
       
        # Elevator handling
        if (self.isElevator):
            ageSDL.setFlags("ElevStatus"+TID,1,1)
            ageSDL.sendToClients("ElevStatus"+TID)
            ageSDL.setNotify(self.key,"ElevStatus"+TID,0.0)

By the way, they do not fail completely - they work perfectly on region exits. The only problem is when the state is changed soon befor link out.
But to be honest: I do not really understand what setFlags() and sendToClients() do. Which flags are set? When is something sent to Clients?
Only setNotify() gives me a real idea.

D'Lanor wrote:The fact that BeginAgeUnload is not called is also very strange (unless you are using global prp files or something like that).

No, I don't use any global PRP files.

Here's BeginAgeUnload() as a snippet of the script, as an example:
Code: Select all
    def BeginAgeUnload(self, avatar):                  # Multiplayer handling
        "reset accessibility if user links out"            # ~~~~~~~~~~~~~~~~~~~~
        print ('---%s.BeginAgeUnload()' % self.cn)   # (Seems not to be called ever)
       
        if (self.ControlKeysTrapped):
            PtDisableControlKeyEvents(self.key)
            self.ControlKeysTrapped = False
       
        if (self.FirstPersonOverriden):
            ptCamera().enableFirstPersonOverride()
            self.FirstPersonOverriden = False
       
        # Make sure player re-enables occupied Transporter
        ageSDL = PtGetAgeSDL()
        avID = PtGetClientIDFromAvatarKey(avatar.getKey())
        if (avID == ageSDL["TravellerID"+TID][0]):
            self.ILockTransporter(None, False)
            self.PlayChainRun(kPlayStop)
            print("%s.BeginAgeUnLoad(): Operator (ID=%d) linked out, reenabled Transporter #%d." % (self.cn, avID, intTransID.value))


D'Lanor wrote:About the vault SDL, you should not use it unless you need to change SDL variables across ages. But whatever you do, never use both because offline (and in Alcugs) they are not synched. If you switch over from one to the other now the age might become "confused" even more than it already is.

Okay. So PtGetAgeSDL() and related functions are all I need and I should avoid functions from the ptAgeVault class?
Already did it this way. Really strange.

D'Lanor wrote:These things are always tough to troubleshoot. Once you checked the AgeSDLHook you could try deleting the sav file and see if that makes any difference.

It did not make any difference if I deleted the .sav file.
:roll:


UPDATE: Oh, wait, it's BeginAgeUnLoad(), not BeginAgeUnload(). Ding, dong, Dang!
Well, I'll test that soon.

UPDATE2: Okay, BeginAgeUnLoad() is called now, and it does what it should.
Or, better said, it does nothing - because "if (avID == ageSDL["TravellerID"+TID][0])" evaluates already to false, since the ID was already cleared in OnBehaviorNotify(), which is called prior to BeginAgeUnLoad(). Completely logical.
So the SDL value is definitely cleared on link out - and it's STILL again set on the next link in.

:shock: :shock:
User avatar
tachzusamm
 
Posts: 575
Joined: Thu May 29, 2008 2:03 am
Location: Germany

Re: Escher's Relativity is doable

Postby D'Lanor » Mon Sep 26, 2011 6:29 pm

tachzusamm wrote:AgeSDLHook setup? Umm, I assume you mean a block in OnFirstUpdate() like this?

No, I mean this Blender setting in "Book"...
Code: Select all
config:
   agesdlhook: True

...and the Python file which has the same name/class as the age in order to "activate" it.

tachzusamm wrote:By the way, they do not fail completely - they work perfectly on region exits. The only problem is when the state is changed soon befor link out.
But to be honest: I do not really understand what setFlags() and sendToClients() do. Which flags are set? When is something sent to Clients?
Only setNotify() gives me a real idea.

Ok, if they do not fail completely I guess your AgeSDLHook is alright. I have never experimented with setFlags() and sendToClients() because well... their settings are the same in every Python file, just as you are setting them. Plasma.py tells us the following about setFlags():

Code: Select all
    def setFlags(self, name, sendImmediate, skipOwnershipCheck):
        pass

So I guess flag 1 makes sense for those two. setFlags() is always paired with sendToClients() which sends a new value to all players.

setNotify() is only required if you want to receive a notification for OnSDLNotify. It tells the clients that there was a change of the SDL value, who changed it etc., but... funny enough it does not send the new value itself. That is why we still have to query the SDL variable for its value (which we should have received through sendToClients).

From what I can see you have everything set correctly so I don't know where that reset is coming from. Can you show us the full Python code?
"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

PreviousNext

Return to Building

Who is online

Users browsing this forum: Google [Bot] and 0 guests