Save File Format

Saving now uses Json serialization for easy to use, human readable format. More specifically, JSON .NET for Unity.

You can modify the physics properties of an object in the save file. By adding and modifying the PhysicsMaterial and Rigidbody. You can see an example of that in the Json below.

You can also change an objects scaling separately in each axis, unlike the uniform only scaling in-game.

Newly added in v4.0 you can control the shader for custom objects, check out the CustomShaderState below.

If you make any mistakes when editing a save, the chat will spit out a debugging error for troubleshooting.

If you have any questions on this topic feel free to post about it on our forums.

**Example Json:**

```
{
  "SaveName": "Json Example Save",
  "GameMode": "None",
  "Date": "2/22/2015 2:44:18 PM",
  "Table": "Table_Octagon",
  "Sky": "Sky_Forest",
  "Note": "This is an example save demonstrating how to use the custom shader and edit physics properties.",
  "Rules": "",
  "PlayerTurn": "",
  "Grid": {
    "Type": 0,
    "Lines": false,
    "Snapping": false,
    "Offset": false,
    "xSize": 2.0,
    "ySize": 2.0
  },
  "DrawImage": "",
  "ObjectStates": [
    {
      "Name": "Custom_Model",
      "Transform": {
        "posX": -6.14662361,
        "posY": 1.02520883,
        "posZ": 0.435920656,
        "rotX": 8.387837E-06,
        "rotY": 179.991959,
        "rotZ": 1.49730022E-05,
        "scaleX": 1.0,
        "scaleY": 1.0,
        "scaleZ": 1.0
      },
      "Nickname": "Example Chip",
      "Description": "You can see how to tweak the custom shader with this example.",
      "ColorDiffuse": {
        "r": 0.9999999,
        "g": 0.9999999,
        "b": 0.9999999
      },
      "Grid": true,
      "Locked": false,
      "CustomMesh": {
        "MeshURL": "http://pastebin.com/raw.php?i=00YWZ28Y",
        "DiffuseURL": "http://www.berserk-games.com/images/TTS-Coin-Template.png",
        "NormalURL": "",
        "ColliderURL": "",
        "Convex": true,
        "MaterialIndex": 1,
        "TypeIndex": 5,
        "CustomShader": {
          "SpecularColor": {
            "r": 0.9,
            "g": 0.9,
            "b": 0.9
          },
          "SpecularIntensity": 0.1,
          "SpecularSharpness": 3.0,
          "FresnelStrength": 0.1
        }
      }
    },
    {
      "Name": "Die_20",
      "Transform": {
        "posX": 5.3177824,
        "posY": 1.38374138,
        "posZ": 0.03327445,
        "rotX": 10.8123074,
        "rotY": 0.00238325051,
        "rotZ": 198.000031,
        "scaleX": 1.0,
        "scaleY": 1.0,
        "scaleZ": 1.0
      },
      "Nickname": "Example D20",
      "Description": "You can see how to tweak the physics properties of an object with this example.",
      "ColorDiffuse": {
        "r": 0.7960843,
        "g": 0.0,
        "b": 0.0
      },
      "Grid": false,
      "Locked": false,
      "MaterialIndex": 0,
      "PhysicsMaterial": {
        "DynamicFriction": 0.4,
        "StaticFriction": 0.4,
        "Bounciness": 0.0,
        "FrictionCombine": 0,
        "BounceCombine": 0
      },
      "Rigidbody": {
        "Mass": 1.0,
        "Drag": 0.1,
        "AngularDrag": 0.1,
        "UseGravity": true
      }
    }
  ]
}
```

**Here are the classes that are serialized:**

