Unity: Preserving static object/data between editor and play - scripting

I made offline Waypoints Network generator, which is able to construct waypoints network in editor so we can move or remove the waypoints during the editing process. However I need some way to reference the waypoints network from different objects in play mode and I really like the singleton approach. My idea is:
I have 3 scripts: WNNetwork, WNNetworkObject and WNNetworkData.
WNNetworkData is simple ScriptableObject, which holds the calculated data.
[System.Serializable]
public class WNNetworkData : ScriptableObject {
// Data of waypoints network
public List<WNWaypoint> waypoints = new List<WNWaypoint> ();
public WNKDTree tree = null;
}
WNNetworkObject is MonoBehaviour scripts that is attached to GameObject and it is use to update, re-generate or delete the waypoints network.
public class WNNetworkObject : MonoBehaviour {
#region Public Variables
// Properties of waypoints
public float size = 1f;
public Color color = Color.cyan;
public Color colorSelected = Color.white;
public Color colorLine = Color.white;
public float lineWidth = 0.5f;
public WNWaypoint.GizmosType type = WNWaypoint.GizmosType.CUBE;
// Parameters for network generation
public float maxClusterRadius = 2;
public float neighborsThreshold = 10f;
public bool doNeighborsSimplification = true;
// Others
// public GameObject queryTarget;
#endregion
#region Life-cycle
void Awake () {
DontDestroyOnLoad (this.gameObject);
}
void Start () {
Debug.Log (WNNetwork.data);
}
#endregion
...
}
This is how it's look in inspector editor:
WNNetwork Inspector editor
The last script is WNNetwork, which is basically a wrapper class holding static reference to WNNetworkData and WNNetworkObject, so I can easily access both.
public class WNNetwork {
public static WNNetworkObject root;
public static WNNetworkData data;
...
}
I also created an EditorScript, so I can create all objects from Menu, here is the creation part.
public class CreateWaypointsNetwork {
[MenuItem("GameObject/Create Other/Waypoints Network")]
public static void Create ()
{
WNNetworkData data = ScriptableObject.CreateInstance <WNNetworkData> ();
GameObject go = new GameObject ("WaypointsNetwork", new System.Type[]{typeof(WNNetworkObject)});
WNNetworkObject root = (WNNetworkObject) go.GetComponent<WNNetworkObject> ();
WNNetwork.data = data;
WNNetwork.root = root;
AssetDatabase.CreateAsset (data, "Assets/WaypointsNetworkData");
AssetDatabase.SaveAssets ();
EditorUtility.FocusProjectWindow ();
Selection.activeObject = go;
}
}
The thing is, when I create the Waypoints Network everything works in editor, every object seems to be successfully created and I can edit the waypoints. But as soon as I hit the play button, the WNNetwork is reset and all static variables are equal to null. The Network itself seems to be preserved, because every waypoint still have reference to all its neighbours, but I cannot access the data.
I know I am doing something terrible wrong, but I'm unable to determine what, I'm still not so familiar with Unity.
Thanks for any help.

Simply unity doesn't serialize static fields (even if they are of a serializable type).
When you switch from editor to play mode you are deserializing/serializing data, so you will end up losing everything stored into static fields.

Related

Making a highly customizable method, or a specific method that does a task?

