Time to wire - but where to start?

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

Time to wire - but where to start?

Postby ametist » Sat Apr 25, 2020 8:47 am

Now I would appreciate some help - or a lot of help! I feel quite lost, I can write C# so I am familiar with the terms, 'booleans, 'integer's etc, but python is new. Back in the day D'Lanor and diafero did all that work for me ;). I am almost ready with my age so it is time to start wiring. I am using korman nodes to open and close doors and animations to start etc, and them nodes are extremly easy to set up!
But of course I will need SDL states to get it all to work properly. I have some puzzles, I have some things that should be triggered 'if', I have objects that I want to be disabled at start etc. I have read the documentation several times, but I cant really figure out where to start...
I assume I have to start with the.sdl file, setting all states there. But I dont even know where I write that file, or how? After that I would hook those states up to the x...py files I will need, in a node, I get that. But do I only use the global .py files for that, or do I have to write my own? I understand I have to do that in PlasmaShop, but I dont know how?
User avatar
ametist
 
Posts: 354
Joined: Fri Dec 28, 2007 6:55 am

Re: Time to wire - but where to start?

Postby Sirius » Sun Apr 26, 2020 12:00 pm

Okay... Once you get the hang of it, it's not so bad, but my explanation is going to be a bit long.

ametist wrote:I assume I have to start with the.sdl file, setting all states there. But I dont even know where I write that file, or how?

That's almost correct. There is just one small step before this, which is going into your world settings in Blender, and tick the "Age Global SDL" checkbox (this is required to tell the game to load the SDL file for your Age).
As you probably guessed, the SDL file describes the variables used throughout your Age, along with their default value. This is similar to declaring class members in C#. The thing to remember, is that this is the ONLY way to synchronize information between two different clients, and the ONLY thing that will save progress in the Age. (Well, to be honest there are of course other mechanisms, but it's best to stick to SDL.)
Right now Korman doesn't have an SDL editor, so you will have to write it by hand. Since you're familiar with programming languages this shouldn't be too hard.

Creating the SDL file is fairly simple - you can do it in PlasmaShop, and you just save it in Uru's "SDL" folder, with the same file name as your Age.
As for the content, here is an example which you can copy and paste.
Code: Select all
#==============================================================
# READ:   When modifying an SDL record, do *not* modify the
#   existing record. You must copy and paste a new version
#   below the current one and make your changes there.
#==============================================================

STATEDESC YourAgeFileNameHere # obviously replace with your Age's filename !
{
   VERSION 1

    VAR BOOL    myBooleanVariable[1] DEFAULT=0
    VAR BOOL    anotherBooleanVariable[1] DEFAULT=1
    VAR BYTE    aSmallNumber[1] DEFAULT=3
    VAR SHORT   aBiggerNumber[1] DEFAULT=12000
    VAR INT     aVeryBigNumber[1] DEFAULT=432489
    VAR STRING32 someText[1] DEFAULT="Hello, world !"
}

Now let's recap what each thing does...
  • You probably guessed it, the # character marks a comment, like the C# "//" equivalent.
  • "STATEDESC YourAgeFileNameHere {}" is similar to "class MyClass {}" in C#.
  • The VERSION number indicates the revision number of the "STATEDESC" you just declared. For now, set it to 1, we'll come back to it later.
  • "VAR BOOL..." etc is your variable - this should feel familiar. The number in brackets [1] indicates the number of values held by this variable - that's right, every SDL variable is actually an array. Usually you just leave it as 1 for normal variables, arrays are rarely useful (and they can't be resized anyway). DEFAULT is the default value it has when you first link there. If you study Cyan's SDL files, you will notice some extra options like DEFAULTOPTION or DISPLAYOPTION - don't bother with those.

Now, a word of warning, which you may already have heard of previously. SDL descriptions (everything between the curly braces) should NEVER be modified once the file is saved and you linked to your Age. This usually confuses Uru, and may result in corrupting your save of the Age.
So, how do you add variables once you've linked once to your Age ? Simple. Copy and paste the whole "STATEDESC YourAgeFileNameHere {...}" block under the existing one, and increase its version number. Uru will notice the new version number, and will do the appropriate to avoid issues. This is why usually people leave the disclaimer at the top of the file.
(I'm not sure how Uru reacts to altering a variable's description. Might be better to avoid it altogether, and only add new variables...)
If you ever suspect SDLs to be corrupted in your Age, you can simply delete the corresponding ".sav" file somewhere in your "SAV" folder in Uru. This will reset the Age to zero. This can theoretically be done if you don't want to create a new version of the statedesc, but it's not considered best practice.

