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