Jump to content

[Creation kit] PlaceAtMe() fails for custom furniture


Recommended Posts

I've made a custom furniture object (duplicate of a default chair with a different name). However, every time I try to spawn this custom chair in-game via PlaceAtMe(), nothing happens.

 

I.e:

 

ObjectReference customSpawnedCHair = Game.GetPlayer().PlaceAtMe(Game.GetForm(0x0803e617),1)

 

Above code does nothing in-game. 0x0803e617 is a formID of the custom chair. What could be the reason?

 

Link to comment
34 minutes ago, Nexussux! said:

I've made a custom furniture object (duplicate of a default chair with a different name). However, every time I try to spawn this custom chair in-game via PlaceAtMe(), nothing happens.

 

I.e:

 

ObjectReference customSpawnedCHair = Game.GetPlayer().PlaceAtMe(Game.GetForm(0x0803e617),1)

 

Above code does nothing in-game. 0x0803e617 is a formID of the custom chair. What could be the reason?

 

 

 

Blind at the laptop with wordpad ;)

 

Set the chair as Property...

 

ObjectReference Property customChairRef Auto
ObjectReference spawnedCustomChair

 

Function spawnChair()
    Form myChair
    myChair = customChairRef.getBaseObject()
    
    If myChair != None
        spawnedCustomChair = Game.GetPlayer().PlaceAtMe(myChair,1)
    endIf
endfunction
 

Link to comment
3 hours ago, Andy14 said:

 

 

Blind at the laptop with wordpad ;)

 

Set the chair as Property...

 

ObjectReference Property customChairRef Auto
ObjectReference spawnedCustomChair

 

Function spawnChair()
    Form myChair
    myChair = customChairRef.getBaseObject()
    
    If myChair != None
        spawnedCustomChair = Game.GetPlayer().PlaceAtMe(myChair,1)
    endIf
endfunction
 

 

Thank you for the tip! I've actually found the getBaseObject() method on google before asking this forum. It was pretty much identical to what you gave.

 

Since  I am new, I assumed it was irrelevant to my simple case because having an ENTIRE WALL OF CODE just to spawn ONE DAMN CHAIR seemed sus. I guess this is what passes as good dev practices for Bethesda. ;D

 

Moreso spawning a horker didn't require setting it as a property or getting the object base. Just Game.GetPlayer().PlaceAtMe(<horker form ID>,1)

 

 

Edited by Nexussux!
Link to comment
1 hour ago, Nexussux! said:

Since  I am new, I assumed it was irrelevant to my simple case because having an ENTIRE WALL OF CODE just to spawn ONE DAMN CHAIR seemed sus. I guess this is what passes as good dev practices for Bethesda. ;D

 

xD

Skyrim has many questionable design decisions, but this is one of those that actually make sense.

 

Since it seems to me you know about programming, I think I can explain you what you are actually doing and why.

 

When creating an app in any normal object-oriented programming language (what Papyrus is kind of) you just create an instance of a class when you need a new object and you are done.

Here, you are actually filling an already existing class (to which you have very limited access to) with data loaded from some particular record in some database. The database is the esp file and the record is whatever furniture/actor/spell/etc you want to manipulate.

 

So, when spawning a chair you're actually telling the engine you want to create a new object and load its data from a record in a database.

 

The most hassle-free way for Skyrim to know which record you want to get data from is by using a script property that points to that record.

In the example @Andy14 posted, that was done in this line:

 

ObjectReference Property customChairRef Auto

 

But this is only the part that declares the variable that will hold that record reference.

To actually assign a value to that variable, you usually open the CK and set the record you want to use as a base for creating your new object.

 

Soooo... tl; dr:

Objects in Papyrus aren't classes, but records filled with data the engine uses to fill its internally instantiated objects (I hope I explained that well :S).

 

Those walls of code needed to spawn a miserable chair are the result of the trade-off of letting non-programmers fill a database to develop a full game as soon as possible, instead of hiring an army of programmers that will take more time to make the game, will ask for higher wages and will be even more error prone when filling by hand all the structures needed to create the game.

 

