Hi there! You are currently browsing as a guest. Why not create an account? Then you get less ads, can thank creators, post feedback, keep a list of your favourites, and more!
Quick Reply
Search this Thread
Virtual gardener
staff: administrator
Original Poster
#1 Old 22nd Sep 2019 at 2:19 PM Last edited by Lyralei : 22nd Sep 2019 at 3:16 PM.
Default Tip/brains needed for instantiating objects on world loading
Yes! Another coding thread I am so sorry.

However, currently i'm working on a script where I'd add new thingies and features for snow, which includes the worst idea ever, but adding more meshes to (most or all) trees. Because SpeedTree's TOU simply does not allow ANY mesh-y tweaking done and reuploaded (Unless this is done inside of EA), I want to add the meshes through a script. Also because we somehow need to have a condition where we know that it's snowing and then adding the mesh.

Now the code currently isn't exactly done, it's in it's very testy and debugging state, so currently it will create meteors at every position of a tree and basically logging the position into notification in the worst way possible, but it does the job (So still need to finetune it ) And it's not winter-compatible yet (aka, that the mesh would show up and get destroyed if it isn't winter or is winter).

Code:
public static void OnWorldLoadFinished(object sender, EventArgs e)
        {
        	// Load in all the alarms after 5 min of the world being loaded. 
        	AlarmManager.Global.AddAlarm(5f, TimeUnit.Minutes, new AlarmTimerCallback(LoadNotificationAfter_5_SimMinutes), "LoadLyraleiSnowModloader", AlarmType.DeleteOnReset, null);
        	AlarmManager.Global.AddAlarm(0f, TimeUnit.Minutes, new AlarmTimerCallback(GetAllFrozenObjects), "LoadFrozenObjects", AlarmType.DeleteOnReset, null);
        }
        
       	public static void LoadNotificationAfter_5_SimMinutes()
        {
        	StyledNotification.Format format = new StyledNotification.Format("Snow Additions has loaded!", StyledNotification.NotificationStyle.kGameMessagePositive);
            StyledNotification.Show(format); 
        }
        
        public static void GetAllFrozenObjects()
        {
            // Here we get an array of all the Flora being loaded into the world (So trees and bushes) 
            Flora[] objects = Sims3.Gameplay.Queries.GetObjects<Flora>();
            if(objects.Length == 0)
            {  
            	Exception exception = new Exception();
				ShowException(exception);
           	} 
          	else
            {
	            foreach(Flora flora in  Sims3.Gameplay.Queries.GetObjects<Flora>())
	            {
	            	// Get the object id of the tree/bush
	            	ObjectGuid objectId 	= flora.ObjectId;
	            	
	            	// Store the tree/bush position/transform into a var
	            	mTransform                             = flora.Transform;
	            	mPosition                                 = flora.Position;
	            	mForwardVector                      = flora.ForwardVector;
	            	mDisplayPosition                     = flora.DisplayPosition;
	            	mPositionXZ                            = flora.PositionXZ;
	            	mPositionOnFloor                   = flora.PositionOnFloor;
	            	mBoundingBox                        = flora.Dimensions;
	            	
	            	// Convert them to strings for now to use in the debug log
	            	mTransformString                    = mTransform.ToString();
	            	mPositionString                       = mPosition.ToString();
	            	mForwardString                      = mForwardVector.ToString();
	            	mDisplayPositionString           = mDisplayPosition.ToString();
	            	mPositionXZString                  = mPositionXZ.ToString();
	            	mPositionOnFloorString          = mPositionOnFloor.ToString();
	            	mBoundingBoxString              = mBoundingBox.ToString();
	
            		StyledNotification.Format objectReactionLog = new StyledNotification.Format(LogDebugInfo(), StyledNotification.NotificationStyle.kSystemMessage);
                	StyledNotification.Show(objectReactionLog);
                	GameObject meteor = GlobalFunctions.CreateObject("MeteorHuge", mPosition, 0, mForwardVector) as GameObject;
            	} // end for loop
            } // end else
        } // end GetAllFrozenObjects
        
        public static string LogDebugInfo()
        {
        	StringBuilder stringBuilder = new StringBuilder();
			try
			{
				stringBuilder.AppendFormat(string.Format("\n Tree or bush position: {0}", mPositionString));
				stringBuilder.AppendFormat(string.Format("\n Tree or bush transform: {0}", mTransformString));
				stringBuilder.AppendFormat(string.Format("\n Tree or bush ForwardVector: {0}", mForwardString));
				stringBuilder.AppendFormat(string.Format("\n Tree or bush Display Position: {0}", mDisplayPositionString));
				stringBuilder.AppendFormat(string.Format("\n Tree or bush Position XZ: {0}", mPositionXZString));
				stringBuilder.AppendFormat(string.Format("\n Tree or bush Position on Floor: {0}", mPositionOnFloorString));
				stringBuilder.AppendFormat(string.Format("\n Tree or bush Bounding Box: {0}", mBoundingBoxString));
			}
			catch
			{
				stringBuilder.AppendFormat(string.Format("\n Exception was thrown in LogDebugInfo(). Couldn't load everything properly "));
			}
			return stringBuilder.ToString();
        }


Now, I noticed that OnWorldLoadFinished() Seems to have a few lasting minutes before it would stop, because, of course, it's an event! Those are supposed to stop at some point. However, the time given for that event isn't long enough for my code to execute.

All the other events I've found don't seem to meet the needs, and I'm not sure if at "OnWorldLoadStartedEventHandler()" or "OnStartupAppEventHandler()" Would do the trick since it has to be done at a point that all the trees are instantiated.

Thoughts?
Advertisement
Space Pony
#2 Old 22nd Sep 2019 at 4:11 PM
Hmm well events dont have a livetime theyre more like delegates
My gut feeling says maybe theres an object limit in place, im off to do some testing

E: OPTIMIZE !!!
Code:
            // Here we get an array of all the Flora being loaded into the world (So trees and bushes) 
            Flora[] objects = Sims3.Gameplay.Queries.GetObjects<Flora>();

you already have the flora there loop through it and use
Code:
 foreach(Flora flora in objects )
	            {
}

instead of
Code:
  foreach(Flora flora in  Sims3.Gameplay.Queries.GetObjects<Flora>())
	            {
}


I know this was not your problem, i couldnt help it but to point that out
Virtual gardener
staff: administrator
Original Poster
#3 Old 22nd Sep 2019 at 4:34 PM
LOL I actually noticed that after I posted this Thanks for poiting it out though!

I actually did some debugging on having it not load an object but a notification. The Notification would show 140 trees and bushes reacting on it, but it seems indeed only shows a few meshes (so not for all 140 trees). I'll also check if there's a limit
Virtual gardener
staff: administrator
Original Poster
#4 Old 22nd Sep 2019 at 5:38 PM
You might be right on the limits. I noticed that on every lot it adds 4 meteorites for only 1 type of each (So like if there's 5 sunflowers, 3 spruces, 4 high grass and 7 other trees it would place 4 meteorites on 1 of each kind, so you end up with 1 at a random sunflower, 1 at a random spruce and 1 at a random highgrass and 1 at a random tree).
Virtual gardener
staff: administrator
Original Poster
#5 Old 24th Sep 2019 at 10:20 AM
Battery and I discussed this a bit more on PM so, just wanted to say for anyone with this issue or looking for the cause, is batching. Basically what happens to this line:

Code:
 Flora flora in Sims3.Gameplay.Queries.GetObjects<Flora>() 


Filters out copies (Or returns only one of each tree/bush kind). Here's the code EA uses to batches the array (thanks to battery ):

Code:
 
public static T[] GetObjects<T>() where T : class
{
    Array objects = Queries.GetObjects(typeof(T));
    if (objects != null)
    {
        return objects as T[];
    }
    return new T[0];
}


So, looking at the "Return new T[0]" (And then imagine T being ea's Flora class I used). It will always return the very first entry. Which if you know arrays you probably might have figured that out already
This exact thing is also filtered by lot. So world trees/bushes won't even be affected by this array or even the "GetObjects()" function. Which kind of sucks! But I feel like if you ever check out this tutorial: http://www.simlogical.com/ContentUp..._script_mod.pdf

That you should be aware of the following things:
  • Two of the same items on a lot will only affect 1. In NonaMena's case, they are also applying it to an event listener so that by itself would trigger it on duplicates I believe. But sometimes the code logistics don't need you to have an "OnBought" listener. (Like my code)
  • There's not an easy way around this.
  • It's not the OnWorldLoadFinished()
Virtual gardener
staff: administrator
Original Poster
#6 Old 28th Sep 2019 at 1:14 PM
Hey @battery , Rereading the code, I actually realised something which is basically this line:

Code:
Array objects = Queries.GetObjects(typeof(T));


Basically, it's not returning T[0] (Aka the first entry) it's actually returning a Type. Which means, Of all types it can find, it creates an array, which means that the Typeof here is the issue.

Now I'm wondering if it's possible to return it as a Class specifically rather than a type. but I feel like that could be a workaround for this
Space Pony
#7 Old 28th Sep 2019 at 2:22 PM
Hey @Lyralei,
the GetObjects Method takes in a Type as a parameter and returns an array filled with instances of this type. Unfortunately i have no insight into the actual Function since its hidden away in the Sims3Common.dll
Our problem really seems to be the batching we have mentioned.
Code:
ISittable[] HeyLookLyraleiHeresTheSuffASimCanSitOn = Queries.GetObjects(typeof(ISittable),Sim.ActiveActor.LotHome.LotId);

Will actually return ALL Sittable Object instances and not one of each type like with our Trees. So these Objects are treated differently (e: and dont seem to be batched)... This is why your Candle Example you did link will work but our Tree stuff wont. I will try a few more things but at this point i have little hope that i can figure something out
Virtual gardener
staff: administrator
Original Poster
#8 Old 28th Sep 2019 at 3:27 PM
not sure if i'm just screwing it up, but I was just curious as to what your code outputs if you were to log it in a notification or whatever. To me, this:

Code:
Sittable[] HeyLookLyraleiHeresTheSuffASimCanSitOn = Queries.GetObjects(typeof(ISittable),Sim.ActiveActor.LotHome.LotId);


Is throwing numerous of compiling errors actually, mainly because it's not sure whether to use Sims3.gameplay.queries or sims3.SimIface queries. Also, if I do use the sims3.SimIface queries, this creates an infinite loading loop (Aka the world will never be loaded). If I do:

Code:
 Sittable[] HeyLookLyraleiHeresTheSuffASimCanSitOn = Sims3.Gameplay.Queries.GetObjects<iSittable>;


Then this funnily enough also returns exactly what the trees are doing, aka, returning Sims3.Gameplay.Interfaces.ISittable[] on all 3 chairs I placed on an empty world
Space Pony
#9 Old 28th Sep 2019 at 4:43 PM Last edited by Battery : 28th Sep 2019 at 4:59 PM.
Quote: Originally posted by Lyralei
Code:
 Sittable[] HeyLookLyraleiHeresTheSuffASimCanSitOn = Sims3.Gameplay.Queries.GetObjects<iSittable>;


Then this funnily enough also returns exactly what the trees are doing, aka, returning Sims3.Gameplay.Interfaces.ISittable[] on all 3 chairs I placed on an empty world


Yes it does that but it doesnt for the trees so if you would have a total of 3 of the same trees you would only get one object back


This is the out put i get for that bit of code (After the game finished loading and an alarm was triggered

Screenshots
Virtual gardener
staff: administrator
Original Poster
#10 Old 29th Sep 2019 at 4:07 PM
I could be totally not understanding the instances, or my limited C# knowledge here so please bear with me :p

When one would actually do something like:
Code:
Array treebirch = Sims3.SimIFace.Queries.GetObjects(TreeBirch.GetType());


It would output something like:
Code:
Sims3.Gameplay.Objects.Mimics.TreePear[] 


Could that maybe indicate that maybe it has all those trees inside that array? I couldn't seem to apply the same trick on the Doors or ISittable to see what they'd return but I get the feeling it would be the same. Just a thought really!

But I will be honest, I'm this close to leave it as is. I did however look at how EA finds all the "Fire Objects". Which is pretty much done with this:

Code:
		public override IExtinguishable[] GetObjects(Lot lot)
		{
			return lot.GetObjects<Fire>();
		}


But I feel like if this would be applied to trees instead it would possibly not do much.
Virtual gardener
staff: administrator
Original Poster
#11 Old 5th Oct 2019 at 2:16 PM
I was thinking, Upon some diving into code and such, I did notice there was a function called "CountSpeedTrees()" Coming straight from the engine dll (Sims3Common).

Now, thinking about the logic, would it be a good idea (Or even a stupid idea) to take the result of that count and see if that can be stored in a variable that can later be used for a foreach loop to apply a mesh?
Back to top