FlyBy263 Posted August 21, 2017 Share Posted August 21, 2017 I'm somewhat new to papyrus scripting but have managed to write fairly large script mod so far. My coding experience is mostly in java so i know object based code. My question is if papyrus supports custom object types and if you can make an array out of them. For instant make a script named TagObject that acts as an object scriptname TagObject String Property name = "" Auto Float Property base = 0.0 Auto Float Property gen = 0.0 Auto Float Property walk = 0.0 Auto Float Property run = 0.0 Auto So i can have many instances of TagObject all with different valuesThen make an array to hold the object such as below TagObject tag = new TagObject[10] Link to comment Share on other sites More sharing options...
Lisselli Posted August 21, 2017 Share Posted August 21, 2017 (edited) No, arrays in papryus don't support that. Arrays can accept all the types in papyrus(ObjectReference, Form, Int, Float, String, Bool, MiscObject, Message, etc). No custom types. You can't mix and match types in an array either, the types must match. If you want a Float array you must create the property in array format, like so: Float[] property myArray auto ; or even a variable and fill it locally Float[] myArray As a property it will have a special UI in the property manager on the script in the CK for you to add elements. However once it's set, you can't change the elements at run time that way. So it's best to leave it empty and fill it at run time. It may sound restricting, but arrays are fast an efficient, and you can just all kinds of crazy s*** with arrays. However the best practices you may have learned about them in Java, still applies. Infinite loops and all that can still happen. Edited August 21, 2017 by Lisselli Link to comment Share on other sites More sharing options...
FlyBy263 Posted August 21, 2017 Author Share Posted August 21, 2017 Ah i see, so there is no universal object type either? Can i cast my script as a Form (from what i read it seems to be the closest thing to an object) put it in a Form array and then revert it back to my script to use? Link to comment Share on other sites More sharing options...
Lisselli Posted August 21, 2017 Share Posted August 21, 2017 (edited) It looks like Form could be universal, but I'm not entirely sure. Casting might be needed. Lots of events have form parameters but accept certain types passed into them. GetItemCount() being an example, or even PlaceAtMe() Forms are the objects defined in the Creation Kit. Otherwise known as the base object. An ObjectReference is a Form that has been(and if it can be) placed in the world. Type casting is something I still don't have a firm grasp of yet, so I don't want to steer you in the wrong direction. Some examples of casting I know for sure:Integers can be cast to a float and vice versa.ObjectReference can be cast to an actor if the ObjectReference is an actor. I'm not sure about casting to or from Form. Script casting works in a different way. You can declare an object's script as a property and access its script properties and function in another script. I'll use a quest as an example, since I've worked with these: Quest A has a scriptname ScriptAQuestScript extends Quest and I want to call it/s properties and functions in Quest B.. ; Quest B Quest property QuestA auto ScriptAQuestScript property ScriptA auto Event SomeEvent() ; let/s say you just want to directly use Quest A/s script without casting. ScriptA.ScriptAproperty ; but what you don/t? You just need to know Quest A/s script name instead and do this: (QuestA as ScriptAQuestScript).ScriptAProperty EndEvent Edited August 21, 2017 by Lisselli Link to comment Share on other sites More sharing options...
foamyesque Posted August 21, 2017 Share Posted August 21, 2017 Papyrus uses a hierarchial system for script object casting. The default + SKSE tree is documented here: https://www.creationkit.com/index.php?title=Category:Script_Objects (It's also a very handy page to refer to when you want to dig up what events or functions a particular script object has available) Anything can be successfully cast to any of it's parent script objects. So, for example, an Actor script object has access to all the functions and events of an ObjectReference or Form, and can be cast to either, but an ObjectReference doesn't have access to Actor scripting and cannot be cast to it, though it can still be cast to a form. Casting from a parent to a child script object can only be done if the thing in question is actually that child object. This is also the only thing that needs to be explicitly cast; Papyrus will automatically cast going up the tree. When you declare a script as extending some other script, you're positioning it in that hierarchy. So if you say your script extends Actor, you'll have access to all the Actor functions, etc. However, obvously, any default functions in Skyrim will only ever return Actor. If they're actually operating on your new script object, you could then cast the Actor to whatever your script is named, and proceed to access any new properties, functions, or events you've added. If you attempt to do so on something that doesn't have your new script on it, the cast will fail and a none value will be returned. This is often used to test for object types in various scripts (e.g. making sure something is a weapon -- you try casting the base form to a weapon, and if you get a none back, it's something else). You can create arrays of anything except other arrays, including custom script objects you have created. Link to comment Share on other sites More sharing options...
Reneer Posted August 21, 2017 Share Posted August 21, 2017 No, arrays in papryus don't support that.Papyrus doesn't support it "directly", no. But it can be done. Example Quest script (compiled and working): Scriptname RenTestTagQuestScript extends Quest Activator Property RenTagAct Auto RenTestTagScript[] Property RenTags Auto int itr = 0 Event OnInit() itr = 0 RenTags = new RenTestTagScript[100] while (itr < RenTags.length) RenTags[itr] = Game.GetPlayer().PlaceAtMe(RenTagAct, 1) As RenTestTagScript itr += 1 endWhile itr = 0 while (itr < RenTags.length) debug.messagebox("RenTags[" + itr + "].TestFloat = " + RenTags[itr].TestFloat) itr += 1 endWhile endEvent Example "Tag" script: Scriptname RenTestTagScript extends ObjectReference Float Property TestFloat Auto String Property TestString Auto Event OnInit() TestFloat = Utility.RandomFloat(0, 500) endEvent Link to comment Share on other sites More sharing options...
Lisselli Posted August 21, 2017 Share Posted August 21, 2017 Thanks for that, I did not know that. Link to comment Share on other sites More sharing options...
cdcooley Posted August 22, 2017 Share Posted August 22, 2017 In general you shouldn't be thinking in terms of arbitrary data like that. Papyrus is an event-driven, object-oriented language but scripts don't have an existence apart from being connected to game objects (except in the case of global scripts which can't have properties). As Reneer's script shows you can cheat by using some form (like an Activator) as a script holder but script instances are always linked to instances of objects (derived from Form) in the game world or things like quests which have a single global instance. (And for this purpose I'm ignoring the TIF scripts which have an extremely brief lifetime.) If you're coming from a traditional, general-purpose language like Java here is how you translate your concepts into Papyrus. The script file itself is the equivalent of a class definition. Instance methods are the Papyrus functions and events. They are always public. Instance variables are the Papyrus properties and variables. Variables are private instance variables and only provide storage. Properties appear to be public instance variables but despite appearances are really a matched pair of set and get functions that manipulate a hidden variable. The properties are modeled on Visual Basic practice. There are no class variables. The concept simply doesn't exist. If you think you need one you can use one of the singleton objects like quests to fake it though. You can make a class method by tagging a Papyrus function with the Global flag. The Math, Game, and Debug scripts consist entirely of global functions and are really just used to create a namespace for those global functions. All class instances are linked to an instance of some object in the game. For most scripts derived from Form which represent actual things the scripts will be attached to some ObjectReference. Other scripts are attached to special objects like Quests, Aliases, Perks, Scenes, etc. that have a single instance in the game with a global scope and lifetime. Other scripts like TIF (topic info fragments) and those attached to active magic effects tend to have very brief lifetimes and aren't really accessible from the outside in any useful way. Link to comment Share on other sites More sharing options...
foamyesque Posted August 22, 2017 Share Posted August 22, 2017 I've done some shenanigans with active magic effects -- particularly long-duration ones, such as enchantments -- via registering them with an external script, such a quest, that can be stuffed into properties and used to communicate data back and forth. The magic effects, on start, would call a registration function that would add them to an array and then return that array back to the calling magic effect. Because arrays are passed as pointers any other changes made to that array by other magic effects would be immediately visible to all of them, without need to explicitly pass the data back. On finish, same thing in reverse. Using arrays to pass data like that is really fast and I use similar solutions pretty liberally when I need to do performance sensitive stuff. Link to comment Share on other sites More sharing options...
cdcooley Posted August 22, 2017 Share Posted August 22, 2017 Shared arrays are fast because the are implemented as shared memory with absolutely no locking mechanism. By contrast every object in the game (including GlobalVariable objects) are designed to be thread-safe with a robust locking scheme. Link to comment Share on other sites More sharing options...
Recommended Posts