Creating new objects of new types at runtime?

Post » Sat Nov 17, 2012 7:02 am

So, perhaps I'm critically misunderstanding the concept here, but I'm trying to create a new type (I guess the closer anology would be "class") called SpecialType. I have a script that looks like the following:

Scriptname SpecialTypeint istring sfunction SetInt(int myInt)i = myIntendFunctionfunction SetString(string myString)s = myStringendFunctionint function GetInt()return iendFunctionstring function GetString()return sendFunction

...that defines the "member methods" of SpecialType.

I then have this script attached to a quest:

scriptname _TEST_TypeTest extends Questimport debugSpecialType appleSpecialType bananaEvent OnInit()RegisterForSingleUpdate(3)endEventEvent OnUpdate()apple.SetInt(5)banana.SetString("bob");Display the values storednotification("apple = " + apple.GetInt())notification("banana = " + banana.GetString())RegisterForSingleUpdate(3)endEvent

In-game, I receive this feedback via notification:

apple = 0
banana =

Papyrus logs report the following:
[07/17/2012 - 07:55:47PM] error: Cannot call SetInt() on a None object, aborting function callstack:[_TestQuest (02000D62)]._TEST_TypeTest.OnUpdate() - "_TEST_TypeTest.psc" Line 13[07/17/2012 - 07:55:47PM] error: Cannot call SetString() on a None object, aborting function callstack:[_TestQuest (02000D62)]._TEST_TypeTest.OnUpdate() - "_TEST_TypeTest.psc" Line 14[07/17/2012 - 07:55:47PM] error: Cannot call GetInt() on a None object, aborting function callstack:[_TestQuest (02000D62)]._TEST_TypeTest.OnUpdate() - "_TEST_TypeTest.psc" Line 17[07/17/2012 - 07:55:47PM] warning: Assigning None to a non-object variable named "::temp1"stack:[_TestQuest (02000D62)]._TEST_TypeTest.OnUpdate() - "_TEST_TypeTest.psc" Line 17[07/17/2012 - 07:55:47PM] error: Cannot call GetString() on a None object, aborting function callstack:[_TestQuest (02000D62)]._TEST_TypeTest.OnUpdate() - "_TEST_TypeTest.psc" Line 18

What I'm essentially trying to do is instantiate a new object with their own member variables. Apple's GetInt() call should return a different result than Banana's GetInt(), and so on.

Is there a way of implementing this in Papyrus?
User avatar
Kelly Tomlinson
 
Posts: 3503
Joined: Sat Jul 08, 2006 11:57 pm

Post » Sat Nov 17, 2012 1:16 am

this is only my guess, but since SpecialType does not extend anything, SpecialType Apple is basically just an empty object (hence the 'None' errors)

i'm not even sure how you would be able to get papyrus to recognize SpecialType as a new Data Type without coding something into the native source code.

have you tried to see if the script will compile if Apple is set as a SpecialType property? and if so, what happens in the property window?
User avatar
lisa nuttall
 
Posts: 3277
Joined: Tue Jun 20, 2006 1:33 pm

Post » Sat Nov 17, 2012 11:57 am

I changed the top of the Quest script to read:

scriptname _TEST_TypeTest extends QuestSpecialType property myType autoimport debugmyType applemyType banana

And got this error at compile-time.

Starting 1 compile threads for 1 files...Compiling "_TEST_TypeTest"...C:\SteamGamesSSD\skyrim\Data\Scripts\Source\_TEST_TypeTest.psc(7,7): unknown type mytypeC:\SteamGamesSSD\skyrim\Data\Scripts\Source\_TEST_TypeTest.psc(8,7): unknown type mytypeC:\SteamGamesSSD\skyrim\Data\Scripts\Source\_TEST_TypeTest.psc(15,7): mytype is not a known user-defined typeC:\SteamGamesSSD\skyrim\Data\Scripts\Source\_TEST_TypeTest.psc(16,8): mytype is not a known user-defined typeC:\SteamGamesSSD\skyrim\Data\Scripts\Source\_TEST_TypeTest.psc(19,33): mytype is not a known user-defined typeC:\SteamGamesSSD\skyrim\Data\Scripts\Source\_TEST_TypeTest.psc(20,35): mytype is not a known user-defined typeNo output generated for _TEST_TypeTest.psc, compilation failed.Batch compile of 1 files finished. 0 succeeded, 1 failed.Failed on _TEST_TypeTest.psc

It compiles just fine however the other way.
User avatar
Jason Rice
 
Posts: 3445
Joined: Thu Aug 16, 2007 3:42 pm