Now that your SDL is written, you can link to your Age, and use the Offline-KI's /listsdl, /getsdl and /setsdl commands. This won't have any effect for now, but you will be able to observe how any modification to SDLs are stored for later...

[I'll continue this in another post soon]
User avatar
Sirius
 
Posts: 1372
Joined: Mon Jul 26, 2010 4:46 am
Location: France

Re: Time to wire - but where to start?

Postby Sirius » Sun Apr 26, 2020 12:39 pm

Now, to actually make those SDL variables do something in-game...

Let's ignore actual puzzles like Gahreesen's power room, which are fairly complex. Instead, let's just focus on understanding how Uru handles a simple door (an animated object with a sound playing when opened), which you can open via a clickable button.

Like I said, SDL variables are the only method of synchronisation between two players - animations and played sounds are (usually) not synchronized between players.
Which means, usually you don't "bind" a button to a door opening, because only the local player would see the door animate. Instead, you "bind" a button to an SDL var, then you "bind" this SDL var to the door opening animation. Uru will handle telling all other clients that the SDL was modified, which in turn will trigger the "opening" animation/sound for each player.

Python is the way to create this "bind" between a button/lever (aka "Activator") and an SDL var, or between an SDL var and a list of animations/sounds to play (aka "Responder"). A single script can do both, or only one of those "binds".

Now, as you can guess, there are some cases which are extremely common - like changing an SDL var when pressing a button, or opening a door in reaction to an SDL var being modified. This is where the xSomething.py scripts become useful.

For instance...
  • xAgeSDLBoolToggle will toggle a boolean SDL variable in response to an activator (button being clicked, region being entered, etc).
  • xAgeSDLBoolRespond will run a responder (=list of animations/sounds) when a boolean SDL variable is set to true or false.
  • xAgeSDLBoolShowHide will hide or show an object depending on whether a boolean variable is true or false.

Those scripts are nice, but fairly limited. For actual puzzles, you will almost certainly need your own Python script. You can write those directly within Blender's text editor (beware, Blender is queen on deleting too much of your text if you Ctrl-Z in the wrong area). To get Korman to export those, you will need the Blender text to be named as "YourScriptName.py", then click the "Export" checkbox. This script will automatically be packaged in a PAK file in your Uru "Python" folder on export. You can also reexport just the Python package without the whole Age by clicking the "Package Scripts" option in the drop-down next to the "Export Age" button in the World panel.

As for how Python scripts themselves work... This is yet another subject that takes a lot of time to explain, so I won't do that yet :lol: For now you should probably get familiar with the xSomething.py scripts to create a simple door. Don't hesitate to ask if you have questions, this can be a confusing subject and hard for me to explain in a concise manner... ;)
User avatar
Sirius
 
Posts: 1372
Joined: Mon Jul 26, 2010 4:46 am
Location: France

Re: Time to wire - but where to start?

Postby Aloys » Sun Apr 26, 2020 7:04 pm

This kind of discussion always make me wonder how the heck Cyan did all of Uru like that back in the day??

And I mean that in a sincere way. In this day and age (pun intended) of evolved tools, and visual scripting, and nodes, and what have you, how did they developed all of Uru's puzzles with Python? (or any other form of non game designer friendly tools). One key thing to any fluid game development is the ability to iterate. Design, implement, test, repeat. It's hard enough to do that on other games. Say action games. But doing that on a puzzle game. Where every puzzle is basically a whole different gameplay, and where a puzzle that tests poorly might mean that you have to redesign the whole thing, and throw away all of your code.. That's just horrible. Now, they had money and time and full time programmers doing just that but still..This is *so* constraining and time consuming...

For all the talk about the tech I'd love to know how they designed, and more importantly: how they *tested* their gameplay. Because the way I see it; you just want to design your thing on paper, 'test' it there, and implement it just *once*. And get it right the first time around. :lol:

:arrow: The problem we (the GoW) have here is that most of us are designing their stuff alone, 'testing' it alone (which is the worst way to do it). And part of why we do that is because we want our puzzles to be surprises, we don't want to spoil them, and so it's hard to just talk about them and ask for opinions... But we should. How do we do that?

Forget it, this is getting off topic. Sorry Ametist. :) I'll start another thread.
User avatar
Aloys
 
Posts: 1946
Joined: Sun Oct 21, 2007 7:57 pm
Location: France (GMT +1)

Re: Time to wire - but where to start?

Postby Sirius » Mon Apr 27, 2020 5:03 am

Aloys wrote:This kind of discussion always make me wonder how the heck Cyan did all of Uru like that back in the day??

Heh. Why do you think it took 6 months to make Kadish Tolesa ? (okay, the modelling must have taken lots of time, but still...)
I like to consider this period the early Middle Ages when it comes to game engines... They just somehow dealt with it because there wasn't anything better at the time :)