It's way easier to use databases, anyway. Everyone does that for a reason.

Edited by Papitas
Link to comment
30 minutes ago, Papitas said:

 

When creating an app in any normal object-oriented programming language (what Papyrus is kind of) you just create an instance of a class when you need a new object and you are done.

Here, you are actually filling an already existing class (to which you have very limited access to) with data loaded from some particular record in some database. The database is the esp file and the record is whatever furniture/actor/spell/etc you want to manipulate.

 

So, when spawning a chair you're actually telling the engine you want to create a new object and load its data from a record in a database.

 

Soooo... tl; dr:

Objects in Papyrus aren't classes, but records filled with data the engine uses to fill its internally instantiated objects (I hope I explained that well :S).

 

Those walls of code needed to spawn a miserable chair are the result of the trade-off of letting non-programmers fill a database to develop a full game as soon as possible, instead of hiring an army of programmers that will take more time to make the game, will ask for higher wages and will be even more error prone when filling by hand all the structures needed to create the game.

 

It's way easier to use databases, anyway. Everyone does that for a reason.

 

Well damn... Not sure if I agree with what Beth has done (CKit is an eldritch mess for a non-programmer anyway), but you've made it quite clear.

 

If I understand correctly now, any "custom" object that is based off a default objects (one we cant access much). Then every time a "custom" object is spawned, the game first "takes" the default object, then immediately modifies it according to the .esp database record (i.e. the mod). If that's the case then I see why the code wall is necessary.

 

And so the reason unmodded horker spawns without a code wall, is because it is an existing ("default, limited access") class already.

 

Is it me, or your explanation should be pinned on Creation Kit wiki? ;D

 

 

Edited by Nexussux!
Link to comment
50 minutes ago, Nexussux! said:

If I understand correctly now, any "custom" object that is based off a default objects (one we cant access much). Then every time a "custom" object is spawned, the game first "takes" the default object, then immediately modifies it according to the .esp database record (i.e. the mod)

No.

There is no such thing as a custom object. Your chair is just a regular object that happens to use the same Nif File.

 

52 minutes ago, Nexussux! said:

If that's the case then I see why the code wall is necessary

Its not.

Use "game.getFormFromFile()" rather than "game.getForm()", and it will work like a charm.

 

54 minutes ago, Nexussux! said:

And so the reason unmodded horker spawns without a code wall, is because it is an existing

The root cause of your problem is the modIndex in the ID. the fist two digits in an ID always represent the Load order slot of the containing esp. And because the CK only loads direct dependency's for the mod you are working on, rather than all the mods you have installed, The actual ingame ID will most likely differ, hence your chair wont spawn.

 

The Horker on he other Hand is defined in Skyrim.esm, which will always have the loadorder index of 00, so this problem wont appear here.

Link to comment
1 hour ago, Papitas said:

Those walls of code needed to spawn a miserable chair are the result of the trade-off of letting non-programmers fill a database to develop a full game as soon as possible, instead of hiring an army of programmers that will take more time to make the game, will ask for higher wages and will be even more error prone when filling by hand all the structures needed to create the game.

I have to disagree here. Im pretty sure the reason here is that you can re-use the same script file for different (but similar) use cases.

 

For example, if i wanted to place two of my Guilloutines, I can attach the same script to both and just fill in their associated parts (lever, blade) as properties.

Trying to fill those in in realtime afterwards would be kinda inefficient... (and annoying).

 

Link to comment
7 hours ago, Andy14 said:

ObjectReference Property customChairRef Auto
ObjectReference spawnedCustomChair

 

Function spawnChair()
    Form myChair
    myChair = customChairRef.getBaseObject()
    
    If myChair != None
        spawnedCustomChair = Game.GetPlayer().PlaceAtMe(myChair,1)
    endIf
endfunction

Wrong.

 

this can be shortened to something like this:

Furniture property myChair Auto
  