Post » Sat Nov 17, 2012 4:26 am

yeah, unfortunately that is what i figured.

i think in order to create a new data type, it might need to be defined in the native source code or else the compiler will not recognize it, or simply assign it a none value (since there is no definition for it).
User avatar
His Bella
 
Posts: 3428
Joined: Wed Apr 25, 2007 5:57 am

Post » Sat Nov 17, 2012 1:33 pm

out of curiosity, what kind of data type did you intend to create with SpecialType?

the reason i ask, is because maybe it would be possible to define it in SpecialType's script if it extended something already existing

like for example, going back to the flying camera thing, if you were to create a Steadicam type, it should probably extend Actor. then you can define a bunch of new functions for it that piggyback off the existing actor functions


then using a different script, you should be able to define a Steadicam property by using an actor cast as a steadicam, and it will be able to call the functions of Steadicam type (in theory, i havent actually tried this but now im curious as hell)
User avatar
adame
 
Posts: 3454
Joined: Wed Aug 29, 2007 2:57 am

Post » Sat Nov 17, 2012 4:32 pm

I was trying to find a more elegant way to fudge creating a multidimensional array using user-defined types.

For instance, consider:

SpecialType[] myMultiArray = new SpecialType[8]

myMultiArray[0].SetInt(5)
myMultiArray[0].SetString("Bob")

To store more than one datum in a given array index.

Edit: Yea, that's how I would approach a Steadicam function library. :nod:
User avatar
Dina Boudreau
 
Posts: 3410
Joined: Thu Jan 04, 2007 10:59 pm

Post » Sat Nov 17, 2012 2:26 pm

(Coming from someone who has basically no experience with Papyrus, so take it with a grain of salt)

In your first example, you declare instances of type SpecialType, but never initialize them. So they are none. Just like an uninitialized array for example.
An array you'd initialize with new[C] in OnInit, but AFAIK there's no generic new operator.
Spontaneous (and probably terrible) idea: Bind your script to some dummy object and place instances of that object in some dummy cell, which should instantiate it.

SpecialType property myType auto
myType apple

tries to use a variable name as a type, so that's a syntax error.
User avatar
Spaceman
 
Posts: 3429
Joined: Wed May 23, 2007 10:09 am

Post » Sat Nov 17, 2012 3:39 pm

An array you'd initialize with new[C] in OnInit, but AFAIK there's no generic new operator.
Spontaneous (and probably terrible) idea: Bind your script to some dummy object and place instances of that object in some dummy cell, which should instantiate them.


I think that's how the guy that implemented linked lists did it :smile: But yea, I would classify that as "inelegant".

SpecialType property myType auto
myType apple

tries to use a variable name as a type, so that's a syntax error.

Thanks, that makes more sense.
User avatar
Maya Maya
 
Posts: 3511
Joined: Wed Jul 05, 2006 7:35 pm

Post » Sat Nov 17, 2012 10:58 am

I'm not exactly well-versed in Papyrus, but from looking at the OP, it seemed like the age old function scope problem, of any programming language. I'm pretty sure that your setters are only modifying "i" or "s" local to the function, and this value is essentially lost because it is not modifying the same i or s, in essence. You could trace this if you wanted, print the value of i and s before you set, during the set, and after the set. I'm sure in the scope local to the setter functions the value will be correct, but it doesn't do you much good.

So I looked into the issue, and I think this is the solution:

Scriptname TestScript1int Property i    function Set(int myInt)        i = myInt    endFunction    int function Get()        return i    endFunctionEndPropertystring Property s    function Set(string myString)        s = myString    endFunction    string function Get()        return s    endFunctionEndProperty

This gives you a public setter and a public getter so in the case of your test code it should just be modified like so:
scriptname _TEST_TypeTest extends Questimport debugSpecialType appleSpecialType bananaEvent OnInit()RegisterForSingleUpdate(3)endEventEvent OnUpdate()apple.Set(5)banana.Set("bob");Display the values storednotification("apple = " + apple.Get())notification("banana = " + banana.Get())RegisterForSingleUpdate(3)endEvent

I have no idea if this works. I may test it soon, but the wiki seems to support my hunch that this will work just based on the http://www.creationkit.com/Property_Reference page. You can see it says that all variables are private (hence why you can't publicly set them), so I believe turning them into properties may be the only way.

Edit: Formatting
User avatar
Harry Leon
 
Posts: 3381
Joined: Tue Jun 12, 2007 3:53 am

Post » Sat Nov 17, 2012 9:10 am