Despite all the flaws of the engine, Cyan did something good when designing Ages: the way they setup PRPs is very consistent.
Plasma has many features that allow you to completely bypass SDLs by using "persistent" animations, or forcing some objects to trigger over the network instead of only locally. But that's like fully rotating a steering wheel on the highway - just because you can do it, doesn't mean you should... AFAIK they always avoided that, and kept to the way I mentioned with SDLs. No matter which PRP you open, you always find the same setup. This doesn't mean the game will be bug-free, but at least bugs will usually be located within Python scripts. Hence the use of xSomething.py scripts, since they are used everywhere and thus easier to maintain (and yet Cyan rarely used those themselves...).

Oh, and while I'm at it, here is a simplified explanation of how PRPs, SDLs and Python scripts usually interact, to complete my previous post.
Code: Select all
[The local avatar triggers an activator on the local client]
activator NOTIFIES→ python script CHANGES→ sdl
[The SDL change is synchronised over the network, everyone receives it]
sdl change NOTIFIES→ python script RUNS→ responder
[Each client runs the responder locally]

With "activator": clickable button or detector region, and "responder": a list of animations and sound effects to play.

Hmmm.... Looking at this, I wonder if that doesn't imply there is something that could go really wrong when using Python scripts in Korman. I'll cover this in the next post, as those are really boring details.


Aloys wrote:In this day and age (pun intended) of evolved tools, and visual scripting, and nodes, and what have you

To be honest, even our modern tools have major flaws that we are probably blind to. In the case of Unity for instance...
small rant Show Spoiler


Aloys wrote:how did they developed all of Uru's puzzles with Python? (or any other form of non game designer friendly tools). One key thing to any fluid game development is the ability to iterate. Design, implement, test, repeat.

Oh boy, that must have been an utter pain... Game engines with physics engines are already impossible to test because they are non-deterministic. But throw into that the added complexity of Plasma, the multiplayer component, the fact that they probably tested the game without a Python debugger to step through the program ? Oh boy...
And yet I did this too on multiple occasions, like rewriting the Gahreesen Wall's logic on Deep Island. That... was not a piece of cake. And that's just a small part of all the multiplayer bugs the Offline-KI fixes.
User avatar
Sirius
 
Posts: 1372
Joined: Mon Jul 26, 2010 4:46 am
Location: France

Re: Time to wire - but where to start?

Postby Sirius » Mon Apr 27, 2020 5:59 am

Concerning the way PRPs, Python and SDL work... Hoikas or Deledrius, if you're reading this, could you please confirm the following ?

Most objects sending plMessages only send them locally (kLocalPropagate). This is fine for camera regions and responders.
Logic Modifiers always send the message on the network as well (kLocalPropagate | kNetPropagate). This can be dangerous, but usually it's fine for small "fire and forget" responders and objects like Sitting Modifiers and such. But does it mean that every client will send a plNotifyMsg whenever *any* avatar (not just the local one) enters a region, for instance ? I think this would just cause extra network traffic without real issues, but I'm not certain.

It sounds like it could be a problem with Python scripts though... Let's see.
When notified, xAgeSDLBoolToggle ensures that PtFindAvatar(events) == PtGetLocalAvatar(), but it DOESN'T check for PtWasLocallyNotified(self.key). So that means it might be triggered if another client detected our own avatar entering a region and broadcasted this message to us, right ?
xAgeSDLBoolSet does the inverse. It ensures PtWasLocallyNotified(self.key), but does NOT check if it was our own avatar. Once again, this means another avatar entering a region would cause us to change the value of an SDL variable, when it's not our client's job...
So if I'm right (I'm having a hard time wrapping my head around this), this means xAgeSDLBoolSet could cause extra network traffic, and xAgeSDLBoolToggle might even cause a race condition with multiple clients trying to toggle an SDL var at the same time. I wonder if it could cause responders to trigger multiple times simultaneously too...
Ugh. I need a break, this is giving me a headache... :(
User avatar
Sirius
 
Posts: 1372
Joined: Mon Jul 26, 2010 4:46 am
Location: France

Re: Time to wire - but where to start?

Postby ametist » Mon Apr 27, 2020 7:17 am

Thank you Sirius for your explanation and your time to write it! Now you got me on the right track - I think :) . So to check if I really am:

This is for testing now - see attached images - I haven't actually written the SDL yet ;)

I want the 'clickable1' to be shown from start so I would set a boolean variable like this " VAR BOOL clickable1[1] DEFAULT=0" in the SDL file, and to hide when I click it. I would attach the nodetree to the clickable.

