k4kfh / ZephyrCab

Drive a model train with prototypical controls, realistic behavior, and simulated physics; uses JMRI's WebSockets interface for layout connection
http://k4kfh.github.io/ZephyrCab
GNU Affero General Public License v3.0
10 stars 4 forks source link

Properties being copied between train objects #13

Closed k4kfh closed 8 years ago

k4kfh commented 8 years ago

For some reason, properties are being copied between rolling stock elements with the same name. For example, if I add two "Generic Boxcar" elements to my train, and set some property on the first one, the property is INSTANTLY set on the second one.

It is not clear yet whether this extends to locomotives, as currently only one locomotive can be created.

This is present in master branch.

k4kfh commented 8 years ago

Removing train.js from index.html's head and adding items to the train via the developer console does not fix the problem. Exactly the same problem is exhibited.

k4kfh commented 8 years ago

This is not an accidental bug in some piece of code (which is good, I don't have to dig). Rather, it is an issue with JavaScript's object system itself. Since the objects added to the train come from the same source (bundles.rollingStock["Generic Boxcar"]) they all end up linked. This is present in both Chrome and Firefox, with and without any of my code running.

According to this StackOverflow, this is expected because of the way JavaScript handles objects. The proper way to handle this (I should've known) is to have each object in bundles.json be a constructor, not just a plain ol' object.

k4kfh commented 8 years ago

The constructor idea did not work. It does, in principle, but ZephyrCab depends on the ability to modify the "source" objects in bundles.json. It adds JMRI roster information, as well as decoder information. A true object "cloning" solution is needed, which pretty much doesn't exist in elegant native JavaScript. Since this only needs to be done on the initial adding of an object to the train, I am going with the following solution:


copyObject = JSON.parse(JSON.stringify(sourceObject));

If anyone has a better solution, I'm happy to investigate further.

k4kfh commented 8 years ago

The constructor idea did not work. It does, in principle, but ZephyrCab depends on the ability to modify the "source" objects in bundles.json. It adds JMRI roster information, as well as decoder information. A true object "cloning" solution is needed, which pretty much doesn't exist in elegant native JavaScript. Since this only needs to be done on the initial adding of an object to the train, I am going with the following solution:


copyObject = JSON.parse(JSON.stringify(sourceObject));

If anyone has a better solution, I'm happy to investigate further.

In my infinite wisdom, I lied. I did not realize that this method does not clone functions, as they are not "proper" JSON. A large amount of ZephyrCab relies on functions stored in individual train objects, so copying those functions is crucial. I opted to go with jQuery.extend, which is a "deep clone" system. It may be inefficient, but I can't afford to totally rewrite this program over something that only has to happen occasionally and otherwise works fine.