Variables can only be initialized to a specific Type. These Types are hardcoded, and you cannot initialize a variable to a Property's identifier. Identifier != Type. You do not create a new Type when creating a Property.

Your SpecialType script is not doing anything whatsoever. There are three ways to activate a script in-game: attach it to an object, extend it with another script that gets attached to an object, or reference that script as a Property of another script after attaching the former script to an object. If you don't do any of those, your script is worthless, as it will never be accessed. Bethesda gets a fourth way: bind the script to a Type in the engine. Creating new Types requires engine modification or extension, though, so unless you want your mod to become SKSE dependent, you aren't going to be doing this any time soon.

The Base scripts have special code in the game engine because their functions are native and they are bound to the Types. This logic line does not hold over to creating your own Types, though. If the Type is not in the engine, it does not exist and nothing you can do will make it exist.
User avatar
meg knight
 
Posts: 3463
Joined: Wed Nov 29, 2006 4:20 am

Post » Sat Nov 17, 2012 6:13 am

If the Type is not in the engine, it does not exist and nothing you can do will make it exist.
Sorry, but that's not true. From the Properties CK wiki page:
;I have a result script (OWNED by MQ01) with this in it: MQ01Script myQuest                        ;declares a variable "myQuest" which is a TYPE of MQ01Script myQuest = GetOwningQuest() as MQ01Script  ;sets the myQuest variable to it's owning quest as the type MQ01Script float myDeadCount                         ;declaring the variable "myDeadCount"  myDeadCount = myQuest.deadCount           ;setting local variable to be the quest's property value ;you can also set the quest property thusly: myQuest.deadCount = 10
Here, myQuest is initialized as type MQ01Script. (which is a script that extends another base Type, Quest, but still) Casting and initializing variables to user-defined types is very possible in Papyrus. But for the reasons Schlangster mentioned, these objects are never really being instantiated. I'd have to bind the script to a created object, which gets very messy very fast. Thanks for the help all.
User avatar
Andrew Perry
 
Posts: 3505
Joined: Sat Jul 07, 2007 5:40 am

Post » Sat Nov 17, 2012 6:23 am

Sorry, but that's not true. From the Properties CK wiki page:
;I have a result script (OWNED by MQ01) with this in it:MQ01Script myQuest						;declares a variable "myQuest" which is a TYPE of MQ01ScriptmyQuest = GetOwningQuest() as MQ01Script  ;sets the myQuest variable to it's owning quest as the type MQ01Scriptfloat myDeadCount						 ;declaring the variable "myDeadCount"myDeadCount = myQuest.deadCount		   ;setting local variable to be the quest's property value;you can also set the quest property thusly:myQuest.deadCount = 10
Here, myQuest is initialized as type MQ01Script. (which is a script that extends another base Type, Quest, but still) Casting and initializing variables to user-defined types is very possible in Papyrus. But for the reasons Schlangster mentioned, these objects are never really being instantiated. I'd have to bind the script to a created object, which gets very messy very fast. Thanks for the help all.

No, it is very true. MQ01Script is accepted because it is a Script Type where the script in question is attached to a game object. Note that it is still a pre-defined hardcoded Type. What you are trying to do is create a brand new non-Script Type, which is impossible without engine access.
User avatar
steve brewin
 
Posts: 3411
Joined: Thu Jun 21, 2007 7:17 am

Post » Sat Nov 17, 2012 1:53 pm

No, it is very true. MQ01Script is accepted because it is a Script Type where the script in question is attached to a game object. Note that it is still a pre-defined hardcoded Type. What you are trying to do is create a brand new non-Script Type, which is impossible without engine access.

I see. Ah well. I'll just have to cheese what I'm trying to do another way :tongue:
User avatar
Paula Rose
 
Posts: 3305
Joined: Fri Feb 16, 2007 8:12 am

Post » Sat Nov 17, 2012 7:20 am

I'm doing this in one of my projects, and there's a dead easy way to do it.
  • Duplicate Gold001 (or any other form based object)
  • add a script extending it
  • add whatever properties you like to the script
  • create a warehouse cell with a floor and an x-marker
  • Each time you a new data record, use place at me to put a new instance of your hacked gold record at the x marker. Placeatme returns the obect reference which can be cast to the script
  • add the ref to whatever structure you need. You can ignore the pseudo-gold coins in the test cell. Just make sure the player can't pick them up :)

Works just fine for me :)
User avatar
Sammie LM
 
Posts: 3424
Joined: Thu Nov 30, 2006 1:59 pm


Return to V - Skyrim