game.getPlayer().placeAtme(myChair)

 

Link to comment
1 hour ago, Pamatronic said:

No.

There is no such thing as a custom object. Your chair is just a regular object that happens to use the same Nif File.

 

Yeah, that's why I've put "custom" in quotes right there ?

image.png.e2beb8af54dbdc572f0259b9186d6e42.png

 

1 hour ago, Pamatronic said:

 

 

Its not.

Use "game.getFormFromFile()" rather than "game.getForm()", and it will work like a charm.

 

 Thanks, I'll try that and see if it works. Always could use shorter code.

Link to comment
1 hour ago, Pamatronic said:

Wrong.

 

this can be shortened to something like this:

Furniture property myChair Auto
  
game.getPlayer().placeAtme(myChair)

 

 

It is not wrong. It's just longer than code and yet not slower to execute.
What is slow (and wrong in that sense) is Game.GetPlayer ().
This should also be properly declared and not read again at runtime with each call.

Link to comment
14 hours ago, Pamatronic said:

I have to disagree here. Im pretty sure the reason here is that you can re-use the same script file for different (but similar) use cases.

 

For example, if i wanted to place two of my Guilloutines, I can attach the same script to both and just fill in their associated parts (lever, blade) as properties.

Trying to fill those in in realtime afterwards would be kinda inefficient... (and annoying).

 

 

There's no denying one of the best uses for properties is to do "parametric" reusable scripts.

One of the hallmarks of an amateur programmer is to repeat almost the same code over and over (altough, let us be honest: Papyrus is a toy language that doesn't lend itself too well for doing proper code factorization).

 

But if you study how the vanilla scripts are made, most of them communicate with the esp files by using properties, even if they want to access a non parametric value.

For example: keywords, spells, global variables... most of them are accessed by properties instead of Game.GetFormFromFile or something.

 

It's not uncommon to see things like:

 

GlobalVariable property GameHour Auto

 

What's better? Depends.

I'm not too fond on Game.GetFormFromFile because if the FormID changes for some reason (like compacting your esp for esl flagging), your code breaks and you have to search all the places that used the old FormId and update them with the new one.

A quite error prone endeavor.

 

On the other hand, properties get baked into saves and they can be a real pain in the ass to update once your mod is already deployed and used by others.

 

I also once thought GetFormFromFile was slower than assigning a property in the CK, but right now I'm not too sure that's a real issue.

In both cases you are telling the engine you want a record identified by an integer number that belongs to some file.

 

I suppose GetFormFromFile is still slower because the file name must be first interpreted as a string; while using properties should use the esp file order to find which database will be used.

But this is just an hypothesis of mine.

Link to comment
8 hours ago, Nexussux! said:

 Love your website and tutorial style btw

 

Thanks! I never cared for popularity, so you won't find me riding waves and repeating whatever everyone is saying so I can be "easily" found xD

 

I need to update it with my many findings about NiOverride, since it's not documented at all and learning about it was a real pain in the ass and I literally got many headaches when working with it. 

 

Hopefully I can save from hell many other people xD

Link to comment
On 9/18/2021 at 7:00 PM, Papitas said:

Hopefully I can save from hell many other people xD

I've delved into the C.K. and find it a miserable creature. It is really strange that Bethesda has created something that has great potential but at the same time their own programmers have issues getting it to work correctly. I would like to do more with Skyrim but I'm not sure I can handle the mental gymnastics. Kudos to you and everyone else for sharing hard gained information.

Edited by Ripstop
Link to comment
14 hours ago, Ripstop said:

I've delved into the C.K. and find it a miserable creature. It is really strange that Bethesda has created something that has great potential but at the same time their own programmers have issues getting it to work correctly. I would like to do more with Skyrim but I'm not sure I can handle the mental gymnastics. Kudos to you any everyone else for sharing hard gained information.

 

I wish more people shared their knowledge. 

 

I also have my egoistic reasons to share what I have learned. 

More knowledge floating around means more people will make more and better mods I can play with. 

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use