I'm not really sure how I would phrase the title right, so I apologize for the initial confusion.
This is just a small question I had about how to structure code and such and I have no idea on what to call it so I will explain it with this example:
Say I am writing a Call of Duty type game where the player can customize their weapons with certain attachment.
I have a class that defines each gun. It looks something like this:
class Gun {
int clip = 30;
int ammo = 100;
float reloadTime = 5f;
float damage = 10f;
Attachment[] attachments;
//Plus some not included attachments.
void shoot() {
//...
}
void reload() {
//...
}
void applyAllAttachments() {
//Apply the list of attachments' effects
}
}
class Attachment {
void effect() {
//change the gun in some way.
}
}
Now I would like to add 4 attachments, Fast Mags (increase reload speed), Hollow Point (increase damage), Grenade Launcher (Secondary Gun) and Minigun (Replace the barrel with a minigun or something).
For the Fast Mags and the Hollow Point, it should be simple, all I have to do is change a number or a value, but for the Grenade Launcher and Minigun, which have custom, extra functions (like Unity Delegates), would it be wiser to add a function that handles external custom firing types, or would it be better to just have separate methods inside the Gun class that specifically handle to extra minigun functions?
TL;DR
If I want to add a grenade launcher attachment to a gun, should I do this:
class Gun {
int clip = 30;
int ammo = 100;
float reloadTime = 5f;
float damage = 10f;
Attachment[] attachments = Attachment[10];
//Plus some not included attachments.
void shoot() {
//...
customShoot();
}
void customShoot() {
//Apply attachments custom attachment shoot methods.
}
void reload() {
//...
}
void applyAllAttachments() {
//Apply the list of attachments' effects
}
}
class GrenadeLauncher extends Attachment {
#Override
public void effect() {
//Spawn new grenade
}
}
Or This:
class Gun {
int clip = 30;
int ammo = 100;
float reloadTime = 5f;
float damage = 10f;
Attachment[] attachments = Attachment[10];
//Plus some not included attachments.
void shoot() {
//...
if (attachments.GetType() == GrenadeLauncher) {
grenadeLauncherShoot();
}
}
void grenadeLauncherShoot() {
}
void reload() {
//...
}
void applyAllAttachments() {
//Apply the list of attachments' effects
}
}
Sorry for my pseudo/java code, hope it's comprehensible.
The first way is better: You can create new attachments without having to modify the Gun class.
In a general manner, you shouldn't need to check for type, and your code will be cleaner if you don't.
Here, your Attachment class should be abstract (I suppose it already is), and force children to implements some functions.
public abstract class Attachment
{
protected abstract void shoot();
}
Then the gun calls it for all Attachements:
class Gun {
int clip = 30;
int ammo = 100;
float reloadTime = 5f;
float damage = 10f;
Attachment[] attachments = Attachment[10];
//Plus some not included attachments.
void shoot() {
//...
for(int i = 0; i < attachments.length(); ++i) {
attachments[i].shoot();
}
}
void reload() {
//...
}
}
class GrenadeLauncher extends Attachment {
#Override
public void shoot()
{
//Spawn new grenade
}
}
By the way, why did you tag java and Unity? If you work with unity your code should be c# or javascript

I have an issue with casting Player to a MyPlayer