```
public class SaveState { //Holds a state of the game

	public string SaveName = "";
	public string GameMode = "";
	public string Date = "";
	public string Table = "";
	public string TableURL = null; //For custom large table
	public string Sky = "";
	public string SkyURL = null; //For custom sky
	public string Note = "";
	public string Rules = "";
	public string PlayerTurn = "";
	public GridState Grid;
	public byte[] DrawImage; //PNG converted to bytes
	public List<ObjectState> ObjectStates; //Object on the table
}

public class ObjectState { //Moveable objects

	public string Name = ""; //Internal object name
	public TransformState Transform;
	public string Nickname = ""; //Name supplied in game
	public string Description = "";
	public ColorState ColorDiffuse;
	public bool Grid = true;
	public bool Locked = false;
	/*Nullable to hide object specific properties and save space*/
	public Nullable<bool> AltSound; //Some objects have 2 materials, with two sound sets
	public Nullable<int> MaterialIndex;
	public Nullable<int> MeshIndex;
	public Nullable<int> Layer; //Sound Layer
	public Nullable<int> Number;
	public Nullable<int> CardID;
	public Nullable<bool> SidewaysCard;
	public Nullable<bool> RPGmode;
	public Nullable<bool> RPGdead;
	public string FogColor = null;
	public Nullable<bool> FogHidePointers;
	public List<int> DeckIDs;
	public Dictionary<int, CustomDeckState> CustomDeck; //Key matches the hundreth place of the id (ex. id = 354, index = 3)
	public CustomMeshState CustomMesh;
	public CustomImageState CustomImage;
	public ClockSaveState Clock;
	public TabletState Tablet;
	public List<ObjectState> ContainedObjects; //Objects in bag
	public PhysicsMaterialState PhysicsMaterial; //Use to modify the physics material (friction, bounce, etc.) http://docs.unity3d.com/Manual/class-PhysicMaterial.html
	public RigidbodyState Rigidbody; //Use to modify the physical properties (mass, drag, etc) http://docs.unity3d.com/Manual/class-Rigidbody.html

	public bool EqualsJson(System.Object obj)
	{
		if (obj == null)
		{
			return false;
		}

		ObjectState p = obj as ObjectState;
		if ((System.Object)p == null)
		{
			return false;
		}

		string ThisJson = SaveScript.GetJsonString(this);
		string NewJson = SaveScript.GetJsonString(p);
		return ThisJson == NewJson;
	}

	public ObjectState Clone()
	{
		string JsonString = SaveScript.GetJsonString(this);
		return SaveScript.GetObjectState(JsonString);
	}

	public string ToJson()
	{
		return SaveScript.GetJsonString(this);
	}

}

public class GridState {

	public GridType Type;
	public bool Lines;
	public bool Snapping;
	public bool Offset;
	public float xSize;
	public float ySize;
}

public enum GridType
{
	Box, Hex
};

public class TransformState {

	public float posX;
	public float posY;
	public float posZ;

	public float rotX;
	public float rotY;
	public float rotZ;

	public float scaleX;
	public float scaleY;
	public float scaleZ;
}

public class ColorState
{
	public float r, g, b;
	public ColorState(float r, float g, float b)
	{
		this.r = r;
		this.g = g;
		this.b = b;
	}
}

public class RigidbodyState
{
	public float Mass = 1f; //The mass of the object (arbitrary units). You should not make masses more or less than 100 times that of other Rigidbodies.
	public float Drag = 0.1f; //How much air resistance affects the object when moving from forces. 0 means no air resistance, and infinity makes the object stop moving immediately.
	public float AngularDrag = 0.1f; //How much air resistance affects the object when rotating from torque. 0 means no air resistance. Note that you cannot make the object stop rotating just by setting its Angular Drag to infinity.
	public bool UseGravity = true; //If enabled, the object is affected by gravity.
}

public class PhysicsMaterialState
{
	public float DynamicFriction = 0.4f; //The friction used when already moving. Usually a value from 0 to 1. A value of zero feels like ice, a value of 1 will make it come to rest very quickly unless a lot of force or gravity pushes the object.
	public float StaticFriction = 0.4f; //The friction used when an object is laying still on a surface. Usually a value from 0 to 1. A value of zero feels like ice, a value of 1 will make it very hard to get the object moving.
	public float Bounciness = 0f; //How bouncy is the surface? A value of 0 will not bounce. A value of 1 will bounce without any loss of energy.
	public PhysicMaterialCombine FrictionCombine = PhysicMaterialCombine.Average; //How the friction of two colliding objects is combined. 0 = Average, 1 = Minimum, 2 = Maximum, 3 = Multiply.
	public PhysicMaterialCombine BounceCombine = PhysicMaterialCombine.Average; //How the bounciness of two colliding objects is combined. 0 = Average, 1 = Minimum, 2 = Maximum, 3 = Multiply.
}

public class CustomDeckState {

	public string FaceURL = "";
	public string BackURL = "";
}

public class CustomImageState {

	public string ImageURL = "";
	public float WidthScale;
}

public class CustomMeshState {

	public string MeshURL = "";
	public string DiffuseURL = "";
	public string NormalURL = "";
	public string ColliderURL = "";
	public bool Convex = true;
	public int MaterialIndex = 0; //0 = Plastic, 1 = Wood, 2 = Metal.
	public int TypeIndex = 0; //0 = Generic, 1 = Figurine, 2 = Dice, 3 = Coin, 4 = Board, 5 = Chip
	public CustomShaderState CustomShader; //Used to override the shader
}

public class CustomShaderState {

	public ColorState SpecularColor = new ColorState(0.9f, 0.9f, 0.9f);
	public float SpecularIntensity = 0.1f;
	public float SpecularSharpness = 3f; //Range: 2 - 8
	public float FresnelStrength = 0.1f; //Range: 0 - 1
}

public class TabletState {

	public string PageURL = "";
}

public class ClockSaveState {

	public ClockScript.ClockState ClockState;
	public int SecondsPassed = 0;
	public bool Paused = false;
}
```

