mirror of
				https://github.com/genxium/DelayNoMore
				synced 2025-11-03 21:06:35 +00:00 
			
		
		
		
	A broken commit during backend bullet adaptation.
This commit is contained in:
		@@ -2,7 +2,6 @@ package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	. "battle_srv/protos"
 | 
			
		||||
	. "dnmshared/sharedprotos"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) map[int32]*PlayerDownsync {
 | 
			
		||||
@@ -13,13 +12,11 @@ func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) map[int32]
 | 
			
		||||
 | 
			
		||||
	for k, last := range modelInstances {
 | 
			
		||||
		toRet[k] = &PlayerDownsync{
 | 
			
		||||
			Id:           last.Id,
 | 
			
		||||
			VirtualGridX: last.VirtualGridX,
 | 
			
		||||
			VirtualGridY: last.VirtualGridY,
 | 
			
		||||
			Dir: &Direction{
 | 
			
		||||
				Dx: last.Dir.Dx,
 | 
			
		||||
				Dy: last.Dir.Dy,
 | 
			
		||||
			},
 | 
			
		||||
			Id:             last.Id,
 | 
			
		||||
			VirtualGridX:   last.VirtualGridX,
 | 
			
		||||
			VirtualGridY:   last.VirtualGridY,
 | 
			
		||||
			DirX:           last.DirX,
 | 
			
		||||
			DirY:           last.DirY,
 | 
			
		||||
			ColliderRadius: last.ColliderRadius,
 | 
			
		||||
			Speed:          last.Speed,
 | 
			
		||||
			BattleState:    last.BattleState,
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@ import (
 | 
			
		||||
	. "battle_srv/protos"
 | 
			
		||||
	"battle_srv/storage"
 | 
			
		||||
	. "dnmshared"
 | 
			
		||||
	. "dnmshared/sharedprotos"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	sq "github.com/Masterminds/squirrel"
 | 
			
		||||
	"github.com/jmoiron/sqlx"
 | 
			
		||||
@@ -64,12 +63,7 @@ func GetPlayerById(id int) (*Player, error) {
 | 
			
		||||
 | 
			
		||||
func getPlayer(cond sq.Eq) (*Player, error) {
 | 
			
		||||
	p := Player{}
 | 
			
		||||
	pd := PlayerDownsync{
 | 
			
		||||
		Dir: &Direction{
 | 
			
		||||
			Dx: 0,
 | 
			
		||||
			Dy: 0,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	pd := PlayerDownsync{}
 | 
			
		||||
	query, args, err := sq.Select("*").From("player").Where(cond).Limit(1).ToSql()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
 
 | 
			
		||||
@@ -54,6 +54,7 @@ const (
 | 
			
		||||
 | 
			
		||||
	COLLISION_PLAYER_INDEX_PREFIX  = (1 << 17)
 | 
			
		||||
	COLLISION_BARRIER_INDEX_PREFIX = (1 << 16)
 | 
			
		||||
	COLLISION_BULLET_INDEX_PREFIX  = (1 << 15)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@@ -1147,13 +1148,6 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		nextRenderFrame := pR.applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, currRenderFrame, pR.CollisionSysMap)
 | 
			
		||||
		// Update in the latest player pointers
 | 
			
		||||
		for playerId, playerDownsync := range nextRenderFrame.Players {
 | 
			
		||||
			pR.Players[playerId].VirtualGridX = playerDownsync.VirtualGridX
 | 
			
		||||
			pR.Players[playerId].VirtualGridY = playerDownsync.VirtualGridY
 | 
			
		||||
			pR.Players[playerId].Dir.Dx = playerDownsync.Dir.Dx
 | 
			
		||||
			pR.Players[playerId].Dir.Dy = playerDownsync.Dir.Dy
 | 
			
		||||
		}
 | 
			
		||||
		pR.RenderFrameBuffer.Put(nextRenderFrame)
 | 
			
		||||
		pR.CurDynamicsRenderFrameId++
 | 
			
		||||
	}
 | 
			
		||||
@@ -1166,18 +1160,23 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
 | 
			
		||||
	// Make a copy first
 | 
			
		||||
	for playerId, currPlayerDownsync := range currRenderFrame.Players {
 | 
			
		||||
		nextRenderFramePlayers[playerId] = &PlayerDownsync{
 | 
			
		||||
			Id:           playerId,
 | 
			
		||||
			VirtualGridX: currPlayerDownsync.VirtualGridX,
 | 
			
		||||
			VirtualGridY: currPlayerDownsync.VirtualGridY,
 | 
			
		||||
			Dir: &Direction{
 | 
			
		||||
				Dx: currPlayerDownsync.Dir.Dx,
 | 
			
		||||
				Dy: currPlayerDownsync.Dir.Dy,
 | 
			
		||||
			},
 | 
			
		||||
			Speed:       currPlayerDownsync.Speed,
 | 
			
		||||
			BattleState: currPlayerDownsync.BattleState,
 | 
			
		||||
			Score:       currPlayerDownsync.Score,
 | 
			
		||||
			Removed:     currPlayerDownsync.Removed,
 | 
			
		||||
			JoinIndex:   currPlayerDownsync.JoinIndex,
 | 
			
		||||
			Id:              playerId,
 | 
			
		||||
			VirtualGridX:    currPlayerDownsync.VirtualGridX,
 | 
			
		||||
			VirtualGridY:    currPlayerDownsync.VirtualGridY,
 | 
			
		||||
			DirX:            currPlayerDownsync.DirX,
 | 
			
		||||
			DirY:            currPlayerDownsync.DirY,
 | 
			
		||||
			CharacterState:  currPlayerDownsync.CharacterState,
 | 
			
		||||
			Speed:           currPlayerDownsync.Speed,
 | 
			
		||||
			BattleState:     currPlayerDownsync.BattleState,
 | 
			
		||||
			Score:           currPlayerDownsync.Score,
 | 
			
		||||
			Removed:         currPlayerDownsync.Removed,
 | 
			
		||||
			JoinIndex:       currPlayerDownsync.JoinIndex,
 | 
			
		||||
			FramesToRecover: currPlayerDownsync.FramesToRecover - 1,
 | 
			
		||||
			Hp:              currPlayerDownsync.Hp,
 | 
			
		||||
			MaxHp:           currPlayerDownsync.MaxHp,
 | 
			
		||||
		}
 | 
			
		||||
		if nextRenderFramePlayers[playerId].FramesToRecover < 0 {
 | 
			
		||||
			nextRenderFramePlayers[playerId].FramesToRecover = 0
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -1185,29 +1184,113 @@ func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputF
 | 
			
		||||
		Id:             currRenderFrame.Id + 1,
 | 
			
		||||
		Players:        nextRenderFramePlayers,
 | 
			
		||||
		CountdownNanos: (pR.BattleDurationNanos - int64(currRenderFrame.Id)*pR.RollbackEstimatedDtNanos),
 | 
			
		||||
		MeleeBullets:   make([]*MeleeBullet, 0), // Is there any better way to reduce malloc/free impact, e.g. smart prediction for fixed memory allocation?
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bulletPushbacks := make([]Vec2D, pR.Capacity) // Guaranteed determinism regardless of traversal order
 | 
			
		||||
	effPushbacks := make([]Vec2D, pR.Capacity)    // Guaranteed determinism regardless of traversal order
 | 
			
		||||
 | 
			
		||||
	// Reset playerCollider position from the "virtual grid position"
 | 
			
		||||
	for playerId, player := range pR.Players {
 | 
			
		||||
		joinIndex := player.JoinIndex
 | 
			
		||||
		bulletPushbacks[joinIndex-1].X, bulletPushbacks[joinIndex-1].Y = float64(0), float64(0)
 | 
			
		||||
		effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y = float64(0), float64(0)
 | 
			
		||||
		currPlayerDownsync := currRenderFrame.Players[playerId]
 | 
			
		||||
		newVx, newVy := currPlayerDownsync.VirtualGridX, currPlayerDownsync.VirtualGridY
 | 
			
		||||
		collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
 | 
			
		||||
		playerCollider := collisionSysMap[collisionPlayerIndex]
 | 
			
		||||
		playerCollider.X, playerCollider.Y = VirtualGridToPolygonColliderAnchorPos(newVx, newVy, player.ColliderRadius, player.ColliderRadius, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, pR.VirtualGridToWorldRatio)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check bullet-anything collisions first, because the pushbacks caused by bullets might later be reverted by player-barrier collision
 | 
			
		||||
	bulletColliders := make(map[int32]*resolv.Object, 0) // Will all be removed at the end of `applyInputFrameDownsyncDynamicsOnSingleRenderFrame` due to the need for being rollback-compatible
 | 
			
		||||
	removedBulletsAtCurrFrame := make(map[int32]int32, 0)
 | 
			
		||||
	for _, meleeBullet := range currRenderFrame.MeleeBullets {
 | 
			
		||||
		if (meleeBullet.OriginatedRenderFrameId+meleeBullet.StartupFrames <= currRenderFrame.Id) && (meleeBullet.OriginatedRenderFrameId+meleeBullet.StartupFrames+meleeBullet.ActiveFrames > currRenderFrame.Id) {
 | 
			
		||||
			collisionBulletIndex := COLLISION_BULLET_INDEX_PREFIX + meleeBullet.BattleLocalId
 | 
			
		||||
			collisionOffenderIndex := COLLISION_PLAYER_INDEX_PREFIX + meleeBullet.OffenderJoinIndex
 | 
			
		||||
			offenderCollider := collisionSysMap[collisionOffenderIndex]
 | 
			
		||||
			offender := currRenderFrame.Players[meleeBullet.OffenderPlayerId]
 | 
			
		||||
 | 
			
		||||
			xfac, yfac := float64(1.0), float64(0) // By now, straight Punch offset doesn't respect "y-axis"
 | 
			
		||||
			if 0 > offender.DirX {
 | 
			
		||||
				xfac = float64(-1.0)
 | 
			
		||||
			}
 | 
			
		||||
			offenderWx, offenderWy := PolygonColliderAnchorToWorldPos(offenderCollider.X, offenderCollider.Y, offender.ColliderRadius, offender.ColliderRadius, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY)
 | 
			
		||||
 | 
			
		||||
			bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy+yfac*meleeBullet.HitboxOffset
 | 
			
		||||
 | 
			
		||||
			newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, xfac*meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, "MeleeBullet")
 | 
			
		||||
			// newBulletCollider.collisionBulletIndex = collisionBulletIndex
 | 
			
		||||
			// newBulletCollider.offenderPlayerId = meleeBullet.offenderPlayerId
 | 
			
		||||
			// newBulletCollider.pushback = meleeBullet.pushback
 | 
			
		||||
			// newBulletCollider.hitStunFrames = meleeBullet.hitStunFrames
 | 
			
		||||
			collisionSysMap[collisionBulletIndex] = newBulletCollider
 | 
			
		||||
			bulletColliders[collisionBulletIndex] = newBulletCollider
 | 
			
		||||
			newBulletCollider.Update()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// for _, bulletCollider := range bulletColliders {
 | 
			
		||||
	// 	shouldRemove := false
 | 
			
		||||
	// 	if collision := bulletCollider.Check(0, 0); collision != nil {
 | 
			
		||||
	// 		bulletShape := bulletCollider.Shape.(*resolv.ConvexPolygon)
 | 
			
		||||
	// 		for _, obj := range collision.Objects {
 | 
			
		||||
	// 			bShape := obj.Shape.(*resolv.ConvexPolygon)
 | 
			
		||||
	// 			if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, bulletShape, bShape); overlapped {
 | 
			
		||||
	// 				bulletPushbacks[joinIndex-1].X += pushbackX
 | 
			
		||||
	// 				bulletPushbacks[joinIndex-1].Y += pushbackY
 | 
			
		||||
	// 			}
 | 
			
		||||
	// 		}
 | 
			
		||||
	// 		shouldRemove = true
 | 
			
		||||
	// 	}
 | 
			
		||||
	// 	if shouldRemove {
 | 
			
		||||
	// 		removedBulletsAtCurrFrame[bulletCollider.CollisionBulletIndex] = 1
 | 
			
		||||
	// 	}
 | 
			
		||||
	// }
 | 
			
		||||
 | 
			
		||||
	for _, meleeBullet := range currRenderFrame.MeleeBullets {
 | 
			
		||||
		collisionBulletIndex := COLLISION_BULLET_INDEX_PREFIX + meleeBullet.BattleLocalId
 | 
			
		||||
		if bulletCollider, existent := collisionSysMap[collisionBulletIndex]; existent {
 | 
			
		||||
			bulletCollider.Space.Remove(bulletCollider)
 | 
			
		||||
			delete(collisionSysMap, collisionBulletIndex)
 | 
			
		||||
		}
 | 
			
		||||
		if _, existent := removedBulletsAtCurrFrame[collisionBulletIndex]; existent {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		toRet.MeleeBullets = append(toRet.MeleeBullets, meleeBullet)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if nil != delayedInputFrame {
 | 
			
		||||
		inputList := delayedInputFrame.InputList
 | 
			
		||||
		effPushbacks := make([]Vec2D, pR.Capacity) // Guaranteed determinism regardless of traversal order
 | 
			
		||||
		// Process player inputs
 | 
			
		||||
		for playerId, player := range pR.Players {
 | 
			
		||||
			joinIndex := player.JoinIndex
 | 
			
		||||
			effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y = float64(0), float64(0)
 | 
			
		||||
			currPlayerDownsync := currRenderFrame.Players[playerId]
 | 
			
		||||
			decodedInput := pR.decodeInput(inputList[joinIndex-1])
 | 
			
		||||
			proposedVirtualGridDx, proposedVirtualGridDy := (decodedInput.Dx + decodedInput.Dx*currPlayerDownsync.Speed), (decodedInput.Dy + decodedInput.Dy*currPlayerDownsync.Speed)
 | 
			
		||||
			newVx, newVy := (currPlayerDownsync.VirtualGridX + proposedVirtualGridDx), (currPlayerDownsync.VirtualGridY + proposedVirtualGridDy)
 | 
			
		||||
			// Reset playerCollider position from the "virtual grid position"
 | 
			
		||||
			collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
 | 
			
		||||
			playerCollider := collisionSysMap[collisionPlayerIndex]
 | 
			
		||||
			playerCollider.X, playerCollider.Y = VirtualGridToPolygonColliderAnchorPos(newVx, newVy, player.ColliderRadius, player.ColliderRadius, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, pR.VirtualGridToWorldRatio)
 | 
			
		||||
			if 0 < nextRenderFramePlayers[playerId].FramesToRecover {
 | 
			
		||||
				// No need to process inputs for this player, but there might be bullet pushbacks on this player
 | 
			
		||||
				playerCollider.X += bulletPushbacks[joinIndex-1].X
 | 
			
		||||
				playerCollider.Y += bulletPushbacks[joinIndex-1].Y
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			currPlayerDownsync := currRenderFrame.Players[playerId]
 | 
			
		||||
			decodedInput := pR.decodeInput(inputList[joinIndex-1])
 | 
			
		||||
 | 
			
		||||
			if 0 != decodedInput.Dx || 0 != decodedInput.Dy {
 | 
			
		||||
				nextRenderFramePlayers[playerId].DirX = decodedInput.Dx
 | 
			
		||||
				nextRenderFramePlayers[playerId].DirY = decodedInput.Dy
 | 
			
		||||
				nextRenderFramePlayers[playerId].CharacterState = 1
 | 
			
		||||
			} else {
 | 
			
		||||
				nextRenderFramePlayers[playerId].CharacterState = 0
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			movementX, movementY := VirtualGridToWorldPos(decodedInput.Dx+decodedInput.Dx*currPlayerDownsync.Speed, decodedInput.Dy+decodedInput.Dy*currPlayerDownsync.Speed, pR.VirtualGridToWorldRatio)
 | 
			
		||||
			playerCollider.X += movementX
 | 
			
		||||
			playerCollider.Y += movementY
 | 
			
		||||
 | 
			
		||||
			// Update in the collision system
 | 
			
		||||
			playerCollider.Update()
 | 
			
		||||
			if 0 != decodedInput.Dx || 0 != decodedInput.Dy {
 | 
			
		||||
				nextRenderFramePlayers[playerId].Dir.Dx = decodedInput.Dx
 | 
			
		||||
				nextRenderFramePlayers[playerId].Dir.Dy = decodedInput.Dy
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// handle pushbacks upon collision after all movements treated as simultaneous
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
// Code generated by protoc-gen-go. DO NOT EDIT.
 | 
			
		||||
// versions:
 | 
			
		||||
// 	protoc-gen-go v1.28.1
 | 
			
		||||
// 	protoc        v3.7.1
 | 
			
		||||
// 	protoc        v3.21.4
 | 
			
		||||
// source: room_downsync_frame.proto
 | 
			
		||||
 | 
			
		||||
package protos
 | 
			
		||||
@@ -257,24 +257,25 @@ type PlayerDownsync struct {
 | 
			
		||||
	sizeCache     protoimpl.SizeCache
 | 
			
		||||
	unknownFields protoimpl.UnknownFields
 | 
			
		||||
 | 
			
		||||
	Id                int32                   `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
 | 
			
		||||
	VirtualGridX      int32                   `protobuf:"varint,2,opt,name=virtualGridX,proto3" json:"virtualGridX,omitempty"`
 | 
			
		||||
	VirtualGridY      int32                   `protobuf:"varint,3,opt,name=virtualGridY,proto3" json:"virtualGridY,omitempty"`
 | 
			
		||||
	Dir               *sharedprotos.Direction `protobuf:"bytes,4,opt,name=dir,proto3" json:"dir,omitempty"`
 | 
			
		||||
	Speed             int32                   `protobuf:"varint,5,opt,name=speed,proto3" json:"speed,omitempty"` // in terms of virtual grid units
 | 
			
		||||
	BattleState       int32                   `protobuf:"varint,6,opt,name=battleState,proto3" json:"battleState,omitempty"`
 | 
			
		||||
	JoinIndex         int32                   `protobuf:"varint,7,opt,name=joinIndex,proto3" json:"joinIndex,omitempty"`
 | 
			
		||||
	ColliderRadius    float64                 `protobuf:"fixed64,8,opt,name=colliderRadius,proto3" json:"colliderRadius,omitempty"`
 | 
			
		||||
	Removed           bool                    `protobuf:"varint,9,opt,name=removed,proto3" json:"removed,omitempty"`
 | 
			
		||||
	Score             int32                   `protobuf:"varint,10,opt,name=score,proto3" json:"score,omitempty"`
 | 
			
		||||
	LastMoveGmtMillis int32                   `protobuf:"varint,11,opt,name=lastMoveGmtMillis,proto3" json:"lastMoveGmtMillis,omitempty"`
 | 
			
		||||
	FramesToRecover   int32                   `protobuf:"varint,12,opt,name=framesToRecover,proto3" json:"framesToRecover,omitempty"`
 | 
			
		||||
	Hp                int32                   `protobuf:"varint,13,opt,name=hp,proto3" json:"hp,omitempty"`
 | 
			
		||||
	MaxHp             int32                   `protobuf:"varint,14,opt,name=maxHp,proto3" json:"maxHp,omitempty"`
 | 
			
		||||
	CharacterState    int32                   `protobuf:"varint,15,opt,name=characterState,proto3" json:"characterState,omitempty"`
 | 
			
		||||
	Name              string                  `protobuf:"bytes,16,opt,name=name,proto3" json:"name,omitempty"`
 | 
			
		||||
	DisplayName       string                  `protobuf:"bytes,17,opt,name=displayName,proto3" json:"displayName,omitempty"`
 | 
			
		||||
	Avatar            string                  `protobuf:"bytes,18,opt,name=avatar,proto3" json:"avatar,omitempty"`
 | 
			
		||||
	Id                int32   `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
 | 
			
		||||
	VirtualGridX      int32   `protobuf:"varint,2,opt,name=virtualGridX,proto3" json:"virtualGridX,omitempty"`
 | 
			
		||||
	VirtualGridY      int32   `protobuf:"varint,3,opt,name=virtualGridY,proto3" json:"virtualGridY,omitempty"`
 | 
			
		||||
	DirX              int32   `protobuf:"varint,4,opt,name=dirX,proto3" json:"dirX,omitempty"`
 | 
			
		||||
	DirY              int32   `protobuf:"varint,5,opt,name=dirY,proto3" json:"dirY,omitempty"`
 | 
			
		||||
	Speed             int32   `protobuf:"varint,6,opt,name=speed,proto3" json:"speed,omitempty"` // in terms of virtual grid units
 | 
			
		||||
	BattleState       int32   `protobuf:"varint,7,opt,name=battleState,proto3" json:"battleState,omitempty"`
 | 
			
		||||
	JoinIndex         int32   `protobuf:"varint,8,opt,name=joinIndex,proto3" json:"joinIndex,omitempty"`
 | 
			
		||||
	ColliderRadius    float64 `protobuf:"fixed64,9,opt,name=colliderRadius,proto3" json:"colliderRadius,omitempty"`
 | 
			
		||||
	Removed           bool    `protobuf:"varint,10,opt,name=removed,proto3" json:"removed,omitempty"`
 | 
			
		||||
	Score             int32   `protobuf:"varint,11,opt,name=score,proto3" json:"score,omitempty"`
 | 
			
		||||
	LastMoveGmtMillis int32   `protobuf:"varint,12,opt,name=lastMoveGmtMillis,proto3" json:"lastMoveGmtMillis,omitempty"`
 | 
			
		||||
	FramesToRecover   int32   `protobuf:"varint,13,opt,name=framesToRecover,proto3" json:"framesToRecover,omitempty"`
 | 
			
		||||
	Hp                int32   `protobuf:"varint,14,opt,name=hp,proto3" json:"hp,omitempty"`
 | 
			
		||||
	MaxHp             int32   `protobuf:"varint,15,opt,name=maxHp,proto3" json:"maxHp,omitempty"`
 | 
			
		||||
	CharacterState    int32   `protobuf:"varint,16,opt,name=characterState,proto3" json:"characterState,omitempty"`
 | 
			
		||||
	Name              string  `protobuf:"bytes,17,opt,name=name,proto3" json:"name,omitempty"`
 | 
			
		||||
	DisplayName       string  `protobuf:"bytes,18,opt,name=displayName,proto3" json:"displayName,omitempty"`
 | 
			
		||||
	Avatar            string  `protobuf:"bytes,19,opt,name=avatar,proto3" json:"avatar,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *PlayerDownsync) Reset() {
 | 
			
		||||
@@ -330,11 +331,18 @@ func (x *PlayerDownsync) GetVirtualGridY() int32 {
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *PlayerDownsync) GetDir() *sharedprotos.Direction {
 | 
			
		||||
func (x *PlayerDownsync) GetDirX() int32 {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.Dir
 | 
			
		||||
		return x.DirX
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *PlayerDownsync) GetDirY() int32 {
 | 
			
		||||
	if x != nil {
 | 
			
		||||
		return x.DirY
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (x *PlayerDownsync) GetSpeed() int32 {
 | 
			
		||||
@@ -1198,167 +1206,166 @@ var file_room_downsync_frame_proto_rawDesc = []byte{
 | 
			
		||||
	0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x68, 0x61,
 | 
			
		||||
	0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f,
 | 
			
		||||
	0x6e, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
 | 
			
		||||
	0x38, 0x01, 0x22, 0xb5, 0x04, 0x0a, 0x0e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x77,
 | 
			
		||||
	0x38, 0x01, 0x22, 0xb2, 0x04, 0x0a, 0x0e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x77,
 | 
			
		||||
	0x6e, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c,
 | 
			
		||||
	0x47, 0x72, 0x69, 0x64, 0x58, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x76, 0x69, 0x72,
 | 
			
		||||
	0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x58, 0x12, 0x22, 0x0a, 0x0c, 0x76, 0x69, 0x72,
 | 
			
		||||
	0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x12, 0x29, 0x0a,
 | 
			
		||||
	0x03, 0x64, 0x69, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x68, 0x61,
 | 
			
		||||
	0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74,
 | 
			
		||||
	0x69, 0x6f, 0x6e, 0x52, 0x03, 0x64, 0x69, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x65,
 | 
			
		||||
	0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x12, 0x20,
 | 
			
		||||
	0x0a, 0x0b, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x0b, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65,
 | 
			
		||||
	0x12, 0x1c, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x07, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x26,
 | 
			
		||||
	0x0a, 0x0e, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x52, 0x61, 0x64, 0x69, 0x75, 0x73,
 | 
			
		||||
	0x18, 0x08, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0e, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72,
 | 
			
		||||
	0x52, 0x61, 0x64, 0x69, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65,
 | 
			
		||||
	0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64,
 | 
			
		||||
	0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x4d, 0x6f,
 | 
			
		||||
	0x76, 0x65, 0x47, 0x6d, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x05, 0x52, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x65, 0x47, 0x6d, 0x74, 0x4d, 0x69,
 | 
			
		||||
	0x6c, 0x6c, 0x69, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x54, 0x6f,
 | 
			
		||||
	0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x66,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x0e,
 | 
			
		||||
	0x0a, 0x02, 0x68, 0x70, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x68, 0x70, 0x12, 0x14,
 | 
			
		||||
	0x0a, 0x05, 0x6d, 0x61, 0x78, 0x48, 0x70, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6d,
 | 
			
		||||
	0x61, 0x78, 0x48, 0x70, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65,
 | 
			
		||||
	0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x63, 0x68,
 | 
			
		||||
	0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04,
 | 
			
		||||
	0x6e, 0x61, 0x6d, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x12, 0x20, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18,
 | 
			
		||||
	0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61,
 | 
			
		||||
	0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x12, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x22, 0x51, 0x0a, 0x11, 0x49, 0x6e,
 | 
			
		||||
	0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x12,
 | 
			
		||||
	0x0e, 0x0a, 0x02, 0x64, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x78, 0x12,
 | 
			
		||||
	0x0e, 0x0a, 0x02, 0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x79, 0x12,
 | 
			
		||||
	0x1c, 0x0a, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x50, 0x0a,
 | 
			
		||||
	0x10, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e,
 | 
			
		||||
	0x63, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49,
 | 
			
		||||
	0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72,
 | 
			
		||||
	0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64,
 | 
			
		||||
	0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x22,
 | 
			
		||||
	0x7c, 0x0a, 0x12, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77,
 | 
			
		||||
	0x6e, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72,
 | 
			
		||||
	0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70,
 | 
			
		||||
	0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x70,
 | 
			
		||||
	0x75, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6e,
 | 
			
		||||
	0x70, 0x75, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69,
 | 
			
		||||
	0x72, 0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d,
 | 
			
		||||
	0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x3b, 0x0a,
 | 
			
		||||
	0x0f, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63,
 | 
			
		||||
	0x12, 0x28, 0x0a, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
 | 
			
		||||
	0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e,
 | 
			
		||||
	0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xb8, 0x02, 0x0a, 0x05, 0x57,
 | 
			
		||||
	0x73, 0x52, 0x65, 0x71, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x01, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c,
 | 
			
		||||
	0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c,
 | 
			
		||||
	0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x03, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e,
 | 
			
		||||
	0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6a, 0x6f, 0x69,
 | 
			
		||||
	0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67,
 | 
			
		||||
	0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61,
 | 
			
		||||
	0x63, 0x6b, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x12,
 | 
			
		||||
	0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67,
 | 
			
		||||
	0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x4e, 0x0a, 0x15,
 | 
			
		||||
	0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63,
 | 
			
		||||
	0x42, 0x61, 0x74, 0x63, 0x68, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72,
 | 
			
		||||
	0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55,
 | 
			
		||||
	0x70, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x15, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d,
 | 
			
		||||
	0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x27, 0x0a, 0x02,
 | 
			
		||||
	0x68, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
 | 
			
		||||
	0x73, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e,
 | 
			
		||||
	0x63, 0x52, 0x02, 0x68, 0x62, 0x22, 0x89, 0x02, 0x0a, 0x06, 0x57, 0x73, 0x52, 0x65, 0x73, 0x70,
 | 
			
		||||
	0x12, 0x10, 0x0a, 0x03, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x72,
 | 
			
		||||
	0x65, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49,
 | 
			
		||||
	0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d,
 | 
			
		||||
	0x73, 0x67, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
 | 
			
		||||
	0x05, 0x52, 0x03, 0x61, 0x63, 0x74, 0x12, 0x2b, 0x0a, 0x03, 0x72, 0x64, 0x66, 0x18, 0x04, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f,
 | 
			
		||||
	0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x03,
 | 
			
		||||
	0x72, 0x64, 0x66, 0x12, 0x54, 0x0a, 0x17, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d,
 | 
			
		||||
	0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x18, 0x05,
 | 
			
		||||
	0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e,
 | 
			
		||||
	0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63,
 | 
			
		||||
	0x52, 0x17, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e,
 | 
			
		||||
	0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x36, 0x0a, 0x08, 0x62, 0x63, 0x69,
 | 
			
		||||
	0x46, 0x72, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72,
 | 
			
		||||
	0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69,
 | 
			
		||||
	0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61, 0x6d,
 | 
			
		||||
	0x65, 0x22, 0xe5, 0x05, 0x0a, 0x0b, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65,
 | 
			
		||||
	0x74, 0x12, 0x24, 0x0a, 0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
 | 
			
		||||
	0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65,
 | 
			
		||||
	0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74,
 | 
			
		||||
	0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d,
 | 
			
		||||
	0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a,
 | 
			
		||||
	0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x73, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61,
 | 
			
		||||
	0x6d, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x76,
 | 
			
		||||
	0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x72, 0x65, 0x63,
 | 
			
		||||
	0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x42, 0x6c, 0x6f,
 | 
			
		||||
	0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65,
 | 
			
		||||
	0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12,
 | 
			
		||||
	0x30, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x73, 0x4f, 0x6e, 0x48, 0x69, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x72, 0x65,
 | 
			
		||||
	0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x48, 0x69,
 | 
			
		||||
	0x74, 0x12, 0x35, 0x0a, 0x0b, 0x6d, 0x6f, 0x76, 0x65, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64,
 | 
			
		||||
	0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70,
 | 
			
		||||
	0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x56, 0x65, 0x63, 0x32, 0x44, 0x52, 0x0b, 0x6d, 0x6f, 0x76,
 | 
			
		||||
	0x65, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x68, 0x69, 0x74, 0x62,
 | 
			
		||||
	0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c,
 | 
			
		||||
	0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x33, 0x0a, 0x0a,
 | 
			
		||||
	0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b,
 | 
			
		||||
	0x32, 0x13, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
 | 
			
		||||
	0x56, 0x65, 0x63, 0x32, 0x44, 0x52, 0x0a, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a,
 | 
			
		||||
	0x65, 0x12, 0x38, 0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52,
 | 
			
		||||
	0x65, 0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x0a, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65,
 | 
			
		||||
	0x6e, 0x64, 0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x68,
 | 
			
		||||
	0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x05, 0x52, 0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x73, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72,
 | 
			
		||||
	0x61, 0x6d, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63,
 | 
			
		||||
	0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70,
 | 
			
		||||
	0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x70,
 | 
			
		||||
	0x75, 0x73, 0x68, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x6c, 0x65, 0x61,
 | 
			
		||||
	0x73, 0x65, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0e, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x05, 0x52, 0x12, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x54, 0x72, 0x69, 0x67,
 | 
			
		||||
	0x67, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67,
 | 
			
		||||
	0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x12,
 | 
			
		||||
	0x2c, 0x0a, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49,
 | 
			
		||||
	0x6e, 0x64, 0x65, 0x78, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x66, 0x65,
 | 
			
		||||
	0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2a, 0x0a,
 | 
			
		||||
	0x10, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49,
 | 
			
		||||
	0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65,
 | 
			
		||||
	0x72, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x22, 0x9a, 0x02, 0x0a, 0x11, 0x52, 0x6f,
 | 
			
		||||
	0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12,
 | 
			
		||||
	0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12,
 | 
			
		||||
	0x40, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
 | 
			
		||||
	0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f,
 | 
			
		||||
	0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x2e, 0x50, 0x6c, 0x61, 0x79,
 | 
			
		||||
	0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72,
 | 
			
		||||
	0x73, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61,
 | 
			
		||||
	0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74,
 | 
			
		||||
	0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c,
 | 
			
		||||
	0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
 | 
			
		||||
	0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75,
 | 
			
		||||
	0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65,
 | 
			
		||||
	0x74, 0x73, 0x1a, 0x52, 0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74,
 | 
			
		||||
	0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6c, 0x61,
 | 
			
		||||
	0x79, 0x65, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x05, 0x76, 0x61, 0x6c,
 | 
			
		||||
	0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x13, 0x5a, 0x11, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65,
 | 
			
		||||
	0x5f, 0x73, 0x72, 0x76, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f,
 | 
			
		||||
	0x74, 0x6f, 0x33,
 | 
			
		||||
	0x0c, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x47, 0x72, 0x69, 0x64, 0x59, 0x12, 0x12, 0x0a,
 | 
			
		||||
	0x04, 0x64, 0x69, 0x72, 0x58, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x69, 0x72,
 | 
			
		||||
	0x58, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x69, 0x72, 0x59, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x04, 0x64, 0x69, 0x72, 0x59, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0x06,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x62,
 | 
			
		||||
	0x61, 0x74, 0x74, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x0b, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a,
 | 
			
		||||
	0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x26, 0x0a, 0x0e, 0x63,
 | 
			
		||||
	0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x52, 0x61, 0x64, 0x69, 0x75, 0x73, 0x18, 0x09, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x01, 0x52, 0x0e, 0x63, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x52, 0x61, 0x64,
 | 
			
		||||
	0x69, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x0a,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x12, 0x14, 0x0a,
 | 
			
		||||
	0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x63,
 | 
			
		||||
	0x6f, 0x72, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x6c, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x65, 0x47,
 | 
			
		||||
	0x6d, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11,
 | 
			
		||||
	0x6c, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x76, 0x65, 0x47, 0x6d, 0x74, 0x4d, 0x69, 0x6c, 0x6c, 0x69,
 | 
			
		||||
	0x73, 0x12, 0x28, 0x0a, 0x0f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x63,
 | 
			
		||||
	0x6f, 0x76, 0x65, 0x72, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x66, 0x72, 0x61, 0x6d,
 | 
			
		||||
	0x65, 0x73, 0x54, 0x6f, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x68,
 | 
			
		||||
	0x70, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x68, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x6d,
 | 
			
		||||
	0x61, 0x78, 0x48, 0x70, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6d, 0x61, 0x78, 0x48,
 | 
			
		||||
	0x70, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x53, 0x74,
 | 
			
		||||
	0x61, 0x74, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x63, 0x68, 0x61, 0x72, 0x61,
 | 
			
		||||
	0x63, 0x74, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
 | 
			
		||||
	0x65, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a,
 | 
			
		||||
	0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x12, 0x20, 0x01,
 | 
			
		||||
	0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12,
 | 
			
		||||
	0x16, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52,
 | 
			
		||||
	0x06, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x22, 0x51, 0x0a, 0x11, 0x49, 0x6e, 0x70, 0x75, 0x74,
 | 
			
		||||
	0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x65, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02,
 | 
			
		||||
	0x64, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x78, 0x12, 0x0e, 0x0a, 0x02,
 | 
			
		||||
	0x64, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x79, 0x12, 0x1c, 0x0a, 0x09,
 | 
			
		||||
	0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x09, 0x62, 0x74, 0x6e, 0x41, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x50, 0x0a, 0x10, 0x49, 0x6e,
 | 
			
		||||
	0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x22,
 | 
			
		||||
	0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x01,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x18, 0x02, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x04, 0x52, 0x07, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x22, 0x7c, 0x0a, 0x12,
 | 
			
		||||
	0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79,
 | 
			
		||||
	0x6e, 0x63, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x4c,
 | 
			
		||||
	0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74,
 | 
			
		||||
	0x4c, 0x69, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65,
 | 
			
		||||
	0x64, 0x4c, 0x69, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x63, 0x6f, 0x6e,
 | 
			
		||||
	0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x0f, 0x48, 0x65,
 | 
			
		||||
	0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x12, 0x28, 0x0a,
 | 
			
		||||
	0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
 | 
			
		||||
	0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x54, 0x69,
 | 
			
		||||
	0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xb8, 0x02, 0x0a, 0x05, 0x57, 0x73, 0x52, 0x65,
 | 
			
		||||
	0x71, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x05, 0x6d, 0x73, 0x67, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65,
 | 
			
		||||
	0x72, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65,
 | 
			
		||||
	0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x03, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64,
 | 
			
		||||
	0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6a, 0x6f, 0x69, 0x6e, 0x49, 0x6e,
 | 
			
		||||
	0x64, 0x65, 0x78, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x46, 0x72, 0x61,
 | 
			
		||||
	0x6d, 0x65, 0x49, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x63, 0x6b, 0x69,
 | 
			
		||||
	0x6e, 0x67, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x2e, 0x0a, 0x12, 0x61, 0x63, 0x6b,
 | 
			
		||||
	0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18,
 | 
			
		||||
	0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x12, 0x61, 0x63, 0x6b, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x70,
 | 
			
		||||
	0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x4e, 0x0a, 0x15, 0x69, 0x6e, 0x70,
 | 
			
		||||
	0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74,
 | 
			
		||||
	0x63, 0x68, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
 | 
			
		||||
	0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70, 0x73, 0x79,
 | 
			
		||||
	0x6e, 0x63, 0x52, 0x15, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x55, 0x70,
 | 
			
		||||
	0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x27, 0x0a, 0x02, 0x68, 0x62, 0x18,
 | 
			
		||||
	0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x48,
 | 
			
		||||
	0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x55, 0x70, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x02,
 | 
			
		||||
	0x68, 0x62, 0x22, 0x89, 0x02, 0x0a, 0x06, 0x57, 0x73, 0x52, 0x65, 0x73, 0x70, 0x12, 0x10, 0x0a,
 | 
			
		||||
	0x03, 0x72, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x72, 0x65, 0x74, 0x12,
 | 
			
		||||
	0x20, 0x0a, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49, 0x64, 0x18, 0x02,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x65, 0x63, 0x68, 0x6f, 0x65, 0x64, 0x4d, 0x73, 0x67, 0x49,
 | 
			
		||||
	0x64, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03,
 | 
			
		||||
	0x61, 0x63, 0x74, 0x12, 0x2b, 0x0a, 0x03, 0x72, 0x64, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
 | 
			
		||||
	0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f,
 | 
			
		||||
	0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x52, 0x03, 0x72, 0x64, 0x66,
 | 
			
		||||
	0x12, 0x54, 0x0a, 0x17, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f,
 | 
			
		||||
	0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x18, 0x05, 0x20, 0x03, 0x28,
 | 
			
		||||
	0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74,
 | 
			
		||||
	0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x17, 0x69,
 | 
			
		||||
	0x6e, 0x70, 0x75, 0x74, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e,
 | 
			
		||||
	0x63, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x36, 0x0a, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61,
 | 
			
		||||
	0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
 | 
			
		||||
	0x73, 0x2e, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72,
 | 
			
		||||
	0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x62, 0x63, 0x69, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x22, 0xe5,
 | 
			
		||||
	0x05, 0x0a, 0x0b, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x12, 0x24,
 | 
			
		||||
	0x0a, 0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x18,
 | 
			
		||||
	0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x4c, 0x6f, 0x63,
 | 
			
		||||
	0x61, 0x6c, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x46,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x74, 0x61,
 | 
			
		||||
	0x72, 0x74, 0x75, 0x70, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63,
 | 
			
		||||
	0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x0c, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x26,
 | 
			
		||||
	0x0a, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73,
 | 
			
		||||
	0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79,
 | 
			
		||||
	0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x34, 0x0a, 0x15, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65,
 | 
			
		||||
	0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x18,
 | 
			
		||||
	0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x15, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46,
 | 
			
		||||
	0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x30, 0x0a, 0x13,
 | 
			
		||||
	0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e,
 | 
			
		||||
	0x48, 0x69, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x13, 0x72, 0x65, 0x63, 0x6f, 0x76,
 | 
			
		||||
	0x65, 0x72, 0x79, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x4f, 0x6e, 0x48, 0x69, 0x74, 0x12, 0x35,
 | 
			
		||||
	0x0a, 0x0b, 0x6d, 0x6f, 0x76, 0x65, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x07, 0x20,
 | 
			
		||||
	0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74,
 | 
			
		||||
	0x6f, 0x73, 0x2e, 0x56, 0x65, 0x63, 0x32, 0x44, 0x52, 0x0b, 0x6d, 0x6f, 0x76, 0x65, 0x66, 0x6f,
 | 
			
		||||
	0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x4f,
 | 
			
		||||
	0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0c, 0x68, 0x69, 0x74,
 | 
			
		||||
	0x62, 0x6f, 0x78, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x33, 0x0a, 0x0a, 0x68, 0x69, 0x74,
 | 
			
		||||
	0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e,
 | 
			
		||||
	0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x56, 0x65, 0x63,
 | 
			
		||||
	0x32, 0x44, 0x52, 0x0a, 0x68, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x38,
 | 
			
		||||
	0x0a, 0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64,
 | 
			
		||||
	0x65, 0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x17, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x64, 0x52, 0x65, 0x6e, 0x64, 0x65,
 | 
			
		||||
	0x72, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x69, 0x74, 0x53,
 | 
			
		||||
	0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52,
 | 
			
		||||
	0x0d, 0x68, 0x69, 0x74, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x28,
 | 
			
		||||
	0x0a, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74, 0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65,
 | 
			
		||||
	0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x53, 0x74,
 | 
			
		||||
	0x75, 0x6e, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x75, 0x73, 0x68,
 | 
			
		||||
	0x62, 0x61, 0x63, 0x6b, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x70, 0x75, 0x73, 0x68,
 | 
			
		||||
	0x62, 0x61, 0x63, 0x6b, 0x12, 0x2e, 0x0a, 0x12, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x54,
 | 
			
		||||
	0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x05,
 | 
			
		||||
	0x52, 0x12, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72,
 | 
			
		||||
	0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x0f,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x64, 0x61, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x11,
 | 
			
		||||
	0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65,
 | 
			
		||||
	0x78, 0x18, 0x10, 0x20, 0x01, 0x28, 0x05, 0x52, 0x11, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65,
 | 
			
		||||
	0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2a, 0x0a, 0x10, 0x6f, 0x66,
 | 
			
		||||
	0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x18, 0x11,
 | 
			
		||||
	0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x6c,
 | 
			
		||||
	0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x22, 0x9a, 0x02, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x44,
 | 
			
		||||
	0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02,
 | 
			
		||||
	0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x40, 0x0a, 0x07,
 | 
			
		||||
	0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e,
 | 
			
		||||
	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73,
 | 
			
		||||
	0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73,
 | 
			
		||||
	0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, 0x26,
 | 
			
		||||
	0x0a, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73,
 | 
			
		||||
	0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77,
 | 
			
		||||
	0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42,
 | 
			
		||||
	0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70,
 | 
			
		||||
	0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65,
 | 
			
		||||
	0x74, 0x52, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x1a,
 | 
			
		||||
	0x52, 0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
 | 
			
		||||
	0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65,
 | 
			
		||||
	0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
 | 
			
		||||
	0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72,
 | 
			
		||||
	0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
 | 
			
		||||
	0x02, 0x38, 0x01, 0x42, 0x13, 0x5a, 0x11, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x73, 0x72,
 | 
			
		||||
	0x76, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@@ -1388,32 +1395,30 @@ var file_room_downsync_frame_proto_goTypes = []interface{}{
 | 
			
		||||
	nil,                                // 10: protos.BattleColliderInfo.StrToVec2DListMapEntry
 | 
			
		||||
	nil,                                // 11: protos.BattleColliderInfo.StrToPolygon2DListMapEntry
 | 
			
		||||
	nil,                                // 12: protos.RoomDownsyncFrame.PlayersEntry
 | 
			
		||||
	(*sharedprotos.Direction)(nil),     // 13: sharedprotos.Direction
 | 
			
		||||
	(*sharedprotos.Vec2D)(nil),         // 14: sharedprotos.Vec2D
 | 
			
		||||
	(*sharedprotos.Vec2DList)(nil),     // 15: sharedprotos.Vec2DList
 | 
			
		||||
	(*sharedprotos.Polygon2DList)(nil), // 16: sharedprotos.Polygon2DList
 | 
			
		||||
	(*sharedprotos.Vec2D)(nil),         // 13: sharedprotos.Vec2D
 | 
			
		||||
	(*sharedprotos.Vec2DList)(nil),     // 14: sharedprotos.Vec2DList
 | 
			
		||||
	(*sharedprotos.Polygon2DList)(nil), // 15: sharedprotos.Polygon2DList
 | 
			
		||||
}
 | 
			
		||||
var file_room_downsync_frame_proto_depIdxs = []int32{
 | 
			
		||||
	10, // 0: protos.BattleColliderInfo.strToVec2DListMap:type_name -> protos.BattleColliderInfo.StrToVec2DListMapEntry
 | 
			
		||||
	11, // 1: protos.BattleColliderInfo.strToPolygon2DListMap:type_name -> protos.BattleColliderInfo.StrToPolygon2DListMapEntry
 | 
			
		||||
	13, // 2: protos.PlayerDownsync.dir:type_name -> sharedprotos.Direction
 | 
			
		||||
	3,  // 3: protos.WsReq.inputFrameUpsyncBatch:type_name -> protos.InputFrameUpsync
 | 
			
		||||
	5,  // 4: protos.WsReq.hb:type_name -> protos.HeartbeatUpsync
 | 
			
		||||
	9,  // 5: protos.WsResp.rdf:type_name -> protos.RoomDownsyncFrame
 | 
			
		||||
	4,  // 6: protos.WsResp.inputFrameDownsyncBatch:type_name -> protos.InputFrameDownsync
 | 
			
		||||
	0,  // 7: protos.WsResp.bciFrame:type_name -> protos.BattleColliderInfo
 | 
			
		||||
	14, // 8: protos.MeleeBullet.moveforward:type_name -> sharedprotos.Vec2D
 | 
			
		||||
	14, // 9: protos.MeleeBullet.hitboxSize:type_name -> sharedprotos.Vec2D
 | 
			
		||||
	12, // 10: protos.RoomDownsyncFrame.players:type_name -> protos.RoomDownsyncFrame.PlayersEntry
 | 
			
		||||
	8,  // 11: protos.RoomDownsyncFrame.meleeBullets:type_name -> protos.MeleeBullet
 | 
			
		||||
	15, // 12: protos.BattleColliderInfo.StrToVec2DListMapEntry.value:type_name -> sharedprotos.Vec2DList
 | 
			
		||||
	16, // 13: protos.BattleColliderInfo.StrToPolygon2DListMapEntry.value:type_name -> sharedprotos.Polygon2DList
 | 
			
		||||
	1,  // 14: protos.RoomDownsyncFrame.PlayersEntry.value:type_name -> protos.PlayerDownsync
 | 
			
		||||
	15, // [15:15] is the sub-list for method output_type
 | 
			
		||||
	15, // [15:15] is the sub-list for method input_type
 | 
			
		||||
	15, // [15:15] is the sub-list for extension type_name
 | 
			
		||||
	15, // [15:15] is the sub-list for extension extendee
 | 
			
		||||
	0,  // [0:15] is the sub-list for field type_name
 | 
			
		||||
	3,  // 2: protos.WsReq.inputFrameUpsyncBatch:type_name -> protos.InputFrameUpsync
 | 
			
		||||
	5,  // 3: protos.WsReq.hb:type_name -> protos.HeartbeatUpsync
 | 
			
		||||
	9,  // 4: protos.WsResp.rdf:type_name -> protos.RoomDownsyncFrame
 | 
			
		||||
	4,  // 5: protos.WsResp.inputFrameDownsyncBatch:type_name -> protos.InputFrameDownsync
 | 
			
		||||
	0,  // 6: protos.WsResp.bciFrame:type_name -> protos.BattleColliderInfo
 | 
			
		||||
	13, // 7: protos.MeleeBullet.moveforward:type_name -> sharedprotos.Vec2D
 | 
			
		||||
	13, // 8: protos.MeleeBullet.hitboxSize:type_name -> sharedprotos.Vec2D
 | 
			
		||||
	12, // 9: protos.RoomDownsyncFrame.players:type_name -> protos.RoomDownsyncFrame.PlayersEntry
 | 
			
		||||
	8,  // 10: protos.RoomDownsyncFrame.meleeBullets:type_name -> protos.MeleeBullet
 | 
			
		||||
	14, // 11: protos.BattleColliderInfo.StrToVec2DListMapEntry.value:type_name -> sharedprotos.Vec2DList
 | 
			
		||||
	15, // 12: protos.BattleColliderInfo.StrToPolygon2DListMapEntry.value:type_name -> sharedprotos.Polygon2DList
 | 
			
		||||
	1,  // 13: protos.RoomDownsyncFrame.PlayersEntry.value:type_name -> protos.PlayerDownsync
 | 
			
		||||
	14, // [14:14] is the sub-list for method output_type
 | 
			
		||||
	14, // [14:14] is the sub-list for method input_type
 | 
			
		||||
	14, // [14:14] is the sub-list for extension type_name
 | 
			
		||||
	14, // [14:14] is the sub-list for extension extendee
 | 
			
		||||
	0,  // [0:14] is the sub-list for field type_name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() { file_room_downsync_frame_proto_init() }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
// Code generated by protoc-gen-go. DO NOT EDIT.
 | 
			
		||||
// versions:
 | 
			
		||||
// 	protoc-gen-go v1.28.1
 | 
			
		||||
// 	protoc        v3.7.1
 | 
			
		||||
// 	protoc        v3.21.4
 | 
			
		||||
// source: geometry.proto
 | 
			
		||||
 | 
			
		||||
package sharedprotos
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,18 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="64" height="64" tilewidth="16" tileheight="16" infinite="0" nextlayerid="2" nextobjectid="12">
 | 
			
		||||
<map version="1.2" tiledversion="1.2.3" orientation="orthogonal" renderorder="right-down" width="128" height="128" tilewidth="16" tileheight="16" infinite="0" nextlayerid="3" nextobjectid="39">
 | 
			
		||||
 <tileset firstgid="1" source="tiles0.tsx"/>
 | 
			
		||||
 <tileset firstgid="65" source="tiles1.tsx"/>
 | 
			
		||||
 <layer id="1" name="Ground" width="64" height="64">
 | 
			
		||||
 <tileset firstgid="129" source="tiles2.tsx"/>
 | 
			
		||||
 <layer id="2" name="Ground" width="128" height="128">
 | 
			
		||||
  <data encoding="base64" compression="zlib">
 | 
			
		||||
   eJzt0jEOwjAUREGLkiLmALRU3In7HwMKkFCUCCwiNrKnmCbVvh8fSikHAAAA/qruYEOr84Zd+vM9re0v+vXr1z9S/7f0l3KZ9dXZ91r67QeAXxyf0jv0Z/tvO9iS7F+T3ucG+Xuk96RvkN4CMJLaIL0VttLy7r19euHdA+zX6YP0vlR3z/3ax2tfarw+TAO0L/VPb3ruXvv3o7z7lv70zuQN0vtgz+6DDSsZ
 | 
			
		||||
   eJzt2q1u22AYhuEo1UhBtYFWKh/bmRRMRYNFPZPxwcKi7jznSInkWk7teG5ex88FLhQD570d5/PP1WazuQIAAAAAAAAAAAAAAAAAgAmu96r3g/N5bjn0fw5U3aGy/3bv0P+p8XDEdoX0f9//GP3Xp93/YaD/9QJa6f95/fvov26773671zeb7jmhupX+5+2fQH/9qztU9v8yQXUz/fXXX3/9a/ovgf7666+//vrrf1n9/4zc7tue/uvq/9Z4PfLZ7vnz38ZP/cv7T53p4Z7i7/+kv/7667/bl/sO/dff/77T3+9ff/3r+38dMGf/Nv1r+w917+v/0vh1okN/67/l9B/b/nFj/X8pxvYf236r/0UZ6t/X+Efj5kj7bv+uxxPpX9e/r/1NS7f7Z/S/a3zXfzH9Pzrvt/vPTf/l9p+yRjyV/ufvP+YY6M5yzr5D5uy/XUCLJfafa8YfmdJe//X0r6Z/9jGgv/7661/doqp/9fyrpV//Vc+/mv7Z9M+mfzb9s+mfTf9s+mfTP5v+2fTPpn82/bPpn03/bPpn0z+b/tn0z6Z/Nv2z6Z/N+9/Z9M+mfzb//9n0z6Z/Nv2z6Z9N/2z6Z9M/m/7Z0vtT3wEAAAAAAAAAAAAAAAA4v39IY4NC
 | 
			
		||||
  </data>
 | 
			
		||||
 </layer>
 | 
			
		||||
 <objectgroup id="1" name="PlayerStartingPos">
 | 
			
		||||
  <object id="135" x="512" y="512">
 | 
			
		||||
  <object id="135" x="1090" y="833.667">
 | 
			
		||||
   <point/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="137" x="640" y="640">
 | 
			
		||||
  <object id="137" x="1215" y="830.5">
 | 
			
		||||
   <point/>
 | 
			
		||||
  </object>
 | 
			
		||||
 </objectgroup>
 | 
			
		||||
@@ -19,71 +20,149 @@
 | 
			
		||||
  <properties>
 | 
			
		||||
   <property name="type" value="barrier_and_shelter"/>
 | 
			
		||||
  </properties>
 | 
			
		||||
  <object id="1" x="400" y="224.5">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 0,141.5 17,141.5 17,-1"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="2" x="559.5" y="207.5">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 1,158.5 17,158.5 17,0"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="3" x="448.5" y="353">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 0,14.5 -49,14.5 -49,-1.5"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="4" x="577.5" y="351.5">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -98,1 -98,16 -1,15.5"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="5" x="449.333" y="654.667">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -178.667,0.666667 -178.667,17.3333 -0.666667,17.3333"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="6" x="432.5" y="703.5">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -191.667,0.666667 -191.667,17.3333 -0.715174,17.3333"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="7" x="400" y="751">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -191.667,0.666667 -191.667,17.3333 -0.715174,17.3333"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="8" x="-9.33333" y="-13.3333">
 | 
			
		||||
  <object id="8" x="648.242" y="480.606">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 0,18.6667 1041.33,21.3333 1041.33,-1.33333"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="9" x="-9.33333" y="1014.67">
 | 
			
		||||
  <object id="9" x="650.667" y="1604.67">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 0,18.6667 1041.33,21.3333 1041.33,-1.33333"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="10" x="-14" y="-40">
 | 
			
		||||
  <object id="10" x="634.485" y="505.455">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 4,1110 24,1110 24,-8"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="11" x="1014" y="-42">
 | 
			
		||||
  <object id="11" x="1677.64" y="501.333">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 4,1110 24,1110 24,-8"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="14" x="688.667" y="464">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -0.666667,78 33.3333,78 32,-0.666667"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="15" x="833.333" y="495.333">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -112,1.33333 -111.333,44.6667 -1.33333,44.6667"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="17" x="832" y="574">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -67.3333,0 -67.3333,-76.6667 0.666667,-76"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="18" x="865.333" y="606.667">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -210,-0.666667 -210,143.333 0,142.667"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="19" x="754.667" y="1055.33">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="-2,1.33333 -100,0.666667 -97.3333,-454 -9.33333,-451.333"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="20" x="769.333" y="747.333">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -115.333,0.666667 -114.667,160.667 -2,162"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="21" x="768" y="960.667">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -18,0.666667 -18.6667,95.3333 0,95.3333"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="23" x="786" y="1058.67">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 0,-52.6667 -20,-52 -19.3333,-1.33333"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="24" x="1118.67" y="749.333">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -0.666667,-94 -254,-93.3333 -256.667,1.33333"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="25" x="1168" y="975.333">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 0,16.6667 224.667,17.3333 225.333,-2"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="28" x="1394.67" y="958">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -210.667,1.33333 -210.667,17.3333 -2,18"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="29" x="1119" y="654.5">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 0,63.5 272.5,65 273,-1"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="30" x="1136.5" y="717.5">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -0.5,17 255,17.5 255,1.5"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="31" x="1152" y="735.667">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 0,15 80.3333,15.3333 80.3333,-2"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="32" x="1280.67" y="734.667">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -0.666667,64.3333 48,65 48,0"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="34" x="1329" y="783">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 63.3333,0.333333 63,-48.3333 -0.666667,-48.3333"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="35" x="1296.67" y="799">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -0.666667,31.3333 31.3333,31.6667 31.3333,-0.333333"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="36" x="1280" y="848">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 0.333333,62 112,63 111.667,-1.33333"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="37" x="1392.33" y="911.333">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 -81.3333,-0.666667 -81,45 -0.666667,46.3333"/>
 | 
			
		||||
  </object>
 | 
			
		||||
  <object id="38" x="1344.33" y="800.667">
 | 
			
		||||
   <properties>
 | 
			
		||||
    <property name="boundary_type" value="barrier"/>
 | 
			
		||||
   </properties>
 | 
			
		||||
   <polyline points="0,0 0,46.3333 47,46.3333 47,-1"/>
 | 
			
		||||
  </object>
 | 
			
		||||
 </objectgroup>
 | 
			
		||||
</map>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								frontend/assets/resources/map/dungeon/tiles2.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								frontend/assets/resources/map/dungeon/tiles2.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<tileset version="1.2" tiledversion="1.2.3" name="tiles2" tilewidth="16" tileheight="16" tilecount="64" columns="16">
 | 
			
		||||
 <image source="watabou_pixel_dungeon_orig_files/tiles2.png" width="256" height="64"/>
 | 
			
		||||
</tileset>
 | 
			
		||||
							
								
								
									
										5
									
								
								frontend/assets/resources/map/dungeon/tiles2.tsx.meta
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								frontend/assets/resources/map/dungeon/tiles2.tsx.meta
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
  "ver": "2.0.0",
 | 
			
		||||
  "uuid": "2e53500f-f9c8-4b5b-b74c-f2adbc2ec34d",
 | 
			
		||||
  "subMetas": {}
 | 
			
		||||
}
 | 
			
		||||
@@ -38,22 +38,23 @@ message PlayerDownsync {
 | 
			
		||||
  int32 id = 1;
 | 
			
		||||
  int32 virtualGridX = 2; 
 | 
			
		||||
  int32 virtualGridY = 3; 
 | 
			
		||||
  sharedprotos.Direction dir = 4;
 | 
			
		||||
  int32 speed = 5; // in terms of virtual grid units
 | 
			
		||||
  int32 battleState = 6;
 | 
			
		||||
  int32 joinIndex = 7;
 | 
			
		||||
  double colliderRadius = 8;
 | 
			
		||||
  bool removed = 9;
 | 
			
		||||
  int32 score = 10;
 | 
			
		||||
  int32 lastMoveGmtMillis = 11;
 | 
			
		||||
  int32 framesToRecover = 12;
 | 
			
		||||
  int32 hp = 13;
 | 
			
		||||
  int32 maxHp = 14;
 | 
			
		||||
  int32 characterState = 15;
 | 
			
		||||
  int32 dirX = 4;
 | 
			
		||||
  int32 dirY = 5;
 | 
			
		||||
  int32 speed = 6; // in terms of virtual grid units
 | 
			
		||||
  int32 battleState = 7;
 | 
			
		||||
  int32 joinIndex = 8;
 | 
			
		||||
  double colliderRadius = 9;
 | 
			
		||||
  bool removed = 10;
 | 
			
		||||
  int32 score = 11;
 | 
			
		||||
  int32 lastMoveGmtMillis = 12;
 | 
			
		||||
  int32 framesToRecover = 13;
 | 
			
		||||
  int32 hp = 14;
 | 
			
		||||
  int32 maxHp = 15;
 | 
			
		||||
  int32 characterState = 16;
 | 
			
		||||
 | 
			
		||||
  string name = 16;
 | 
			
		||||
  string displayName = 17;
 | 
			
		||||
  string avatar = 18;
 | 
			
		||||
  string name = 17;
 | 
			
		||||
  string displayName = 18;
 | 
			
		||||
  string avatar = 19;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message InputFrameDecoded {
 | 
			
		||||
@@ -123,8 +124,6 @@ message MeleeBullet {
 | 
			
		||||
 | 
			
		||||
  int32 offenderJoinIndex = 16;    
 | 
			
		||||
  int32 offenderPlayerId = 17;    
 | 
			
		||||
 | 
			
		||||
  int32 offenderPlayerId = 17;    
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
message RoomDownsyncFrame {
 | 
			
		||||
 
 | 
			
		||||
@@ -277,6 +277,7 @@
 | 
			
		||||
    "forceBigEndianFloatingNumDecoding": false,
 | 
			
		||||
    "renderFrameIdLagTolerance": 4,
 | 
			
		||||
    "jigglingEps1D": 0.001,
 | 
			
		||||
    "bulletTriggerEnabled": true,
 | 
			
		||||
    "_id": "4b+kZ46VhC0LCBixXEK2dk"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
 
 | 
			
		||||
@@ -95,6 +95,9 @@ cc.Class({
 | 
			
		||||
      type: cc.Float,
 | 
			
		||||
      default: 1e-3
 | 
			
		||||
    },
 | 
			
		||||
    bulletTriggerEnabled: {
 | 
			
		||||
      default: false
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  _inputFrameIdDebuggable(inputFrameId) {
 | 
			
		||||
@@ -321,10 +324,10 @@ cc.Class({
 | 
			
		||||
 | 
			
		||||
    self.battleState = ALL_BATTLE_STATES.WAITING;
 | 
			
		||||
 | 
			
		||||
    self.countdownNanos = null;
 | 
			
		||||
    if (self.countdownLabel) {
 | 
			
		||||
      self.countdownLabel.string = "";
 | 
			
		||||
    }
 | 
			
		||||
    self.countdownNanos = null;
 | 
			
		||||
    if (self.findingPlayerNode) {
 | 
			
		||||
      const findingPlayerScriptIns = self.findingPlayerNode.getComponent("FindingPlayer");
 | 
			
		||||
      findingPlayerScriptIns.init();
 | 
			
		||||
@@ -741,17 +744,15 @@ cc.Class({
 | 
			
		||||
    self.playersInfoNode.getComponent("PlayersInfo").clearInfo();
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  spawnPlayerNode(joinIndex, vx, vy, playerRichInfo) {
 | 
			
		||||
  spawnPlayerNode(joinIndex, vx, vy, playerDownsyncInfo) {
 | 
			
		||||
    const self = this;
 | 
			
		||||
    const newPlayerNode = cc.instantiate(self.controlledCharacterPrefab)
 | 
			
		||||
    const playerScriptIns = newPlayerNode.getComponent("ControlledCharacter");
 | 
			
		||||
    playerScriptIns.joinIndex = joinIndex;
 | 
			
		||||
 | 
			
		||||
    if (1 == joinIndex) {
 | 
			
		||||
      playerScriptIns.setSpecies("SoldierWaterGhost");
 | 
			
		||||
    } else if (2 == joinIndex) {
 | 
			
		||||
      playerScriptIns.setSpecies("SoldierFireGhost");
 | 
			
		||||
      if (0 == playerRichInfo.dir.dx && 0 == playerRichInfo.dir.dy) {
 | 
			
		||||
      if (0 == playerDownsyncInfo.dirX && 0 == playerDownsyncInfo.dirY) {
 | 
			
		||||
        playerScriptIns.animComp.node.scaleX = (-1.0);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@@ -760,16 +761,15 @@ cc.Class({
 | 
			
		||||
 | 
			
		||||
    newPlayerNode.setPosition(cc.v2(wpos[0], wpos[1]));
 | 
			
		||||
    playerScriptIns.mapNode = self.node;
 | 
			
		||||
    const cpos = self.virtualGridToPlayerColliderPos(vx, vy, playerRichInfo);
 | 
			
		||||
    const d = playerRichInfo.colliderRadius * 2,
 | 
			
		||||
    const cpos = self.virtualGridToPlayerColliderPos(vx, vy, playerDownsyncInfo);
 | 
			
		||||
    const d = playerDownsyncInfo.colliderRadius * 2,
 | 
			
		||||
      x0 = cpos[0],
 | 
			
		||||
      y0 = cpos[1];
 | 
			
		||||
    let pts = [[0, 0], [d, 0], [d, d], [0, d]];
 | 
			
		||||
 | 
			
		||||
    const newPlayerCollider = self.collisionSys.createPolygon(x0, y0, pts);
 | 
			
		||||
    const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex;
 | 
			
		||||
    newPlayerCollider.collisionPlayerIndex = parseInt(collisionPlayerIndex);
 | 
			
		||||
    newPlayerCollider.playerId = parseInt(playerRichInfo.id);
 | 
			
		||||
    newPlayerCollider.data = playerDownsyncInfo;
 | 
			
		||||
    self.collisionSysMap.set(collisionPlayerIndex, newPlayerCollider);
 | 
			
		||||
 | 
			
		||||
    safelyAddChild(self.node, newPlayerNode);
 | 
			
		||||
@@ -777,9 +777,9 @@ cc.Class({
 | 
			
		||||
 | 
			
		||||
    newPlayerNode.active = true;
 | 
			
		||||
    playerScriptIns.updateCharacterAnim({
 | 
			
		||||
      dx: playerRichInfo.dir.dx,
 | 
			
		||||
      dy: playerRichInfo.dir.dy
 | 
			
		||||
    }, playerRichInfo, true);
 | 
			
		||||
      dx: playerDownsyncInfo.dirX,
 | 
			
		||||
      dy: playerDownsyncInfo.dirY,
 | 
			
		||||
    }, playerDownsyncInfo, true);
 | 
			
		||||
 | 
			
		||||
    return [newPlayerNode, playerScriptIns];
 | 
			
		||||
  },
 | 
			
		||||
@@ -973,8 +973,6 @@ cc.Class({
 | 
			
		||||
      const dy = (wpos[1] - playerRichInfo.node.y);
 | 
			
		||||
      //const justJiggling = (self.jigglingEps1D >= Math.abs(dx) && self.jigglingEps1D >= Math.abs(dy));
 | 
			
		||||
      playerRichInfo.node.setPosition(wpos[0], wpos[1]);
 | 
			
		||||
      playerRichInfo.virtualGridX = immediatePlayerInfo.virtualGridX;
 | 
			
		||||
      playerRichInfo.virtualGridY = immediatePlayerInfo.virtualGridY;
 | 
			
		||||
      // TODO: check "rdf.players[playerId].characterState" instead, might have to play Atk/Atked anim!
 | 
			
		||||
      if (null != delayedInputFrameForPrevRenderFrame) {
 | 
			
		||||
        const decodedInput = self.ctrl.decodeInput(delayedInputFrameForPrevRenderFrame.inputList[playerRichInfo.joinIndex - 1]);
 | 
			
		||||
@@ -1003,17 +1001,15 @@ cc.Class({
 | 
			
		||||
  // TODO: Write unit-test for this function to compare with its backend counter part
 | 
			
		||||
  applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, currRenderFrame, collisionSys, collisionSysMap) {
 | 
			
		||||
    const self = this;
 | 
			
		||||
    const nextRenderFramePlayers = {}
 | 
			
		||||
    const nextRenderFramePlayers = {};
 | 
			
		||||
    for (let playerId in currRenderFrame.players) {
 | 
			
		||||
      const currPlayerDownsync = currRenderFrame.players[playerId];
 | 
			
		||||
      nextRenderFramePlayers[playerId] = {
 | 
			
		||||
        id: playerId,
 | 
			
		||||
        virtualGridX: currPlayerDownsync.virtualGridX,
 | 
			
		||||
        virtualGridY: currPlayerDownsync.virtualGridY,
 | 
			
		||||
        dir: {
 | 
			
		||||
          dx: currPlayerDownsync.dir.dx,
 | 
			
		||||
          dy: currPlayerDownsync.dir.dy,
 | 
			
		||||
        },
 | 
			
		||||
        dirX: currPlayerDownsync.dirX,
 | 
			
		||||
        dirY: currPlayerDownsync.dirY,
 | 
			
		||||
        characterState: currPlayerDownsync.characterState,
 | 
			
		||||
        speed: currPlayerDownsync.speed,
 | 
			
		||||
        battleState: currPlayerDownsync.battleState,
 | 
			
		||||
@@ -1034,6 +1030,8 @@ cc.Class({
 | 
			
		||||
 | 
			
		||||
    const bulletPushbacks = new Array(self.playerRichInfoArr.length); // Guaranteed determinism regardless of traversal order
 | 
			
		||||
    const effPushbacks = new Array(self.playerRichInfoArr.length); // Guaranteed determinism regardless of traversal order
 | 
			
		||||
 | 
			
		||||
    // Reset playerCollider position from the "virtual grid position"
 | 
			
		||||
    for (let j in self.playerRichInfoArr) {
 | 
			
		||||
      const joinIndex = parseInt(j) + 1;
 | 
			
		||||
      bulletPushbacks[joinIndex - 1] = [0.0, 0.0];
 | 
			
		||||
@@ -1042,17 +1040,17 @@ cc.Class({
 | 
			
		||||
      const playerId = playerRichInfo.id;
 | 
			
		||||
      const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex;
 | 
			
		||||
      const playerCollider = collisionSysMap.get(collisionPlayerIndex);
 | 
			
		||||
      const player = currRenderFrame.players[playerId];
 | 
			
		||||
      const currPlayerDownsync = currRenderFrame.players[playerId];
 | 
			
		||||
 | 
			
		||||
      const newVx = player.virtualGridX;
 | 
			
		||||
      const newVy = player.virtualGridY;
 | 
			
		||||
      const newVx = currPlayerDownsync.virtualGridX;
 | 
			
		||||
      const newVy = currPlayerDownsync.virtualGridY;
 | 
			
		||||
      const newCpos = self.virtualGridToPlayerColliderPos(newVx, newVy, self.playerRichInfoArr[joinIndex - 1]);
 | 
			
		||||
      playerCollider.x = newCpos[0];
 | 
			
		||||
      playerCollider.y = newCpos[1];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check bullet-anything collisions first, because the pushbacks caused by bullets might later be reverted by player-barrier collision 
 | 
			
		||||
    const colliderBullets = new Map(); // Will all be removed at the end of `applyInputFrameDownsyncDynamicsOnSingleRenderFrame` due to the need for being rollback-compatible
 | 
			
		||||
    const bulletColliders = new Map(); // Will all be removed at the end of `applyInputFrameDownsyncDynamicsOnSingleRenderFrame` due to the need for being rollback-compatible
 | 
			
		||||
    const removedBulletsAtCurrFrame = new Set();
 | 
			
		||||
    for (let k in currRenderFrame.meleeBullets) {
 | 
			
		||||
      const meleeBullet = currRenderFrame.meleeBullets[k];
 | 
			
		||||
@@ -1066,39 +1064,39 @@ cc.Class({
 | 
			
		||||
        const offenderCollider = collisionSysMap.get(collisionOffenderIndex);
 | 
			
		||||
        const offender = currRenderFrame.players[meleeBullet.offenderPlayerId];
 | 
			
		||||
 | 
			
		||||
        const xfac = Math.sign(offender.dir.dx),
 | 
			
		||||
        let xfac = 1,
 | 
			
		||||
          yfac = 0; // By now, straight Punch offset doesn't respect "y-axis"
 | 
			
		||||
        if (0 > offender.dirX) {
 | 
			
		||||
          xfac = -1;
 | 
			
		||||
        }
 | 
			
		||||
        const x0 = offenderCollider.x + xfac * meleeBullet.hitboxOffset,
 | 
			
		||||
          y0 = offenderCollider.y + yfac * meleeBullet.hitboxOffset;
 | 
			
		||||
        const pts = [[0, 0], [xfac * meleeBullet.hitboxSize.x, 0], [xfac * meleeBullet.hitboxSize.x, meleeBullet.hitboxSize.y], [0, meleeBullet.hitboxSize.y]];
 | 
			
		||||
        const newBulletCollider = collisionSys.createPolygon(x0, y0, pts);
 | 
			
		||||
        newBulletCollider.collisionBulletIndex = collisionBulletIndex;
 | 
			
		||||
        newBulletCollider.offenderPlayerId = meleeBullet.offenderPlayerId;
 | 
			
		||||
        newBulletCollider.pushback = meleeBullet.pushback;
 | 
			
		||||
        newBulletCollider.hitStunFrames = meleeBullet.hitStunFrames;
 | 
			
		||||
        newBulletCollider.data = meleeBullet;
 | 
			
		||||
        collisionSysMap.set(collisionBulletIndex, newBulletCollider);
 | 
			
		||||
        colliderBullets.set(collisionBulletIndex, newBulletCollider);
 | 
			
		||||
        console.log(`A meleeBullet=${JSON.stringify(meleeBullet)} is added to collisionSys at renderFrame.id=${currRenderFrame.id} as start-up frames ended and active frame is not yet ended`);
 | 
			
		||||
        bulletColliders.set(collisionBulletIndex, newBulletCollider);
 | 
			
		||||
      // console.log(`A meleeBullet is added to collisionSys at renderFrame.id=${currRenderFrame.id} as start-up frames ended and active frame is not yet ended: ${JSON.stringify(meleeBullet)}`);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    collisionSys.update();
 | 
			
		||||
    const result1 = collisionSys.createResult(); // Can I reuse a "self.collisionSysResult" object throughout the whole battle?
 | 
			
		||||
 | 
			
		||||
    colliderBullets.forEach((bulletCollider, collisionBulletIndex) => {
 | 
			
		||||
    bulletColliders.forEach((bulletCollider, collisionBulletIndex) => {
 | 
			
		||||
      const potentials = bulletCollider.potentials();
 | 
			
		||||
      let shouldRemove = false;
 | 
			
		||||
      for (const potential of potentials) {
 | 
			
		||||
        if (null != potential.playerId && potential.playerId == bulletCollider.offenderPlayerId) continue;
 | 
			
		||||
        if (null != potential.data && potential.data.joinIndex == bulletCollider.data.offenderJoinIndex) continue;
 | 
			
		||||
        if (!bulletCollider.collides(potential, result1)) continue;
 | 
			
		||||
        if (null != potential.playerId) {
 | 
			
		||||
          const joinIndex = potential.collisionPlayerIndex - self.collisionPlayerIndexPrefix;
 | 
			
		||||
          bulletPushbacks[joinIndex - 1][0] += result1.overlap_x * bulletCollider.pushback;
 | 
			
		||||
          bulletPushbacks[joinIndex - 1][1] += result1.overlap_y * bulletCollider.pushback;
 | 
			
		||||
          const thatAckedPlayerInNextFrame = nextRenderFramePlayers[potential.playerId];
 | 
			
		||||
        if (null != potential.data && null !== potential.data.joinIndex) {
 | 
			
		||||
          const joinIndex = potential.data.joinIndex;
 | 
			
		||||
          bulletPushbacks[joinIndex - 1][0] += bulletCollider.data.pushback; // Only for straight punch, there's no y-pushback
 | 
			
		||||
          bulletPushbacks[joinIndex - 1][1] += 0;
 | 
			
		||||
          const thatAckedPlayerInNextFrame = nextRenderFramePlayers[potential.data.id];
 | 
			
		||||
          thatAckedPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Atked1[0];
 | 
			
		||||
          const oldFrameToRecover = thatAckedPlayerInNextFrame.framesToRecover;
 | 
			
		||||
          thatAckedPlayerInNextFrame.framesToRecover = oldFrameToRecover > bulletCollider.hitStunFrames ? oldFrameToRecover : bulletCollider.hitStunFrames; // In case the hit player is already stun, we take the larger "hitStunFrames" 
 | 
			
		||||
          thatAckedPlayerInNextFrame.framesToRecover = (oldFrameToRecover > bulletCollider.data.hitStunFrames ? oldFrameToRecover : bulletCollider.data.hitStunFrames); // In case the hit player is already stun, we extend it 
 | 
			
		||||
        }
 | 
			
		||||
        shouldRemove = true;
 | 
			
		||||
      }
 | 
			
		||||
@@ -1107,9 +1105,9 @@ cc.Class({
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // [WARNING] Remove bullets from collisionSys ANYWAY for the convenience of rollback
 | 
			
		||||
    for (let k in currRenderFrame.meleeBullets) {
 | 
			
		||||
      const meleeBullet = currRenderFrame.meleeBullets[k];
 | 
			
		||||
      // [WARNING] remove from collisionSys ANYWAY for the convenience of rollback
 | 
			
		||||
      const collisionBulletIndex = self.collisionBulletIndexPrefix + meleeBullet.battleLocalId;
 | 
			
		||||
      if (collisionSysMap.has(collisionBulletIndex)) {
 | 
			
		||||
        const bulletCollider = collisionSysMap.get(collisionBulletIndex);
 | 
			
		||||
@@ -1120,10 +1118,10 @@ cc.Class({
 | 
			
		||||
      toRet.meleeBullets.push(meleeBullet);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Process player inputs
 | 
			
		||||
    if (null != delayedInputFrame) {
 | 
			
		||||
      const delayedInputFrameForPrevRenderFrame = self.getCachedInputFrameDownsyncWithPrediction(self._convertToInputFrameId(currRenderFrame.id - 1, self.inputDelayFrames));
 | 
			
		||||
      const inputList = delayedInputFrame.inputList;
 | 
			
		||||
      // Process player inputs
 | 
			
		||||
      for (let j in self.playerRichInfoArr) {
 | 
			
		||||
        const joinIndex = parseInt(j) + 1;
 | 
			
		||||
        effPushbacks[joinIndex - 1] = [0.0, 0.0];
 | 
			
		||||
@@ -1131,13 +1129,14 @@ cc.Class({
 | 
			
		||||
        const playerId = playerRichInfo.id;
 | 
			
		||||
        const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex;
 | 
			
		||||
        const playerCollider = collisionSysMap.get(collisionPlayerIndex);
 | 
			
		||||
        const player = currRenderFrame.players[playerId];
 | 
			
		||||
        if (0 < nextRenderFramePlayers[playerId].framesToRecover) {
 | 
			
		||||
        const currPlayerDownsync = currRenderFrame.players[playerId];
 | 
			
		||||
        const thatPlayerInNextFrame = nextRenderFramePlayers[playerId];
 | 
			
		||||
        if (0 < thatPlayerInNextFrame.framesToRecover) {
 | 
			
		||||
          // No need to process inputs for this player, but there might be bullet pushbacks on this player  
 | 
			
		||||
          playerCollider.x += bulletPushbacks[joinIndex - 1][0];
 | 
			
		||||
          playerCollider.y += bulletPushbacks[joinIndex - 1][1];
 | 
			
		||||
          if (0 != bulletPushbacks[joinIndex - 1][0] || 0 != bulletPushbacks[joinIndex - 1][1]) {
 | 
			
		||||
            playerCollider.x += bulletPushbacks[joinIndex - 1][0];
 | 
			
		||||
            playerCollider.y += bulletPushbacks[joinIndex - 1][1];
 | 
			
		||||
            console.log(`playerId=${playerId}, joinIndex=${joinIndex} is pushbacked back by ${bulletPushbacks[joinIndex - 1]} by bullet impacts, now its framesToRecover is ${player.framesToRecover}`);
 | 
			
		||||
            console.log(`playerId=${playerId}, joinIndex=${joinIndex} is pushbacked back by ${bulletPushbacks[joinIndex - 1]} by bullet impacts, now its framesToRecover is ${currPlayerDownsync.framesToRecover}`);
 | 
			
		||||
          }
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
@@ -1148,33 +1147,32 @@ cc.Class({
 | 
			
		||||
        const prevBtnALevel = (null == prevDecodedInput ? 0 : prevDecodedInput.btnALevel);
 | 
			
		||||
 | 
			
		||||
        if (1 == decodedInput.btnALevel && 0 == prevBtnALevel) {
 | 
			
		||||
          console.log(`playerId=${playerId} triggered a rising-edge of btnA at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
 | 
			
		||||
        // The online map is not yet ready for bullet shooting!
 | 
			
		||||
        /*
 | 
			
		||||
        nextRenderFramePlayers[playerId].framesToRecover = PunchAtkConfig.recoveryFrames;
 | 
			
		||||
        const punch = window.pb.protos.MeleeBullet.create(PunchAtkConfig);
 | 
			
		||||
        punch.battleLocalId = self.bulletBattleLocalIdCounter++;
 | 
			
		||||
        punch.offenderJoinIndex = joinIndex;
 | 
			
		||||
        punch.offenderPlayerId = playerId;
 | 
			
		||||
        punch.originatedRenderFrameId = currRenderFrame.id;
 | 
			
		||||
        toRet.meleeBullets.push(punch);
 | 
			
		||||
        console.log(`A rising-edge of meleeBullet=${JSON.stringify(punch)} is created at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
 | 
			
		||||
          // console.log(`playerId=${playerId} triggered a rising-edge of btnA at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
 | 
			
		||||
          if (self.bulletTriggerEnabled) {
 | 
			
		||||
            thatPlayerInNextFrame.framesToRecover = window.PunchAtkConfig.recoveryFrames;
 | 
			
		||||
            const punch = window.pb.protos.MeleeBullet.create(window.PunchAtkConfig);
 | 
			
		||||
            punch.battleLocalId = self.bulletBattleLocalIdCounter++;
 | 
			
		||||
            punch.offenderJoinIndex = joinIndex;
 | 
			
		||||
            punch.offenderPlayerId = playerId;
 | 
			
		||||
            punch.originatedRenderFrameId = currRenderFrame.id;
 | 
			
		||||
            toRet.meleeBullets.push(punch);
 | 
			
		||||
            console.log(`A rising-edge of meleeBullet is created at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}: ${JSON.stringify(punch)}`);
 | 
			
		||||
 | 
			
		||||
        nextRenderFramePlayers[playerId].characterState = window.ATK_CHARACTER_STATE.Atk1[0];
 | 
			
		||||
        */
 | 
			
		||||
            thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Atk1[0];
 | 
			
		||||
          }
 | 
			
		||||
        } else if (0 == decodedInput.btnALevel && 1 == prevBtnALevel) {
 | 
			
		||||
          console.log(`playerId=${playerId} triggered a falling-edge of btnA at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
 | 
			
		||||
          // console.log(`playerId=${playerId} triggered a falling-edge of btnA at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
 | 
			
		||||
        } else {
 | 
			
		||||
          // No trigger, process movement inputs
 | 
			
		||||
          if (0 != decodedInput.dx || 0 != decodedInput.dy) {
 | 
			
		||||
            // Update directions and thus would eventually update moving animation accordingly
 | 
			
		||||
            nextRenderFramePlayers[playerId].dir.dx = decodedInput.dx;
 | 
			
		||||
            nextRenderFramePlayers[playerId].dir.dy = decodedInput.dy;
 | 
			
		||||
            nextRenderFramePlayers[playerId].characterState = window.ATK_CHARACTER_STATE.Walking[0];
 | 
			
		||||
            thatPlayerInNextFrame.dirX = decodedInput.dx;
 | 
			
		||||
            thatPlayerInNextFrame.dirY = decodedInput.dy;
 | 
			
		||||
            thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Walking[0];
 | 
			
		||||
          } else {
 | 
			
		||||
            nextRenderFramePlayers[playerId].characterState = window.ATK_CHARACTER_STATE.Idle1[0];
 | 
			
		||||
            thatPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Idle1[0];
 | 
			
		||||
          }
 | 
			
		||||
          const movement = self.virtualGridToWorldPos(decodedInput.dx + player.speed * decodedInput.dx, decodedInput.dy + player.speed * decodedInput.dy);
 | 
			
		||||
          const movement = self.virtualGridToWorldPos(decodedInput.dx + currPlayerDownsync.speed * decodedInput.dx, decodedInput.dy + currPlayerDownsync.speed * decodedInput.dy);
 | 
			
		||||
          playerCollider.x += movement[0];
 | 
			
		||||
          playerCollider.y += movement[1];
 | 
			
		||||
        }
 | 
			
		||||
@@ -1204,8 +1202,9 @@ cc.Class({
 | 
			
		||||
        const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex;
 | 
			
		||||
        const playerCollider = collisionSysMap.get(collisionPlayerIndex);
 | 
			
		||||
        const newVpos = self.playerColliderAnchorToVirtualGridPos(playerCollider.x - effPushbacks[joinIndex - 1][0], playerCollider.y - effPushbacks[joinIndex - 1][1], self.playerRichInfoArr[j]);
 | 
			
		||||
        nextRenderFramePlayers[playerId].virtualGridX = newVpos[0];
 | 
			
		||||
        nextRenderFramePlayers[playerId].virtualGridY = newVpos[1];
 | 
			
		||||
        const thatPlayerInNextFrame = nextRenderFramePlayers[playerId];
 | 
			
		||||
        thatPlayerInNextFrame.virtualGridX = newVpos[0];
 | 
			
		||||
        thatPlayerInNextFrame.virtualGridY = newVpos[1];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,27 +3,27 @@ i18n.init(window.language); // languageID should be equal to the one we input in
 | 
			
		||||
 | 
			
		||||
const OnlineMap = require('./Map');
 | 
			
		||||
 | 
			
		||||
const PunchAtkConfig = {
 | 
			
		||||
window.PunchAtkConfig = {
 | 
			
		||||
  // for offender
 | 
			
		||||
  startupFrames: 18,
 | 
			
		||||
  activeFrames: 42,
 | 
			
		||||
  recoveryFrames: 60, // usually but not always "startupFrames+activeFrames"
 | 
			
		||||
  recoveryFramesOnBlock: 60, // usually but not always the same as "recoveryFrames" 
 | 
			
		||||
  recoveryFramesOnHit: 60, // usually but not always the same as "recoveryFrames"
 | 
			
		||||
  recoveryFrames: 61, // usually but not always "startupFrames+activeFrames", I hereby set it to be 1 frame more than the actual animation to avoid critical transition, i.e. when the animation is 1 frame from ending but "rdfPlayer.framesToRecover" is already counted 0 and the player triggers an other same attack, making an effective bullet trigger but no animation is played due to same animName is still playing
 | 
			
		||||
  recoveryFramesOnBlock: 61,
 | 
			
		||||
  recoveryFramesOnHit: 61,
 | 
			
		||||
  moveforward: {
 | 
			
		||||
    x: 0,
 | 
			
		||||
    y: 0,
 | 
			
		||||
  },
 | 
			
		||||
  hitboxOffset: 12.0, // should be about the radius of the PlayerCollider 
 | 
			
		||||
  hitboxSize: {
 | 
			
		||||
    x: 32.0,
 | 
			
		||||
    x: 45.0,
 | 
			
		||||
    y: 32.0,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // for defender
 | 
			
		||||
  hitStunFrames: 18,
 | 
			
		||||
  blockStunFrames: 9,
 | 
			
		||||
  pushback: 11.0,
 | 
			
		||||
  pushback: 22.0,
 | 
			
		||||
  releaseTriggerType: 1, // 1: rising-edge, 2: falling-edge  
 | 
			
		||||
  damage: 5
 | 
			
		||||
};
 | 
			
		||||
@@ -35,45 +35,6 @@ cc.Class({
 | 
			
		||||
    console.warn("+++++++ Map onDestroy()");
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  spawnPlayerNode(joinIndex, vx, vy, playerRichInfo) {
 | 
			
		||||
    const self = this;
 | 
			
		||||
    const newPlayerNode = cc.instantiate(self.controlledCharacterPrefab)
 | 
			
		||||
    const playerScriptIns = newPlayerNode.getComponent("ControlledCharacter");
 | 
			
		||||
    if (1 == joinIndex) {
 | 
			
		||||
      playerScriptIns.setSpecies("SoldierWaterGhost");
 | 
			
		||||
    } else if (2 == joinIndex) {
 | 
			
		||||
      playerScriptIns.setSpecies("SoldierFireGhost");
 | 
			
		||||
      playerScriptIns.animComp.node.scaleX = (-1.0);
 | 
			
		||||
    }
 | 
			
		||||
    const wpos = self.virtualGridToWorldPos(vx, vy);
 | 
			
		||||
 | 
			
		||||
    newPlayerNode.setPosition(cc.v2(wpos[0], wpos[1]));
 | 
			
		||||
 | 
			
		||||
    playerScriptIns.mapNode = self.node;
 | 
			
		||||
    const cpos = self.virtualGridToPlayerColliderPos(vx, vy, playerRichInfo);
 | 
			
		||||
    const d = playerRichInfo.colliderRadius * 2,
 | 
			
		||||
      x0 = cpos[0],
 | 
			
		||||
      y0 = cpos[1];
 | 
			
		||||
    let pts = [[0, 0], [d, 0], [d, d], [0, d]];
 | 
			
		||||
 | 
			
		||||
    const newPlayerCollider = self.collisionSys.createPolygon(x0, y0, pts);
 | 
			
		||||
    const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex;
 | 
			
		||||
    newPlayerCollider.collisionPlayerIndex = parseInt(collisionPlayerIndex);
 | 
			
		||||
    newPlayerCollider.playerId = parseInt(playerRichInfo.id);
 | 
			
		||||
    self.collisionSysMap.set(collisionPlayerIndex, newPlayerCollider);
 | 
			
		||||
 | 
			
		||||
    safelyAddChild(self.node, newPlayerNode);
 | 
			
		||||
    setLocalZOrder(newPlayerNode, 5);
 | 
			
		||||
 | 
			
		||||
    newPlayerNode.active = true;
 | 
			
		||||
    playerScriptIns.updateCharacterAnim({
 | 
			
		||||
      dx: playerRichInfo.dir.dx,
 | 
			
		||||
      dy: playerRichInfo.dir.dy
 | 
			
		||||
    }, playerRichInfo, true);
 | 
			
		||||
 | 
			
		||||
    return [newPlayerNode, playerScriptIns];
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  onLoad() {
 | 
			
		||||
    const self = this;
 | 
			
		||||
    window.mapIns = self;
 | 
			
		||||
@@ -182,10 +143,8 @@ cc.Class({
 | 
			
		||||
            colliderRadius: 12,
 | 
			
		||||
            characterState: window.ATK_CHARACTER_STATE.Idle1[0],
 | 
			
		||||
            framesToRecover: 0,
 | 
			
		||||
            dir: {
 | 
			
		||||
              dx: 0,
 | 
			
		||||
              dy: 0
 | 
			
		||||
            }
 | 
			
		||||
            dirX: 0,
 | 
			
		||||
            dirY: 0,
 | 
			
		||||
          },
 | 
			
		||||
          11: {
 | 
			
		||||
            id: 11,
 | 
			
		||||
@@ -196,10 +155,8 @@ cc.Class({
 | 
			
		||||
            colliderRadius: 12,
 | 
			
		||||
            characterState: window.ATK_CHARACTER_STATE.Idle1[0],
 | 
			
		||||
            framesToRecover: 0,
 | 
			
		||||
            dir: {
 | 
			
		||||
              dx: 0,
 | 
			
		||||
              dy: 0
 | 
			
		||||
            }
 | 
			
		||||
            dirX: 0,
 | 
			
		||||
            dirY: 0,
 | 
			
		||||
          },
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
@@ -243,214 +200,4 @@ cc.Class({
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // Overriding this function to test experimental dynamics
 | 
			
		||||
  applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, currRenderFrame, collisionSys, collisionSysMap) {
 | 
			
		||||
    const self = this;
 | 
			
		||||
    const nextRenderFramePlayers = {}
 | 
			
		||||
    for (let playerId in currRenderFrame.players) {
 | 
			
		||||
      const currPlayerDownsync = currRenderFrame.players[playerId];
 | 
			
		||||
      nextRenderFramePlayers[playerId] = {
 | 
			
		||||
        id: playerId,
 | 
			
		||||
        virtualGridX: currPlayerDownsync.virtualGridX,
 | 
			
		||||
        virtualGridY: currPlayerDownsync.virtualGridY,
 | 
			
		||||
        dir: {
 | 
			
		||||
          dx: currPlayerDownsync.dir.dx,
 | 
			
		||||
          dy: currPlayerDownsync.dir.dy,
 | 
			
		||||
        },
 | 
			
		||||
        characterState: currPlayerDownsync.characterState,
 | 
			
		||||
        speed: currPlayerDownsync.speed,
 | 
			
		||||
        battleState: currPlayerDownsync.battleState,
 | 
			
		||||
        score: currPlayerDownsync.score,
 | 
			
		||||
        removed: currPlayerDownsync.removed,
 | 
			
		||||
        joinIndex: currPlayerDownsync.joinIndex,
 | 
			
		||||
        framesToRecover: (0 < currPlayerDownsync.framesToRecover ? currPlayerDownsync.framesToRecover - 1 : 0),
 | 
			
		||||
        hp: currPlayerDownsync.hp,
 | 
			
		||||
        maxHp: currPlayerDownsync.maxHp,
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const toRet = {
 | 
			
		||||
      id: currRenderFrame.id + 1,
 | 
			
		||||
      players: nextRenderFramePlayers,
 | 
			
		||||
      meleeBullets: []
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const bulletPushbacks = new Array(self.playerRichInfoArr.length); // Guaranteed determinism regardless of traversal order
 | 
			
		||||
    const effPushbacks = new Array(self.playerRichInfoArr.length); // Guaranteed determinism regardless of traversal order
 | 
			
		||||
    for (let j in self.playerRichInfoArr) {
 | 
			
		||||
      const joinIndex = parseInt(j) + 1;
 | 
			
		||||
      bulletPushbacks[joinIndex - 1] = [0.0, 0.0];
 | 
			
		||||
      effPushbacks[joinIndex - 1] = [0.0, 0.0];
 | 
			
		||||
      const playerRichInfo = self.playerRichInfoArr[j];
 | 
			
		||||
      const playerId = playerRichInfo.id;
 | 
			
		||||
      const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex;
 | 
			
		||||
      const playerCollider = collisionSysMap.get(collisionPlayerIndex);
 | 
			
		||||
      const player = currRenderFrame.players[playerId];
 | 
			
		||||
 | 
			
		||||
      const newVx = player.virtualGridX;
 | 
			
		||||
      const newVy = player.virtualGridY;
 | 
			
		||||
      const newCpos = self.virtualGridToPlayerColliderPos(newVx, newVy, self.playerRichInfoArr[joinIndex - 1]);
 | 
			
		||||
      playerCollider.x = newCpos[0];
 | 
			
		||||
      playerCollider.y = newCpos[1];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Check bullet-anything collisions first, because the pushbacks caused by bullets might later be reverted by player-barrier collision 
 | 
			
		||||
    const colliderBullets = new Map(); // Will all be removed at the end of `applyInputFrameDownsyncDynamicsOnSingleRenderFrame` due to the need for being rollback-compatible
 | 
			
		||||
    const removedBulletsAtCurrFrame = new Set();
 | 
			
		||||
    for (let k in currRenderFrame.meleeBullets) {
 | 
			
		||||
      const meleeBullet = currRenderFrame.meleeBullets[k];
 | 
			
		||||
      if (
 | 
			
		||||
        meleeBullet.originatedRenderFrameId + meleeBullet.startupFrames <= currRenderFrame.id
 | 
			
		||||
        &&
 | 
			
		||||
        meleeBullet.originatedRenderFrameId + meleeBullet.startupFrames + meleeBullet.activeFrames > currRenderFrame.id
 | 
			
		||||
      ) {
 | 
			
		||||
        const collisionBulletIndex = self.collisionBulletIndexPrefix + meleeBullet.battleLocalId;
 | 
			
		||||
        const collisionOffenderIndex = self.collisionPlayerIndexPrefix + meleeBullet.offenderJoinIndex;
 | 
			
		||||
        const offenderCollider = collisionSysMap.get(collisionOffenderIndex);
 | 
			
		||||
        const offender = currRenderFrame.players[meleeBullet.offenderPlayerId];
 | 
			
		||||
 | 
			
		||||
        const xfac = Math.sign(offender.dir.dx),
 | 
			
		||||
          yfac = 0; // By now, straight Punch offset doesn't respect "y-axis" 
 | 
			
		||||
        const x0 = offenderCollider.x + xfac * meleeBullet.hitboxOffset,
 | 
			
		||||
          y0 = offenderCollider.y + yfac * meleeBullet.hitboxOffset;
 | 
			
		||||
        const pts = [[0, 0], [xfac * meleeBullet.hitboxSize.x, 0], [xfac * meleeBullet.hitboxSize.x, meleeBullet.hitboxSize.y], [0, meleeBullet.hitboxSize.y]];
 | 
			
		||||
        const newBulletCollider = collisionSys.createPolygon(x0, y0, pts);
 | 
			
		||||
        newBulletCollider.collisionBulletIndex = collisionBulletIndex;
 | 
			
		||||
        newBulletCollider.offenderPlayerId = meleeBullet.offenderPlayerId;
 | 
			
		||||
        newBulletCollider.pushback = meleeBullet.pushback;
 | 
			
		||||
        newBulletCollider.hitStunFrames = meleeBullet.hitStunFrames;
 | 
			
		||||
        collisionSysMap.set(collisionBulletIndex, newBulletCollider);
 | 
			
		||||
        colliderBullets.set(collisionBulletIndex, newBulletCollider);
 | 
			
		||||
        console.log(`A meleeBullet=${JSON.stringify(meleeBullet)} is added to collisionSys at renderFrame.id=${currRenderFrame.id} as start-up frames ended and active frame is not yet ended`);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    collisionSys.update();
 | 
			
		||||
    const result1 = collisionSys.createResult(); // Can I reuse a "self.collisionSysResult" object throughout the whole battle?
 | 
			
		||||
 | 
			
		||||
    colliderBullets.forEach((bulletCollider, collisionBulletIndex) => {
 | 
			
		||||
      const potentials = bulletCollider.potentials();
 | 
			
		||||
      let shouldRemove = false;
 | 
			
		||||
      for (const potential of potentials) {
 | 
			
		||||
        if (null != potential.playerId && potential.playerId == bulletCollider.offenderPlayerId) continue;
 | 
			
		||||
        if (!bulletCollider.collides(potential, result1)) continue;
 | 
			
		||||
        if (null != potential.playerId) {
 | 
			
		||||
          const joinIndex = potential.collisionPlayerIndex - self.collisionPlayerIndexPrefix;
 | 
			
		||||
          bulletPushbacks[joinIndex - 1][0] += result1.overlap_x * bulletCollider.pushback;
 | 
			
		||||
          bulletPushbacks[joinIndex - 1][1] += result1.overlap_y * bulletCollider.pushback;
 | 
			
		||||
          const thatAckedPlayerInNextFrame = nextRenderFramePlayers[potential.playerId];
 | 
			
		||||
          thatAckedPlayerInNextFrame.characterState = window.ATK_CHARACTER_STATE.Atked1[0];
 | 
			
		||||
          const oldFrameToRecover = thatAckedPlayerInNextFrame.framesToRecover;
 | 
			
		||||
          thatAckedPlayerInNextFrame.framesToRecover = oldFrameToRecover > bulletCollider.hitStunFrames ? oldFrameToRecover : bulletCollider.hitStunFrames; // In case the hit player is already stun, we take the larger "hitStunFrames" 
 | 
			
		||||
        }
 | 
			
		||||
        shouldRemove = true;
 | 
			
		||||
      }
 | 
			
		||||
      if (shouldRemove) {
 | 
			
		||||
        removedBulletsAtCurrFrame.add(collisionBulletIndex);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    for (let k in currRenderFrame.meleeBullets) {
 | 
			
		||||
      const meleeBullet = currRenderFrame.meleeBullets[k];
 | 
			
		||||
      // [WARNING] remove from collisionSys ANYWAY for the convenience of rollback
 | 
			
		||||
      const collisionBulletIndex = self.collisionBulletIndexPrefix + meleeBullet.battleLocalId;
 | 
			
		||||
      if (collisionSysMap.has(collisionBulletIndex)) {
 | 
			
		||||
        const bulletCollider = collisionSysMap.get(collisionBulletIndex);
 | 
			
		||||
        bulletCollider.remove();
 | 
			
		||||
        collisionSysMap.delete(collisionBulletIndex);
 | 
			
		||||
      }
 | 
			
		||||
      if (removedBulletsAtCurrFrame.has(collisionBulletIndex)) continue;
 | 
			
		||||
      toRet.meleeBullets.push(meleeBullet);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (null != delayedInputFrame) {
 | 
			
		||||
      const delayedInputFrameForPrevRenderFrame = self.getCachedInputFrameDownsyncWithPrediction(self._convertToInputFrameId(currRenderFrame.id - 1, self.inputDelayFrames));
 | 
			
		||||
      const inputList = delayedInputFrame.inputList;
 | 
			
		||||
      // Process player inputs
 | 
			
		||||
      for (let j in self.playerRichInfoArr) {
 | 
			
		||||
        const joinIndex = parseInt(j) + 1;
 | 
			
		||||
        effPushbacks[joinIndex - 1] = [0.0, 0.0];
 | 
			
		||||
        const playerRichInfo = self.playerRichInfoArr[j];
 | 
			
		||||
        const playerId = playerRichInfo.id;
 | 
			
		||||
        const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex;
 | 
			
		||||
        const playerCollider = collisionSysMap.get(collisionPlayerIndex);
 | 
			
		||||
        const player = currRenderFrame.players[playerId];
 | 
			
		||||
        if (0 < nextRenderFramePlayers[playerId].framesToRecover) {
 | 
			
		||||
          // No need to process inputs for this player, but there might be bullet pushbacks on this player  
 | 
			
		||||
          if (0 != bulletPushbacks[joinIndex - 1][0] || 0 != bulletPushbacks[joinIndex - 1][1]) {
 | 
			
		||||
            playerCollider.x += bulletPushbacks[joinIndex - 1][0];
 | 
			
		||||
            playerCollider.y += bulletPushbacks[joinIndex - 1][1];
 | 
			
		||||
            console.log(`playerId=${playerId}, joinIndex=${joinIndex} is pushbacked back by ${bulletPushbacks[joinIndex - 1]} by bullet impacts, now its framesToRecover is ${player.framesToRecover}`);
 | 
			
		||||
          }
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const decodedInput = self.ctrl.decodeInput(inputList[joinIndex - 1]);
 | 
			
		||||
 | 
			
		||||
        const prevDecodedInput = (null == delayedInputFrameForPrevRenderFrame ? null : self.ctrl.decodeInput(delayedInputFrameForPrevRenderFrame.inputList[joinIndex - 1]));
 | 
			
		||||
        const prevBtnALevel = (null == prevDecodedInput ? 0 : prevDecodedInput.btnALevel);
 | 
			
		||||
 | 
			
		||||
        if (1 == decodedInput.btnALevel && 0 == prevBtnALevel) {
 | 
			
		||||
          console.log(`playerId=${playerId} triggered a rising-edge of btnA at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
 | 
			
		||||
          nextRenderFramePlayers[playerId].framesToRecover = PunchAtkConfig.recoveryFrames;
 | 
			
		||||
          const punch = window.pb.protos.MeleeBullet.create(PunchAtkConfig);
 | 
			
		||||
          punch.battleLocalId = self.bulletBattleLocalIdCounter++;
 | 
			
		||||
          punch.offenderJoinIndex = joinIndex;
 | 
			
		||||
          punch.offenderPlayerId = playerId;
 | 
			
		||||
          punch.originatedRenderFrameId = currRenderFrame.id;
 | 
			
		||||
          toRet.meleeBullets.push(punch);
 | 
			
		||||
          console.log(`A rising-edge of meleeBullet=${JSON.stringify(punch)} is created at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
 | 
			
		||||
 | 
			
		||||
          nextRenderFramePlayers[playerId].characterState = window.ATK_CHARACTER_STATE.Atk1[0];
 | 
			
		||||
        } else if (0 == decodedInput.btnALevel && 1 == prevBtnALevel) {
 | 
			
		||||
          console.log(`playerId=${playerId} triggered a falling-edge of btnA at renderFrame.id=${currRenderFrame.id}, delayedInputFrame.id=${delayedInputFrame.inputFrameId}`);
 | 
			
		||||
        } else {
 | 
			
		||||
          // No trigger, process movement inputs
 | 
			
		||||
          if (0 != decodedInput.dx || 0 != decodedInput.dy) {
 | 
			
		||||
            // Update directions and thus would eventually update moving animation accordingly
 | 
			
		||||
            nextRenderFramePlayers[playerId].dir.dx = decodedInput.dx;
 | 
			
		||||
            nextRenderFramePlayers[playerId].dir.dy = decodedInput.dy;
 | 
			
		||||
            nextRenderFramePlayers[playerId].characterState = window.ATK_CHARACTER_STATE.Walking[0];
 | 
			
		||||
          } else {
 | 
			
		||||
            nextRenderFramePlayers[playerId].characterState = window.ATK_CHARACTER_STATE.Idle1[0];
 | 
			
		||||
          }
 | 
			
		||||
          const movement = self.virtualGridToWorldPos(decodedInput.dx + player.speed * decodedInput.dx, decodedInput.dy + player.speed * decodedInput.dy);
 | 
			
		||||
          playerCollider.x += movement[0];
 | 
			
		||||
          playerCollider.y += movement[1];
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      collisionSys.update(); // by now all "bulletCollider"s are removed
 | 
			
		||||
      const result2 = collisionSys.createResult(); // Can I reuse a "self.collisionSysResult" object throughout the whole battle?
 | 
			
		||||
 | 
			
		||||
      for (let j in self.playerRichInfoArr) {
 | 
			
		||||
        const joinIndex = parseInt(j) + 1;
 | 
			
		||||
        const playerId = self.playerRichInfoArr[j].id;
 | 
			
		||||
        const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex;
 | 
			
		||||
        const playerCollider = collisionSysMap.get(collisionPlayerIndex);
 | 
			
		||||
        const potentials = playerCollider.potentials();
 | 
			
		||||
        for (const potential of potentials) {
 | 
			
		||||
          // Test if the player collides with the wall
 | 
			
		||||
          if (!playerCollider.collides(potential, result2)) continue;
 | 
			
		||||
          // Push the player out of the wall
 | 
			
		||||
          effPushbacks[joinIndex - 1][0] += result2.overlap * result2.overlap_x;
 | 
			
		||||
          effPushbacks[joinIndex - 1][1] += result2.overlap * result2.overlap_y;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      for (let j in self.playerRichInfoArr) {
 | 
			
		||||
        const joinIndex = parseInt(j) + 1;
 | 
			
		||||
        const playerId = self.playerRichInfoArr[j].id;
 | 
			
		||||
        const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex;
 | 
			
		||||
        const playerCollider = collisionSysMap.get(collisionPlayerIndex);
 | 
			
		||||
        const newVpos = self.playerColliderAnchorToVirtualGridPos(playerCollider.x - effPushbacks[joinIndex - 1][0], playerCollider.y - effPushbacks[joinIndex - 1][1], self.playerRichInfoArr[j]);
 | 
			
		||||
        nextRenderFramePlayers[playerId].virtualGridX = newVpos[0];
 | 
			
		||||
        nextRenderFramePlayers[playerId].virtualGridY = newVpos[1];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return toRet;
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user