• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright 2015 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// To run, use the `go_sample.sh` script.
18
19package main
20
21import (
22	sample "MyGame/Sample"
23	"fmt"
24	flatbuffers "github.com/google/flatbuffers/go"
25	"strconv"
26)
27
28// Example how to use Flatbuffers to create and read binary buffers.
29func main() {
30	builder := flatbuffers.NewBuilder(0)
31
32	// Create some weapons for our Monster ("Sword" and "Axe").
33	weaponOne := builder.CreateString("Sword")
34	weaponTwo := builder.CreateString("Axe")
35
36	sample.WeaponStart(builder)
37	sample.WeaponAddName(builder, weaponOne)
38	sample.WeaponAddDamage(builder, 3)
39	sword := sample.WeaponEnd(builder)
40
41	sample.WeaponStart(builder)
42	sample.WeaponAddName(builder, weaponTwo)
43	sample.WeaponAddDamage(builder, 5)
44	axe := sample.WeaponEnd(builder)
45
46	// Serialize the FlatBuffer data.
47	name := builder.CreateString("Orc")
48
49	sample.MonsterStartInventoryVector(builder, 10)
50	// Note: Since we prepend the bytes, this loop iterates in reverse.
51	for i := 9; i >= 0; i-- {
52		builder.PrependByte(byte(i))
53	}
54	inv := builder.EndVector(10)
55
56	sample.MonsterStartWeaponsVector(builder, 2)
57	// Note: Since we prepend the weapons, prepend in reverse order.
58	builder.PrependUOffsetT(axe)
59	builder.PrependUOffsetT(sword)
60	weapons := builder.EndVector(2)
61
62	pos := sample.CreateVec3(builder, 1.0, 2.0, 3.0)
63
64	sample.MonsterStart(builder)
65	sample.MonsterAddPos(builder, pos)
66	sample.MonsterAddHp(builder, 300)
67	sample.MonsterAddName(builder, name)
68	sample.MonsterAddInventory(builder, inv)
69	sample.MonsterAddColor(builder, sample.ColorRed)
70	sample.MonsterAddWeapons(builder, weapons)
71	sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon)
72	sample.MonsterAddEquipped(builder, axe)
73	orc := sample.MonsterEnd(builder)
74
75	builder.Finish(orc)
76
77	// We now have a FlatBuffer that we could store on disk or send over a network.
78
79	// ...Saving to file or sending over a network code goes here...
80
81	// Instead, we are going to access this buffer right away (as if we just received it).
82
83	buf := builder.FinishedBytes()
84
85	// Note: We use `0` for the offset here, since we got the data using the
86	// `builder.FinishedBytes()` method. This simulates the data you would store/receive in your
87	// FlatBuffer. If you wanted to read from the `builder.Bytes` directly, you would need to
88	// pass in the offset of `builder.Head()`, as the builder actually constructs the buffer
89	// backwards.
90	monster := sample.GetRootAsMonster(buf, 0)
91
92	// Note: We did not set the `mana` field explicitly, so we get the
93	// default value.
94	assert(monster.Mana() == 150, "`monster.Mana()`", strconv.Itoa(int(monster.Mana())), "150")
95	assert(monster.Hp() == 300, "`monster.Hp()`", strconv.Itoa(int(monster.Hp())), "300")
96	assert(string(monster.Name()) == "Orc", "`string(monster.Name())`", string(monster.Name()),
97		"\"Orc\"")
98	assert(monster.Color() == sample.ColorRed, "`monster.Color()`",
99		strconv.Itoa(int(monster.Color())), strconv.Itoa(int(sample.ColorRed)))
100
101	// Note: Whenever you access a new object, like in `Pos()`, a new temporary accessor object
102	// gets created. If your code is very performance sensitive, you can pass in a pointer to an
103	// existing `Vec3` instead of `nil`. This allows you to reuse it across many calls to reduce
104	// the amount of object allocation/garbage collection.
105	assert(monster.Pos(nil).X() == 1.0, "`monster.Pos(nil).X()`",
106		strconv.FormatFloat(float64(monster.Pos(nil).X()), 'f', 1, 32), "1.0")
107	assert(monster.Pos(nil).Y() == 2.0, "`monster.Pos(nil).Y()`",
108		strconv.FormatFloat(float64(monster.Pos(nil).Y()), 'f', 1, 32), "2.0")
109	assert(monster.Pos(nil).Z() == 3.0, "`monster.Pos(nil).Z()`",
110		strconv.FormatFloat(float64(monster.Pos(nil).Z()), 'f', 1, 32), "3.0")
111
112	// For vectors, like `Inventory`, they have a method suffixed with 'Length' that can be used
113	// to query the length of the vector. You can index the vector by passing an index value
114	// into the accessor.
115	for i := 0; i < monster.InventoryLength(); i++ {
116		assert(monster.Inventory(i) == byte(i), "`monster.Inventory(i)`",
117			strconv.Itoa(int(monster.Inventory(i))), strconv.Itoa(int(byte(i))))
118	}
119
120	expectedWeaponNames := []string{"Sword", "Axe"}
121	expectedWeaponDamages := []int{3, 5}
122	weapon := new(sample.Weapon) // We need a `sample.Weapon` to pass into `monster.Weapons()`
123	// to capture the output of that function.
124	for i := 0; i < monster.WeaponsLength(); i++ {
125		if monster.Weapons(weapon, i) {
126			assert(string(weapon.Name()) == expectedWeaponNames[i], "`weapon.Name()`",
127				string(weapon.Name()), expectedWeaponNames[i])
128			assert(int(weapon.Damage()) == expectedWeaponDamages[i],
129				"`weapon.Damage()`", strconv.Itoa(int(weapon.Damage())),
130				strconv.Itoa(expectedWeaponDamages[i]))
131		}
132	}
133
134	// For FlatBuffer `union`s, you can get the type of the union, as well as the union
135	// data itself.
136	assert(monster.EquippedType() == sample.EquipmentWeapon, "`monster.EquippedType()`",
137		strconv.Itoa(int(monster.EquippedType())), strconv.Itoa(int(sample.EquipmentWeapon)))
138
139	unionTable := new(flatbuffers.Table)
140	if monster.Equipped(unionTable) {
141		// An example of how you can appropriately convert the table depending on the
142		// FlatBuffer `union` type. You could add `else if` and `else` clauses to handle
143		// other FlatBuffer `union` types for this field. (Similarly, this could be
144		// done in a switch statement.)
145		if monster.EquippedType() == sample.EquipmentWeapon {
146			unionWeapon := new(sample.Weapon)
147			unionWeapon.Init(unionTable.Bytes, unionTable.Pos)
148
149			assert(string(unionWeapon.Name()) == "Axe", "`unionWeapon.Name()`",
150				string(unionWeapon.Name()), "Axe")
151			assert(int(unionWeapon.Damage()) == 5, "`unionWeapon.Damage()`",
152				strconv.Itoa(int(unionWeapon.Damage())), strconv.Itoa(5))
153		}
154	}
155
156	fmt.Printf("The FlatBuffer was successfully created and verified!\n")
157}
158
159// A helper function to print out if an assertion failed.
160func assert(assertPassed bool, codeExecuted string, actualValue string, expectedValue string) {
161	if assertPassed == false {
162		panic("Assert failed! " + codeExecuted + " (" + actualValue +
163			") was not equal to " + expectedValue + ".")
164	}
165}
166