Hello I started learning to code minecraft bukkit plugins just few days a go, so please don't blame me if my issue is stiupid. I want to create a new MyPlayer class that will be Player subclass. I have already figured out that Player's root is org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer so I can make somethink like this: public class OticPlayer extends org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer. I want MyClass to contain all of his parent methods, but add some it's own. The problem is when i use: Bukkit.getPlayerExact(arg3[1]) it return the reference to a Player type object. I have a Lobby class with method addPlayer(MyPlayer arg0), so I need a reference to the MyPlayer type object, not Player. When I will try to cast a Player type reference to MyPlayer, it's throws an exception: java.lang.ClassCastException: org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer cannot be cast to me.gtddd.my.MyPlayer. I need to pass MyPlayer type reference to the addPlayer() method, because I want to make some kind of stats system (K/D/A), each of these stats must be a pool accesable, by MyPlayer type object. So how can I cast Player to MyPlayer? Example code that generates this problem:
package test;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_12_R1.CraftServer;
import org.bukkit.plugin.java.JavaPlugin;
import me.gtddd.otic.OticPlayer;
import net.minecraft.server.v1_12_R1.EntityPlayer;
public class MyPlayer extends org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer {
public MyPlayer(CraftServer server, EntityPlayer entity) {
super(server, entity);
}
int kills = 0;
int deaths = 0;
int assists = 0;
public int getKda() {
return kills/deaths/assists;
}
}
public class Lobby {
MyPlayer[] players = new MyPlayer[10];
public void addPlayer(MyPlayer arg0) {
players[players.length] = arg0;
}
public MyPlayer getPlayer(int slot) {
return players[slot-1];
}
}
public class Main extends JavaPlugin {
#Override
public void onEnable() {
Lobby lobby1 = new Lobby();
MyPlayer player = (MyPlayer) Bukkit.getPlayerExact("Notch");
lobby1.addPlayer(player);
System.out.println(lobby1.getPlayer(1).getKda());
}
}
I looked lot to find the answer, but I was not able to find anythink what would satisfy me. From top: Thanks for all answers! If somethink is unclear ask.
Instead of extending a Player, you should create a Wrapper around Bukkit's Player Object, more specifically wrapping the Player's Name or UUID (recommended) as it's not possible to edit Bukkit's Player instances without a lot of effort, it's implementation is very obscure, and you won't be able to include your MyPlayer in Bukkit's server.
So, for example, you could create a MyPlayer as following:
class MyPlayer {
private String playerName;
public MyPlayer(Player player) {
playerName = player.getDisplayName(); //Something like this to store the player
}
//More of your code, for example counting the kills
public Player recoverPlayerObject() {
return Bukkit.getPlayer(playerName);
}
And if you want to do things like adding a kill to the player, and then teleporting him, you could use your MyPlayer instance to modify your players' attributes, and using the recoverPlayerObject if you need to interact directly with Bukkit Player object.
For more information on Wrapper/Decorator, Iluwatar has a very nice Github repository about Design Patterns, including the Decorator.

Accesing arraylist property from another class using constructor

So i have a class that makes an array list for me and i need to access it in another class through a constructor but i don't know what to put into the constructor because all my methods in that class are just for manipulating that list. im either getting a null pointer exception or a out of bounds exception. ive tried just leaving the constructor empty but that dosent seem to help. thanks in advance. i would show you code but my professor is very strict on academic dishonesty so i cant sorry if that makes it hard.
You are confusing the main question, with a potential solution.
Main Question:
I have a class ArrayListOwnerClass with an enclosed arraylist property or field.
How should another class ArrayListFriendClass access that property.
Potential Solution:
Should I pass the arraylist from ArrayListOwnerClass to ArrayListFriendClass,
in the ArrayListFriendClass constructor ?
It depends on what the second class does with the arraylist.
Instead of passing the list thru the constructor, you may add functions to read or change, as public, the elements of the hidden internal arraylist.
Note: You did not specify a programming language. I'll use C#, altought Java, C++, or similar O.O.P. could be used, instead.
public class ArrayListOwnerClass
{
protected int F_Length;
protected ArrayList F_List;
public ArrayListOwnerClass(int ALength)
{
this.F_Length = ALength;
this.F_List = new ArrayList(ALength);
// ...
} // ArrayListOwnerClass(...)
public int Length()
{
return this.F_Length;
} // int Length(...)
public object getAt(int AIndex)
{
return this.F_List[AIndex];
} // object getAt(...)
public void setAt(int AIndex, object AValue)
{
this.F_List[AIndex] = AValue;
} // void setAt(...)
public void DoOtherStuff()
{
// ...
} // void DoOtherStuff(...)
// ...
} // class ArrayListOwnerClass
public class ArrayListFriendClass
{
public void UseArrayList(ArrayListOwnerClass AListOwner)
{
bool CanContinue =
(AListOwner != null) && (AListOwner.Length() > 0);
if (CanContinue)
{
int AItem = AListOwner.getAt(5);
DoSomethingWith(Item);
} // if (CanContinue)
} // void UseArrayList(...)
public void AlsoDoesOtherStuff()
{
// ...
} // void AlsoDoesOtherStuff(...)
// ...
} // class ArrayListFriendClass
Note, that I could use an indexed property.

Loading Static Data from Database in an RIA Application

As part of a WCF RIA application I'm creating, I'd like to cache a bunch of static supporting data locally (lists of water systems, countries, provinces; that sort of thing.) I've created a simple static class to cache the lists into (LocalStateContainer.cs).
Example:
public static class LocalStateContainer
{
private static IEnumerable _waterSystems;
public static IEnumerable WaterSystems
{
get
{
if (_waterSystems== null)
{
DomainDataSource ds = new DomainDataSource();
Web.SuperDomainContext d = new Web.SuperDomainContext();
ds.DomainContext = d;
ds.QueryName = "GetWaterSystems";
ds.Load();
_waterSystems = ds.Data;
}
return _waterSystems;
}
}
}
Is it prudent to use a DomainDataSource in this way? Could I not just as easily go:
public static class LocalStateContainer
{
private static IEnumerable _waterSystems;
public static IEnumerable WaterSystems
{
get
{
if (_waterSystems== null)
{
Web.SuperDomainContext d = new Web.SuperDomainContext();
_waterSystems = from w in d.WaterSystems select w;
}
return _waterSystems;
}
}
}
More broadly, when is it smart to use a DomainDataSource to retrieve data versus accessing the DomainContext directly? I imagine for 2-way linking the DomainDataSource is the way to go, but is it harmful/foolish to yank static data directly out of the DomainContext?
Any insight is appreciated; I'm still very new to Silverlight so apologies if this is mickey mouse stuff.
Thanks!
I wouldn't bother with a DomainDataSource here, just have a static myDomainContext in App.cs that you can ping:
LoadOperation<my_entity> loadComplete = App.myDAL.Load(App.myDAL.Getmy_entityQuery());
And then if you care about knowing when it's done fetching:
loadComplete.Completed += new EventHandler(loadChain_Completed);
void loadChain_Completed(object sender, EventArgs e)
{
//Stuff to do when data has been fetched, for example
return App.myDAL.my_entitys.ToList();
}

Single reference into multiple objects

I am a bit lot about what to do in an OO/DB relation...
Here is the DB model :
CREATE TABLE User
Id
CREATE TABLE Location
userId
// EDIT oups, wrong !
// placeId
// Should be :
seatId
CREATE TABLE Game
locationId
Now some code :
class User
{
private Location locations[]; // need this for several reasons...
public function loadFromDatabase()
{
// Load data from DB
// ...
result = DB::query("SELECT Id FROM Locations WHERE userId="+this->Id);
foreach(result)
{
l = new Location();
l->loadFromDatabase(result);
locations[] = l;
}
}
}
class Location
{
private User user;
public function loadFromDatabase()
{
...
}
}
class Game
{
private Location location;
public loadFromDatabase()
{
/*
Here comes the problem :
how to have a reference to a location
created by the User class ?
*/
}
}
A User play Games in several Locations.
EDIT : And for each location the user plays on seat. Or on another seat...
When I want to know where a game has been played I access Game.location. And when I want to know who played it, I access Game.location.user
Here is my problem : I want the Game.location to be the same reference to one of the User.locations and I do not know how to do this...
And, globally, I feel something wrong about my code...
Any help ?
Thanks
Since you have a placeId in your Location table, I assume there is a Place table which describes what the places actually are, while the Location table simply represents the many-to-many mapping between users and places.
In that case, Location doesn't need to have an Id of its own and doesn't need to be a class, but Place does.
To load just one instance of each object from the database, cache the instances in a static map inside each class.
class Place
{
// Static
private static Place loadedPlaces[];
public static function get(id)
{
if (!loadedPlaces[id])
{
loadedPlaces[id] = new Place(id);
loadedPlaces[id]->loadFromDatabase();
}
return loadedPlaces[id];
}
// Non-static
private id;
public function loadFromDatabase()
{
// ...
}
}
Then to get references to places for the properties of a user or a game, you just access them via the static method.
class User
{
public function loadFromDatabase()
{
result = DB::query("SELECT placeId FROM Locations WHERE userId="+this->Id);
foreach(result)
{
places[] = Place::get(result);
}
}
}
class Game
{
public function loadFromDatabase()
{
place = Place::get(place);
}
}
This uses:
Lazy initialization, because places are only loaded when they are needed.
Multiton pattern, because there is only one instance of each place by id.
Not quite a factory method, because there's no object hierarchy involved.