**List of object names:**

```
backgammon_board
backgammon_piece_brown
backgammon_piece_white
Bag
BlockRectangle
BlockSquare
BlockTriangle
Card Facade
Card
CardBot_Board
CheckerFacade
CheckerStack
Checker_black
Checker_Board
Checker_red
Checker_white
Chess_Bishop
Chess_Board
Chess_King
Chess_Knight
Chess_Pawn
Chess_Queen
Chess_Rook
Chinese_Checkers_Board
Chinese_Checkers_Piece
ChipFacade
ChipStack
Chip_10
Chip_100
Chip_1000
Chip_50
Chip_500
Cup
Custom_Board
Custom_Model
Deck
DeckCustom
Deck_CardBot_Head
Deck_CardBot_Main
Die_10
Die_12
Die_20
Die_4
Die_6
Die_6_Rounded
Die_8
Die_Piecepack
Digital_Clock
Domino
Figurine_Card_Bot
Figurine_Custom
Figurine_Kimi_Kat
Figurine_Knil
Figurine_Mara
Figurine_Sir_Loin
Figurine_Zeke
Figurine_Zomblor
FogOfWarTrigger
Go_Board
go_game_bowl_black
go_game_bowl_white
go_game_piece_black
go_game_piece_white
LineObject
Mahjong_Coin
Mahjong_Stick
Mahjong_Tile
MarqueeTrigger
Metal Ball
Pachisi_board
PiecePack_Arms
PiecePack_Crowns
PiecePack_Moons
PiecePack_Suns
PlayerPawn
Quarter
reversi_board
reversi_chip
rpg_BEAR
rpg_CHIMERA
rpg_CYCLOP
rpg_DRAGONIDE
rpg_EVIL_WATCHER
rpg_GHOUL
rpg_GIANT_VIPER
rpg_GOBLIN
rpg_GOLEM
rpg_GRIFFON
rpg_HYDRA
rpg_KOBOLD
rpg_LIZARD_WARRIOR
rpg_MANTICORA
rpg_MUMMY
rpg_OGRE
rpg_ORC
rpg_RAT
rpg_SKELETON_KNIGHT
rpg_TREE_ENT
rpg_TROLL
rpg_VAMPIRE
rpg_WEREWOLF
rpg_WOLF
rpg_WYVERN
SearchSpaceHolder
SearchTriggerObject
Sky_Field
Sky_Forest
Sky_Museum
Sky_Tunnel
Table_Circular
Table_Custom
Table_Glass
Table_Hexagon
Table_Octagon
Table_Poker
Table_RPG
Table_Square
Tileset_Barrel
Tileset_Chair
Tileset_Chest
Tileset_Corner
Tileset_Floor
Tileset_Rock
Tileset_Table
Tileset_Tree
Tileset_Wall
```