ZeroCore Posted September 8, 2016 Author Share Posted September 8, 2016 Multi-threading inherently introduces de-synchronization, not fixes it. To synchronize different objects would necessitate staying on one thread. In regards to animations and such, I would say that it would be more elegant, less cpu intensive, and more seamless. However, that would in fact require a lot of knowledge about animations/models and it's not as controllable through scripts (obviously scripts are easier to control with scripts :tongue:).I would teach you how to do that, if I knew how. While I have a fairly firm grasp of Nifskope and textures, and I know how to make models in blender and the basics of exporting them to skyrim, I don't really know much more than that. What I do know is programming, so I'll do my best to help you with what I'm most familiar with:If the walls are all premade (none being spawned in that need to be moved, which is fine but requires a bit more code) the easiest method of handling this is to have a script tied to a marker or off-screen object to act as a sort of "main control". Then, pass into it's script all the other wall objects (or an array depending on how many there are) as a property and move the marker with the walls as if it were one of them. Then, using it's translation events as the trigger for all of them, create a loop to tell each wall in rapid succession to move or reset. I'm making the assumption that when the marker or hidden object has it's 3D loaded, all of the walls will (which they should, if they're in the same cell). If not, that would require some workarounds because if one wall is loaded while another is not, that would cause a desync. Thus with the code below, if the control object does not have it's 3D loaded then the walls will not move. You can of course use one array, but I recommend two in order to keep them from getting mixed up. You'll also need an array of markers each acting as a start and end point to their respective walls; that is, if you continue to control them through placed markers and TranslateToRef. I highly recommend either placing the markers in very specific coordinates (setting their position manually in the editor so that they line up exactly with each other) or use a coordinate-based system and TranslateTo instead. This will help with the look and synchronization since while the code will still work, if the distances each wall moves are not identical or they and their markers aren't perfectly lined up on two axes, it might make them look strange. Further, using a coordinate system where the travel distances are identical can eliminate the need for using the many arrays that you see here, and instead replace them with one variable and a bit of math. I'll give you this code using markers, but let me know if you want help shifting to using coordinates instead. Attach this to your "control" object: Scriptname ____________ZIU3 extends ObjectReference ObjectReference Property XSTARTC Auto ; Properties for the start and end markers for ObjectReference Property XENDC Auto ; the control object this script is attached to ObjectReference[] Property XSTARTL Auto ; ObjectReference[] Property XSTARTR Auto ; Arrays containing markers for the start and end points of the left and right walls ObjectReference[] Property XENDL Auto ; set in the order corresponding to their matching walls ObjectReference[] Property XENDR Auto ; ObjectReference[] Property WallsL Auto ; Arrays containing walls on the left and right ObjectReference[] Property WallsR Auto ; set in the order corresponding to their matching markers int speed = 1000 ; Controls the speed of translation for all objects bool ResetNextTranslation = false Function Move() ;Translates the objects to their destination While !Is3DLoaded() Utility.wait(0.2) ;causes the script to wait for Is3DLoaded() to be true, checking every .2 seconds EndWhile ResetNextTranslation = true TranslateToRef(XENDC, speed) ;control object int i = 0 While i<WallsL.length ;Left walls WallsL[i].TranslateToRef(XENDL[i], speed) i+=1 EndWhile i = 0 While i<WallsR.length ;Right Walls WallsR[i].TranslateToRef(XENDR[i], speed) i+=1 EndWhile EndFunction Function ResetPosition() ;Resets the objects position to the start location While !Is3DLoaded() Utility.wait(0.2) ;causes the script to wait for Is3DLoaded() to be true, checking every .2 seconds EndWhile ResetNextTranslation = false TranslateToRef(XSTARTC, 1000000) ;control object int i = 0 While i<WallsL.length ;Left walls WallsL[i].TranslateToRef(XSTARTL[i], 1000000) i+=1 EndWhile i = 0 While i<WallsR.length ;Right Walls WallsR[i].TranslateToRef(XSTARTR[i], 1000000) i+=1 EndWhile Endfunction Event OnCellLoad() ;Starts the recursion MoveToMyEditorLocation() ;This is just a reset to keep tunnel pieces from going nuts and gaps from forming in the tunnel wall Move() EndEvent Event OnTranslationComplete() ;Triggers if the translation was uninterrupted if ResetNextTranslation ResetPosition() else Move() endif EndEvent Event OnTranslationFailed() ;Triggers if OnTranslationComplete doesnt if ResetNextTranslation ResetPosition() else Move() endif EndEvent Which is more or less what I said to FrankFamily. I wasn't going to use arrays though; I was more or less going to use your script as is, only with object references for each object I want to move, but I suppose that having an array would make things quicker. Although to be honest, that script is a bit bigger than it needs to be. What I did to make the train tunnel was that I used the cylindrical carved Dwemer shaft that's used in a few Dwemer pitfall traps (tube-shaped thing with carved etchings on the inside). These things are enlarged to three times normal scale (scale value == 3), and are turned sideways 90 degrees, creating a tube-shaped tunnel (was thinking of the term "tube", meaning subway line, in British slang). The rails are bits of Dwemer dividers (they look like long, solid slabs of Dwemer metal, like someone took an octagon and stretched it). They're turned inward 45 degrees. In short, the tunnel only has 3 types of parts, the rails at -45 degrees (on the right side of the train), the rails at 45 degrees (on the left side of the train), and shaft pieces (which quite honest I don't know why Bethesda didn't make longer, as the shaft pieces are only really used twice in-game, and the shafts are relatively the same length). Link to comment Share on other sites More sharing options...
dalsio Posted September 8, 2016 Share Posted September 8, 2016 (edited) Is there a reason you don't want to use arrays? The script is larger because it has to run loops that take each object and execute an operation on it one after another. Realize that this code is acting as a controller script for all the objects in the room, replacing code that was once attached to each individual object. If you want them to all be synced, you need to operate on them all with the same script, which means this is the smallest it can be (without using a single array and a coordinate system). It doesn't matter how many types of objects there are, when doing it this way you need to reference every single ObjectReference individually. That means every "piece" of tube, railing, etc. has to be given to and operated on by the script meaning without an array, you would need an extra line of code for every operation on, every property containing, and every reference to, each of the sections of every rail and tube that needs to be moved. Putting them in an array allows you to have one line of code for the property declaration, and only a few lines of code to operate on all of them using a while loop. If there are more than 3 objects or "pieces", regardless of their type, I highly suggest using an array. Less code, less work, less room for error, less execution time, etc. You don't have to split them up into different arrays for different sides if you don't want to, I just had them split for the sake of grouping so that each side can be controlled as a unit. Edited September 8, 2016 by dalsio Link to comment Share on other sites More sharing options...
ZeroCore Posted September 8, 2016 Author Share Posted September 8, 2016 Is there a reason you don't want to use arrays? The script is larger because it has to run loops that take each object and execute an operation on it one after another. Realize that this code is acting as a controller script for all the objects in the room, replacing code that was once attached to each individual object. If you want them to all be synced, you need to operate on them all with the same script, which means this is the smallest it can be (without using a single array and a coordinate system). It doesn't matter how many types of objects there are, when doing it this way you need to reference every single ObjectReference individually. That means every "piece" of tube, railing, etc. has to be given to and operated on by the script meaning without an array, you would need an extra line of code for every operation on, every property containing, and every reference to, each of the sections of every rail and tube that needs to be moved. Putting them in an array allows you to have one line of code for the property declaration, and only a few lines of code to operate on all of them using a while loop. If there are more than 3 objects or "pieces", regardless of their type, I highly suggest using an array. Less code, less work, less room for error, less execution time, etc. You don't have to split them up into different arrays for different sides if you don't want to, I just had them split for the sake of grouping so that each side can be controlled as a unit. I didn't say that I didn't want to use arrays; I just said that I wasn't thinking of doing so. I've got nothing against using arrays. :) Link to comment Share on other sites More sharing options...
dalsio Posted September 8, 2016 Share Posted September 8, 2016 Arrays are your friend, friend. :laugh: Link to comment Share on other sites More sharing options...
FrankFamily Posted September 8, 2016 Share Posted September 8, 2016 Imo syncronized would be all parts of the wall moving at the same time, not one by one which is what a single thread would do. I think you should really merge the pieces as much as you can (copy paste the nitrishape branches in nifskope, pretty quick) to reduce the amount of pieces of the tunnel as much as possible, handling the collision would be more complicated but translateto doesn't move the collision of statics anyway (you'd have to make them movable static). I guess the player can't walk on the actual tunnel but a train within it so you can just ignore collision. If you can reduce it to 3 pieces or so the gaps would be much easier to hide. Regarding the animated textures, i did some experiments a while ago but it's not like a could teach. The tutorial I linked has a scrolling texture part, basically moving the texture across the uv map, it includes all the files, the dividers would be a problem though if they are not part of the same mesh. Link to comment Share on other sites More sharing options...
dalsio Posted September 8, 2016 Share Posted September 8, 2016 (edited) You might be confusing "multi-threading" with simply having more than one thread, as well as what a thread actually is. A thread is essentially a computer's "train of thought". It's a series of instructions (like lines of code) that are sent to the CPU that MUST be executed in sequence, without skipping. All computers work this way in that a single CPU core can only process one instruction at a time, in the order that it is given to it. You can have more than one thread but unless they are multi-threaded, they have to each wait their turn to be sent to and executed by the CPU core. When you have multiple scripts running in Skyrim at any given moment, they aren't actually running on separate threads. Instead, Skyrim's engine combines the scripts into a single thread that is then sent to the CPU. Simply making two different scripts does not make two different threads that are multi-threaded, as that would require intricate control of skyrim's engine. Multi-threading specifically refers to allowing two or more threads to each execute on their own CPU core simultaneously which means that you need to remove any dependency of one thread on another. Splitting something up between threads means you remove as much inter-dependency between the two parts of code to be threaded as possible; any communication, passing of variables, sharing of lists, etc. must be kept to a minimum if not removed altogether. If the two threads were constantly communicating with each other, that would cause one core to sit idle waiting for the other core to communicate to it and vice-versa, as well as introduce overhead due to cores having to constantly communicate with each other which would negate the performance benefits of multi-threading. Synchronization, on the other hand, requires that each object either "talks" to each other, or talks with a common controller/timer that is constantly regulating movement and timings. This inherently requires that the scripts become interdependent. Multi-threading is for better utilization of multiple cores for the sake of performance, not for synchronization. Any time you see synchronization in games, what you're actually seeing is each subsequent action being performed a fraction of a millisecond after the other (depending on how many lines of code came between the two actions), so fast than a human wouldn't notice. Edited September 8, 2016 by dalsio Link to comment Share on other sites More sharing options...
FrankFamily Posted September 8, 2016 Share Posted September 8, 2016 I'm pretty sure i'm not confusing anything and I know what multithreading is. The wiki is wrong or this: "When you have multiple scripts running in Skyrim at any given moment, they aren't actually running on separate threads. Instead, Skyrim's engine combines the scripts into a single thread that is then sent to the CPU" Is not exactly true, it specifically sais papyrus is multithreaded. Also imo, this: "Multi-threading is for better utilization of multiple cores for the sake of performance, not for synchronization." is overly simplistic. I don't have any interest in stealing the thread, so i'm just going to quickly quote some stuff from the wiki: http://www.creationkit.com/index.php?title=Creating_Multithreaded_Skyrim_Modsto add to the matter:Multithreading takes tasks that would otherwise be run in sequence and allows them to run simultaneously, which can reduce the time it takes to complete all tasks. Should I Multithread? => Does your mod / script:Have many external function calls to complete a single task? Have many objects that must be placed quickly using things like MoveTo()? Extensively or repeatedly use latent functions? Have time-critical tasks that rely on the results of other (potentially slow) functions? Have need of doing the same thing to a large group of objects? 1, 2 and 5 describe perfectly the script in question. In addition, the example on the wiki is basically spawning a bunch of npcs and doing stuff on them, where instead of doing that on a single thread (one at a time, clunky), it's better to do it multithreaded (simultaneously, aka syncronized). Moving all the pieces of the tunnel isn't any different. A lot of objects in which you need to do something (translate and move them) and it needs to be done at closely the same time. Not saying multithreading this would solve world hunger or cure cancer, but in my honest and unprofessional opinion it's worth a shot and might make it fluent and possible avoid gaps But as said, lets not hijack the thread, was just an idea. But don't tell me i'm confusing stuff because i'm pretty sure i'm not. Link to comment Share on other sites More sharing options...
dalsio Posted September 9, 2016 Share Posted September 9, 2016 But as said, lets not hijack the thread, was just an idea. Agreed. We will either end this discussion or take it elsewhere. Did not mean to offend you, or to derail the topic. Link to comment Share on other sites More sharing options...
ZeroCore Posted September 19, 2016 Author Share Posted September 19, 2016 I But as said, lets not hijack the thread, was just an idea. Agreed. We will either end this discussion or take it elsewhere. Did not mean to offend you, or to derail the topic. On that note; I admit that due to school and other things starting up again, I haven't touched this script since you posted that example. I was wondering though; since I don't frequently use arrays, does this script automatically add the references to the array's addresses, or do I have to do something to do that manually? Link to comment Share on other sites More sharing options...
FrankFamily Posted September 19, 2016 Share Posted September 19, 2016 Yep, you need to fill the array properties with the pieces, in the same window as the rest of the properties. Link to comment Share on other sites More sharing options...
Recommended Posts