The clickable2(in the img) would be hidden from start and enabled, or shown, when 'clickable1' is clicked. So for that I would write "VAR BOOL clickable2[1] DEFAULT=1 I guess?


Aloys wrote:Forget it, this is getting off topic. Sorry Ametist. :) I'll start another thread.
. Dont'worry Aloys, I enjoy reading yours, and Sirius', thoughts about 'all things URU' :)
Attachments
TestPython.jpg
TestPython.jpg (76.17 KiB) Viewed 1134 times
Buttons_LI.jpg
Buttons_LI.jpg (174.85 KiB) Viewed 1134 times
User avatar
ametist
 
Posts: 354
Joined: Fri Dec 28, 2007 6:55 am

Re: Time to wire - but where to start?

Postby Tsar Hoikas » Mon Apr 27, 2020 9:29 am

Sirius wrote:Creating the SDL file is fairly simple - you can do it in PlasmaShop, and you just save it in Uru's "SDL" folder

Don't do this. Korman will export the text note "<agename>.sdl" for you. This means that Korman will overwrite any manual SDL file you try to make.

Sirius wrote:Concerning the way PRPs, Python and SDL work... Hoikas or Deledrius, if you're reading this, could you please confirm the following ?

plLogicModifier requests an exclusive lock from the server via plNetMsgTestAndSet before triggering. The delay between acquiring this lock and the trigger is the cause of many "fall through the floor" subworld bugs. This can be avoided using plVolumeSensorConditionalObjectNoArbitration in MOUL, but then you run into that fun little race condition cascade mayhem you mentioned.

ametist wrote:I want the 'clickable1' to be shown from start so I would set a boolean variable like this " VAR BOOL clickable1[1] DEFAULT=0" in the SDL file, and to hide when I click it

DEFAULT needs to be 1.

I would attach the nodetree to the clickable

Yes - the xAgeSDLBoolShowHide.py script affects the object that the node tree is attached to.

Be conscientious re the x[...] scripts - there were some arguments added by Cyan in MOUL that are not present in PotS. You may have to compare the PotS and MOUL scripts carefully if you intend to export to the legacy PotS engine.
Image
Tsar Hoikas
Councilor of Technical Direction
 
Posts: 2139
Joined: Fri Nov 16, 2007 9:45 pm
Location: South Georgia

Re: Time to wire - but where to start?

Postby ametist » Mon Apr 27, 2020 10:26 am

Tsar Hoikas wrote:
Sirius wrote:Creating the SDL file is fairly simple - you can do it in PlasmaShop, and you just save it in Uru's "SDL" folder

Don't do this. Korman will export the text note "<agename>.sdl" for you. This means that Korman will overwrite any manual SDL file you try to make.

Got it, I will then write it with blender text editor and export it from there.


Tsar Hoikas wrote:
ametist wrote:I want the 'clickable1' to be shown from start so I would set a boolean variable like this " VAR BOOL clickable1[1] DEFAULT=0" in the SDL file, and to hide when I click it

DEFAULT needs to be 1.

Thanks! I am sure I will mix up all these bool variables a lot at the start of this my new journey :)

Tsar Hoikas wrote:
I would attach the nodetree to the clickable

Yes - the xAgeSDLBoolShowHide.py script affects the object that the node tree is attached to.

Be conscientious re the x[...] scripts - there were some arguments added by Cyan in MOUL that are not present in PotS. You may have to compare the PotS and MOUL scripts carefully if you intend to export to the legacy PotS engine.

Ok, so what you are saying is that if I export to URUoffline, which is URU:CC in my case, and I see any differences in the .py files in MOUL(which I have downloaded from this wiki) and URUoffline, I should use the x...py of the latter?
User avatar
ametist
 
Posts: 354
Joined: Fri Dec 28, 2007 6:55 am

Re: Time to wire - but where to start?

Postby Chacal » Tue Apr 28, 2020 10:50 am

Sirius wrote:Plasma has many features that allow you to completely bypass SDLs by using "persistent" animations, or forcing some objects to trigger over the network instead of only locally. But that's like fully rotating a steering wheel on the highway - just because you can do it, doesn't mean you should... AFAIK they always avoided that, and kept to the way I mentioned with SDLs.



Also, using SDL allows the shard admin to set states manually, triggering changes for story purposes.
Such as removing barriers and blockers for allowing access to areas in the City in Prologue.
Chacal


"The weak can never forgive. Forgiveness is an attribute of the strong."
-- Mahatma Gandhi
User avatar
Chacal
 
Posts: 2483
Joined: Tue Nov 06, 2007 2:45 pm
Location: Quebec, Canada

Next

Return to Scripting

Who is online

Users browsing this forum: No registered users and 2 guests

cron