Home | History | Annotate | Download | only in samples
      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 
     19 package main
     20 
     21 import (
     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.
     29 func 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.
    160 func 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