Temp broken commit, refactoring battle_srv to use jsexport.

This commit is contained in:
genxium 2022-12-25 15:39:30 +08:00
parent 013c1ea312
commit 9ffcc6fbd8
19 changed files with 2163 additions and 1348 deletions

View File

@ -5,7 +5,7 @@ import (
. "battle_srv/common" . "battle_srv/common"
"battle_srv/common/utils" "battle_srv/common/utils"
"battle_srv/models" "battle_srv/models"
. "jsexport/protos" . "battle_srv/protos"
"battle_srv/storage" "battle_srv/storage"
"bytes" "bytes"
"crypto/sha256" "crypto/sha256"

View File

@ -4,7 +4,7 @@ import (
. "battle_srv/common" . "battle_srv/common"
"battle_srv/common/utils" "battle_srv/common/utils"
"battle_srv/models" "battle_srv/models"
. "jsexport/protos" . "battle_srv/protos"
"battle_srv/storage" "battle_srv/storage"
. "dnmshared" . "dnmshared"
sq "github.com/Masterminds/squirrel" sq "github.com/Masterminds/squirrel"

View File

@ -4,7 +4,7 @@ import (
. "battle_srv/common" . "battle_srv/common"
"battle_srv/common/utils" "battle_srv/common/utils"
"battle_srv/models" "battle_srv/models"
. "jsexport/protos" . "battle_srv/protos"
"battle_srv/storage" "battle_srv/storage"
. "dnmshared" . "dnmshared"

View File

@ -1,17 +1,52 @@
package models package models
import ( import (
. "jsexport/protos" pb "battle_srv/protos"
"jsexport/battle"
) )
func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) map[int32]*PlayerDownsync { func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) map[int32]*pb.PlayerDownsync {
toRet := make(map[int32]*PlayerDownsync, 0) toRet := make(map[int32]*pb.PlayerDownsync, 0)
if nil == modelInstances { if nil == modelInstances {
return toRet return toRet
} }
for k, last := range modelInstances { for k, last := range modelInstances {
toRet[k] = &PlayerDownsync{ toRet[k] = &pb.PlayerDownsync{
Id: last.Id,
VirtualGridX: last.VirtualGridX,
VirtualGridY: last.VirtualGridY,
DirX: last.DirX,
DirY: last.DirY,
VelX: last.VelX,
VelY: last.VelY,
Speed: last.Speed,
BattleState: last.BattleState,
CharacterState: last.CharacterState,
InAir: last.InAir,
JoinIndex: last.JoinIndex,
ColliderRadius: last.ColliderRadius,
Score: last.Score,
Removed: last.Removed,
}
if withMetaInfo {
toRet[k].Name = last.Name
toRet[k].DisplayName = last.DisplayName
toRet[k].Avatar = last.Avatar
}
}
return toRet
}
func toJsPlayers(modelInstances map[int32]*Player, withMetaInfo bool) map[int32]*battle.PlayerDownsync {
toRet := make(map[int32]*battle.PlayerDownsync, 0)
if nil == modelInstances {
return toRet
}
for k, last := range modelInstances {
toRet[k] = &battle.PlayerDownsync{
Id: last.Id, Id: last.Id,
VirtualGridX: last.VirtualGridX, VirtualGridX: last.VirtualGridX,
VirtualGridY: last.VirtualGridY, VirtualGridY: last.VirtualGridY,

View File

@ -1,7 +1,7 @@
package models package models
import ( import (
. "jsexport/protos" . "battle_srv/protos"
"battle_srv/storage" "battle_srv/storage"
. "dnmshared" . "dnmshared"
"fmt" "fmt"

View File

@ -3,10 +3,8 @@ package models
import ( import (
. "battle_srv/common" . "battle_srv/common"
"battle_srv/common/utils" "battle_srv/common/utils"
. "jsexport/protos" pb "battle_srv/protos"
. "jsexport/models"
. "dnmshared" . "dnmshared"
. "dnmshared/sharedprotos"
"encoding/xml" "encoding/xml"
"fmt" "fmt"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
@ -14,6 +12,7 @@ import (
"github.com/solarlune/resolv" "github.com/solarlune/resolv"
"go.uber.org/zap" "go.uber.org/zap"
"io/ioutil" "io/ioutil"
"jsexport/battle"
"math/rand" "math/rand"
"os" "os"
"path/filepath" "path/filepath"
@ -116,7 +115,7 @@ type Room struct {
* Moreover, during the invocation of `PlayerSignalToCloseDict`, the `Player` instance is supposed to be deallocated (though not synchronously). * Moreover, during the invocation of `PlayerSignalToCloseDict`, the `Player` instance is supposed to be deallocated (though not synchronously).
*/ */
PlayerDownsyncSessionDict map[int32]*websocket.Conn PlayerDownsyncSessionDict map[int32]*websocket.Conn
PlayerDownsyncChanDict map[int32](chan InputsBufferSnapshot) PlayerDownsyncChanDict map[int32](chan pb.InputsBufferSnapshot)
PlayerActiveWatchdogDict map[int32](*Watchdog) PlayerActiveWatchdogDict map[int32](*Watchdog)
PlayerSignalToCloseDict map[int32]SignalToCloseConnCbType PlayerSignalToCloseDict map[int32]SignalToCloseConnCbType
Score float32 Score float32
@ -126,7 +125,6 @@ type Room struct {
CurDynamicsRenderFrameId int32 // [WARNING] The dynamics of backend is ALWAYS MOVING FORWARD BY ALL-CONFIRMED INPUTFRAMES (either by upsync or forced), i.e. no rollback; Moreover when "true == BackendDynamicsEnabled" we always have "Room.CurDynamicsRenderFrameId >= Room.RenderFrameId" because each "all-confirmed inputFrame" is applied on "all applicable renderFrames" in one-go hence often sees a future "renderFrame" earlier CurDynamicsRenderFrameId int32 // [WARNING] The dynamics of backend is ALWAYS MOVING FORWARD BY ALL-CONFIRMED INPUTFRAMES (either by upsync or forced), i.e. no rollback; Moreover when "true == BackendDynamicsEnabled" we always have "Room.CurDynamicsRenderFrameId >= Room.RenderFrameId" because each "all-confirmed inputFrame" is applied on "all applicable renderFrames" in one-go hence often sees a future "renderFrame" earlier
EffectivePlayerCount int32 EffectivePlayerCount int32
DismissalWaitGroup sync.WaitGroup DismissalWaitGroup sync.WaitGroup
Barriers map[int32]*Barrier
InputsBuffer *RingBuffer // Indices are STRICTLY consecutive InputsBuffer *RingBuffer // Indices are STRICTLY consecutive
InputsBufferLock sync.Mutex // Guards [InputsBuffer, LatestPlayerUpsyncedInputFrameId, LastAllConfirmedInputFrameId, LastAllConfirmedInputList, LastAllConfirmedInputFrameIdWithChange] InputsBufferLock sync.Mutex // Guards [InputsBuffer, LatestPlayerUpsyncedInputFrameId, LastAllConfirmedInputFrameId, LastAllConfirmedInputList, LastAllConfirmedInputFrameIdWithChange]
RenderFrameBuffer *RingBuffer // Indices are STRICTLY consecutive RenderFrameBuffer *RingBuffer // Indices are STRICTLY consecutive
@ -144,7 +142,10 @@ type Room struct {
BulletBattleLocalIdCounter int32 BulletBattleLocalIdCounter int32
dilutedRollbackEstimatedDtNanos int64 dilutedRollbackEstimatedDtNanos int64
BattleColliderInfo // Compositing to send centralized magic numbers pb.BattleColliderInfo // Compositing to send centralized magic numbers
TmxPointsMap StrToVec2DListMap
TmxPolygonsMap StrToPolygon2DListMap
} }
func (pR *Room) updateScore() { func (pR *Room) updateScore() {
@ -287,24 +288,8 @@ func (pR *Room) ChooseStage() error {
pR.StageDiscreteH = stageDiscreteH pR.StageDiscreteH = stageDiscreteH
pR.StageTileW = stageTileW pR.StageTileW = stageTileW
pR.StageTileH = stageTileH pR.StageTileH = stageTileH
pR.StrToVec2DListMap = strToVec2DListMap pR.TmxPointsMap = strToVec2DListMap
pR.StrToPolygon2DListMap = strToPolygon2DListMap pR.TmxPolygonsMap = strToPolygon2DListMap
barrierPolygon2DList := *(strToPolygon2DListMap["Barrier"])
var barrierLocalIdInBattle int32 = 0
for _, polygon2DUnaligned := range barrierPolygon2DList.Eles {
polygon2D := AlignPolygon2DToBoundingBox(polygon2DUnaligned)
/*
// For debug-printing only.
Logger.Info("ChooseStage printing polygon2D for barrierPolygon2DList", zap.Any("barrierLocalIdInBattle", barrierLocalIdInBattle), zap.Any("polygon2D.Anchor", polygon2D.Anchor), zap.Any("polygon2D.Points", polygon2D.Points))
*/
pR.Barriers[barrierLocalIdInBattle] = &Barrier{
Boundary: polygon2D,
}
barrierLocalIdInBattle++
}
return nil return nil
} }
@ -345,7 +330,7 @@ func (pR *Room) InputsBufferString(allDetails bool) string {
if nil == tmp { if nil == tmp {
break break
} }
f := tmp.(*InputFrameDownsync) f := tmp.(*pb.InputFrameDownsync)
s = append(s, fmt.Sprintf("{\"inputFrameId\":%d,\"inputList\":%v,\"confirmedList\":\"%d\"}", f.InputFrameId, f.InputList, f.ConfirmedList)) s = append(s, fmt.Sprintf("{\"inputFrameId\":%d,\"inputList\":%v,\"confirmedList\":\"%d\"}", f.InputFrameId, f.InputList, f.ConfirmedList))
} }
@ -365,12 +350,12 @@ func (pR *Room) StartBattle() {
// Initialize the "collisionSys" as well as "RenderFrameBuffer" // Initialize the "collisionSys" as well as "RenderFrameBuffer"
pR.CurDynamicsRenderFrameId = 0 pR.CurDynamicsRenderFrameId = 0
kickoffFrame := &RoomDownsyncFrame{ kickoffFrameJs := &battle.RoomDownsyncFrame{
Id: pR.RenderFrameId, Id: pR.RenderFrameId,
Players: toPbPlayers(pR.Players, false), Players: toJsPlayers(pR.Players, false),
CountdownNanos: pR.BattleDurationNanos, CountdownNanos: pR.BattleDurationNanos,
} }
pR.RenderFrameBuffer.Put(kickoffFrame) pR.RenderFrameBuffer.Put(kickoffFrameJs)
// Refresh "Colliders" // Refresh "Colliders"
spaceW := pR.StageDiscreteW * pR.StageTileW spaceW := pR.StageDiscreteW * pR.StageTileW
@ -435,7 +420,11 @@ func (pR *Room) StartBattle() {
case PlayerBattleStateIns.DISCONNECTED, PlayerBattleStateIns.LOST, PlayerBattleStateIns.EXPELLED_DURING_GAME, PlayerBattleStateIns.EXPELLED_IN_DISMISSAL: case PlayerBattleStateIns.DISCONNECTED, PlayerBattleStateIns.LOST, PlayerBattleStateIns.EXPELLED_DURING_GAME, PlayerBattleStateIns.EXPELLED_IN_DISMISSAL:
continue continue
} }
kickoffFrame := pR.RenderFrameBuffer.GetByFrameId(0).(*RoomDownsyncFrame) kickoffFrame := &pb.RoomDownsyncFrame{
Id: pR.RenderFrameId,
Players: toPbPlayers(pR.Players, false),
CountdownNanos: pR.BattleDurationNanos,
}
pR.sendSafely(kickoffFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_START, playerId, true) pR.sendSafely(kickoffFrame, nil, DOWNSYNC_MSG_ACT_BATTLE_START, playerId, true)
} }
Logger.Info(fmt.Sprintf("In `battleMainLoop` for roomId=%v sent out kickoffFrame", pR.Id)) Logger.Info(fmt.Sprintf("In `battleMainLoop` for roomId=%v sent out kickoffFrame", pR.Id))
@ -463,7 +452,7 @@ func (pR *Room) StartBattle() {
} }
} }
downsyncLoop := func(playerId int32, player *Player, playerDownsyncChan chan InputsBufferSnapshot) { downsyncLoop := func(playerId int32, player *Player, playerDownsyncChan chan pb.InputsBufferSnapshot) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
Logger.Error("downsyncLoop, recovery spot#1, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r)) Logger.Error("downsyncLoop, recovery spot#1, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r))
@ -495,7 +484,7 @@ func (pR *Room) StartBattle() {
Each "playerDownsyncChan" stays alive through out the lifecycle of room instead of each "playerDownsyncSession", i.e. not closed or dereferenced upon disconnection. Each "playerDownsyncChan" stays alive through out the lifecycle of room instead of each "playerDownsyncSession", i.e. not closed or dereferenced upon disconnection.
*/ */
pR.PlayerDownsyncChanDict[playerId] = make(chan InputsBufferSnapshot, pR.InputsBuffer.N) pR.PlayerDownsyncChanDict[playerId] = make(chan pb.InputsBufferSnapshot, pR.InputsBuffer.N)
go downsyncLoop(playerId, player, pR.PlayerDownsyncChanDict[playerId]) go downsyncLoop(playerId, player, pR.PlayerDownsyncChanDict[playerId])
} }
@ -509,7 +498,7 @@ func (pR *Room) toDiscreteInputsBufferIndex(inputFrameId int32, joinIndex int32)
return (inputFrameId << 2) + joinIndex // allowing joinIndex upto 15 return (inputFrameId << 2) + joinIndex // allowing joinIndex upto 15
} }
func (pR *Room) OnBattleCmdReceived(pReq *WsReq) { func (pR *Room) OnBattleCmdReceived(pReq *pb.WsReq) {
/* /*
[WARNING] This function "OnBattleCmdReceived" could be called by different ws sessions and thus from different threads! [WARNING] This function "OnBattleCmdReceived" could be called by different ws sessions and thus from different threads!
@ -560,7 +549,7 @@ func (pR *Room) OnBattleCmdReceived(pReq *WsReq) {
} }
} }
func (pR *Room) onInputFrameDownsyncAllConfirmed(inputFrameDownsync *InputFrameDownsync, playerId int32) { func (pR *Room) onInputFrameDownsyncAllConfirmed(inputFrameDownsync *pb.InputFrameDownsync, playerId int32) {
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked! // [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
inputFrameId := inputFrameDownsync.InputFrameId inputFrameId := inputFrameDownsync.InputFrameId
if -1 == pR.LastAllConfirmedInputFrameIdWithChange || false == pR.equalInputLists(inputFrameDownsync.InputList, pR.LastAllConfirmedInputList) { if -1 == pR.LastAllConfirmedInputFrameIdWithChange || false == pR.equalInputLists(inputFrameDownsync.InputList, pR.LastAllConfirmedInputList) {
@ -603,7 +592,7 @@ func (pR *Room) StopBattleForSettlement() {
Logger.Info("Stopping the `battleMainLoop` for:", zap.Any("roomId", pR.Id)) Logger.Info("Stopping the `battleMainLoop` for:", zap.Any("roomId", pR.Id))
pR.RenderFrameId++ pR.RenderFrameId++
for playerId, _ := range pR.Players { for playerId, _ := range pR.Players {
assembledFrame := RoomDownsyncFrame{ assembledFrame := pb.RoomDownsyncFrame{
Id: pR.RenderFrameId, Id: pR.RenderFrameId,
Players: toPbPlayers(pR.Players, false), Players: toPbPlayers(pR.Players, false),
CountdownNanos: -1, // TODO: Replace this magic constant! CountdownNanos: -1, // TODO: Replace this magic constant!
@ -629,7 +618,7 @@ func (pR *Room) onBattlePrepare(cb BattleStartCbType) {
pR.State = RoomBattleStateIns.PREPARE pR.State = RoomBattleStateIns.PREPARE
Logger.Info("Battle state transitted to RoomBattleStateIns.PREPARE for:", zap.Any("roomId", pR.Id)) Logger.Info("Battle state transitted to RoomBattleStateIns.PREPARE for:", zap.Any("roomId", pR.Id))
battleReadyToStartFrame := &RoomDownsyncFrame{ battleReadyToStartFrame := &pb.RoomDownsyncFrame{
Id: DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START, Id: DOWNSYNC_MSG_ACT_BATTLE_READY_TO_START,
Players: toPbPlayers(pR.Players, true), Players: toPbPlayers(pR.Players, true),
CountdownNanos: pR.BattleDurationNanos, CountdownNanos: pR.BattleDurationNanos,
@ -714,10 +703,9 @@ func (pR *Room) OnDismissed() {
for _, oldChan := range pR.PlayerDownsyncChanDict { for _, oldChan := range pR.PlayerDownsyncChanDict {
close(oldChan) close(oldChan)
} }
pR.PlayerDownsyncChanDict = make(map[int32](chan InputsBufferSnapshot)) pR.PlayerDownsyncChanDict = make(map[int32](chan pb.InputsBufferSnapshot))
pR.PlayerSignalToCloseDict = make(map[int32]SignalToCloseConnCbType) pR.PlayerSignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
pR.JoinIndexBooleanArr = make([]bool, pR.Capacity) pR.JoinIndexBooleanArr = make([]bool, pR.Capacity)
pR.Barriers = make(map[int32]*Barrier)
pR.RenderCacheSize = 1024 pR.RenderCacheSize = 1024
pR.RenderFrameBuffer = NewRingBuffer(pR.RenderCacheSize) pR.RenderFrameBuffer = NewRingBuffer(pR.RenderCacheSize)
pR.InputsBuffer = NewRingBuffer((pR.RenderCacheSize >> 1) + 1) pR.InputsBuffer = NewRingBuffer((pR.RenderCacheSize >> 1) + 1)
@ -745,23 +733,15 @@ func (pR *Room) OnDismissed() {
pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work! pR.BackendDynamicsEnabled = true // [WARNING] When "false", recovery upon reconnection wouldn't work!
pR.ForceAllResyncOnAnyActiveSlowTicker = true // See tradeoff discussion in "downsyncToAllPlayers" pR.ForceAllResyncOnAnyActiveSlowTicker = true // See tradeoff discussion in "downsyncToAllPlayers"
punchSkillId := int32(1) punchSkillId := int32(1)
pR.MeleeSkillConfig = make(map[int32]*MeleeBullet, 0) pR.MeleeSkillConfig = make(map[int32]*pb.MeleeBullet, 0)
pR.MeleeSkillConfig[punchSkillId] = &MeleeBullet{ pR.MeleeSkillConfig[punchSkillId] = &pb.MeleeBullet{
// for offender // for offender
StartupFrames: int32(10), StartupFrames: int32(10),
ActiveFrames: int32(10), ActiveFrames: int32(10),
RecoveryFrames: int32(34), RecoveryFrames: int32(34),
RecoveryFramesOnBlock: int32(34), RecoveryFramesOnBlock: int32(34),
RecoveryFramesOnHit: int32(34), RecoveryFramesOnHit: int32(34),
Moveforward: &Vec2D{
X: 0,
Y: 0,
},
HitboxOffset: float64(12.0), // should be about the radius of the PlayerCollider HitboxOffset: float64(12.0), // should be about the radius of the PlayerCollider
HitboxSize: &Vec2D{
X: float64(24.0),
Y: float64(32.0),
},
// for defender // for defender
HitStunFrames: int32(18), HitStunFrames: int32(18),
@ -769,6 +749,11 @@ func (pR *Room) OnDismissed() {
Pushback: float64(8.0), Pushback: float64(8.0),
ReleaseTriggerType: int32(1), // 1: rising-edge, 2: falling-edge ReleaseTriggerType: int32(1), // 1: rising-edge, 2: falling-edge
Damage: int32(5), Damage: int32(5),
SelfMoveforwardX: 0,
SelfMoveforwardY: 0,
HitboxSizeX: 24.0,
HitboxSizeY: 32.0,
} }
pR.SnapIntoPlatformOverlap = float64(0.1) pR.SnapIntoPlatformOverlap = float64(0.1)
@ -893,16 +878,16 @@ func (pR *Room) onPlayerAdded(playerId int32) {
pR.JoinIndexBooleanArr[index] = true pR.JoinIndexBooleanArr[index] = true
// Lazily assign the initial position of "Player" for "RoomDownsyncFrame". // Lazily assign the initial position of "Player" for "RoomDownsyncFrame".
playerPosList := *(pR.StrToVec2DListMap["PlayerStartingPos"]) playerPosList := pR.TmxPointsMap["PlayerStartingPos"]
if index > len(playerPosList.Eles) { if index > len(playerPosList) {
panic(fmt.Sprintf("onPlayerAdded error, index >= len(playerPosList), roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount)) panic(fmt.Sprintf("onPlayerAdded error, index >= len(playerPosList), roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount))
} }
playerPos := playerPosList.Eles[index] playerPos := playerPosList[index]
if nil == playerPos { if nil == playerPos {
panic(fmt.Sprintf("onPlayerAdded error, nil == playerPos, roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount)) panic(fmt.Sprintf("onPlayerAdded error, nil == playerPos, roomId=%v, playerId=%v, roomState=%v, roomEffectivePlayerCount=%v", pR.Id, playerId, pR.State, pR.EffectivePlayerCount))
} }
pR.Players[playerId].VirtualGridX, pR.Players[playerId].VirtualGridY = WorldToVirtualGridPos(playerPos.X, playerPos.Y, pR.WorldToVirtualGridRatio) pR.Players[playerId].VirtualGridX, pR.Players[playerId].VirtualGridY = battle.WorldToVirtualGridPos(playerPos.X, playerPos.Y, pR.WorldToVirtualGridRatio)
// Hardcoded initial character orientation/facing // Hardcoded initial character orientation/facing
if 0 == (pR.Players[playerId].JoinIndex % 2) { if 0 == (pR.Players[playerId].JoinIndex % 2) {
pR.Players[playerId].DirX = -2 pR.Players[playerId].DirX = -2
@ -942,7 +927,7 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
targetPlayerBattleState := atomic.LoadInt32(&(targetPlayer.BattleState)) targetPlayerBattleState := atomic.LoadInt32(&(targetPlayer.BattleState))
switch targetPlayerBattleState { switch targetPlayerBattleState {
case PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK: case PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK:
playerAckedFrame := &RoomDownsyncFrame{ playerAckedFrame := &pb.RoomDownsyncFrame{
Id: pR.RenderFrameId, Id: pR.RenderFrameId,
Players: toPbPlayers(pR.Players, true), Players: toPbPlayers(pR.Players, true),
} }
@ -995,7 +980,7 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
return true return true
} }
func (pR *Room) sendSafely(roomDownsyncFrame *RoomDownsyncFrame, toSendInputFrameDownsyncs []*InputFrameDownsync, act int32, playerId int32, needLockExplicitly bool) { func (pR *Room) sendSafely(roomDownsyncFrame *pb.RoomDownsyncFrame, toSendInputFrameDownsyncs []*pb.InputFrameDownsync, act int32, playerId int32, needLockExplicitly bool) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
Logger.Error("sendSafely, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r)) Logger.Error("sendSafely, recovered from: ", zap.Any("roomId", pR.Id), zap.Any("playerId", playerId), zap.Any("panic", r))
@ -1003,7 +988,7 @@ func (pR *Room) sendSafely(roomDownsyncFrame *RoomDownsyncFrame, toSendInputFram
}() }()
if playerDownsyncSession, existent := pR.PlayerDownsyncSessionDict[playerId]; existent { if playerDownsyncSession, existent := pR.PlayerDownsyncSessionDict[playerId]; existent {
pResp := &WsResp{ pResp := &pb.WsResp{
Ret: int32(Constants.RetCode.Ok), Ret: int32(Constants.RetCode.Ok),
Act: act, Act: act,
Rdf: roomDownsyncFrame, Rdf: roomDownsyncFrame,
@ -1030,7 +1015,7 @@ func (pR *Room) shouldPrefabInputFrameDownsync(prevRenderFrameId int32, renderFr
return false, -1 return false, -1
} }
func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *InputFrameDownsync { func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *pb.InputFrameDownsync {
/* /*
[WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked. [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked.
@ -1039,12 +1024,12 @@ func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *InputFrameDow
- OR there's no change w.r.t. to its prev cmd. - OR there's no change w.r.t. to its prev cmd.
*/ */
var currInputFrameDownsync *InputFrameDownsync = nil var currInputFrameDownsync *pb.InputFrameDownsync = nil
tmp1 := pR.InputsBuffer.GetByFrameId(inputFrameId) // Would be nil if "pR.InputsBuffer.EdFrameId <= inputFrameId", else if "pR.InputsBuffer.EdFrameId > inputFrameId" is already met, then by now we can just return "tmp1.(*InputFrameDownsync)" tmp1 := pR.InputsBuffer.GetByFrameId(inputFrameId) // Would be nil if "pR.InputsBuffer.EdFrameId <= inputFrameId", else if "pR.InputsBuffer.EdFrameId > inputFrameId" is already met, then by now we can just return "tmp1.(*InputFrameDownsync)"
if nil == tmp1 { if nil == tmp1 {
for pR.InputsBuffer.EdFrameId <= inputFrameId { for pR.InputsBuffer.EdFrameId <= inputFrameId {
j := pR.InputsBuffer.EdFrameId j := pR.InputsBuffer.EdFrameId
currInputFrameDownsync = &InputFrameDownsync{ currInputFrameDownsync = &pb.InputFrameDownsync{
InputFrameId: j, InputFrameId: j,
InputList: make([]uint64, pR.Capacity), InputList: make([]uint64, pR.Capacity),
ConfirmedList: uint64(0), ConfirmedList: uint64(0),
@ -1056,7 +1041,7 @@ func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *InputFrameDow
} }
tmp2 := pR.InputsBuffer.GetByFrameId(j2) tmp2 := pR.InputsBuffer.GetByFrameId(j2)
if nil != tmp2 { if nil != tmp2 {
prevInputFrameDownsync := tmp2.(*InputFrameDownsync) prevInputFrameDownsync := tmp2.(*pb.InputFrameDownsync)
for i, _ := range currInputFrameDownsync.InputList { for i, _ := range currInputFrameDownsync.InputList {
currInputFrameDownsync.InputList[i] = (prevInputFrameDownsync.InputList[i] & uint64(15)) // Don't predict attack input! currInputFrameDownsync.InputList[i] = (prevInputFrameDownsync.InputList[i] & uint64(15)) // Don't predict attack input!
} }
@ -1065,13 +1050,13 @@ func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *InputFrameDow
pR.InputsBuffer.Put(currInputFrameDownsync) pR.InputsBuffer.Put(currInputFrameDownsync)
} }
} else { } else {
currInputFrameDownsync = tmp1.(*InputFrameDownsync) currInputFrameDownsync = tmp1.(*pb.InputFrameDownsync)
} }
return currInputFrameDownsync return currInputFrameDownsync
} }
func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*InputFrameUpsync, playerId int32, player *Player) *InputsBufferSnapshot { func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*pb.InputFrameUpsync, playerId int32, player *Player) *pb.InputsBufferSnapshot {
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked! // [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
// Step#1, put the received "inputFrameUpsyncBatch" into "pR.InputsBuffer" // Step#1, put the received "inputFrameUpsyncBatch" into "pR.InputsBuffer"
for _, inputFrameUpsync := range inputFrameUpsyncBatch { for _, inputFrameUpsync := range inputFrameUpsyncBatch {
@ -1111,7 +1096,7 @@ func (pR *Room) markConfirmationIfApplicable(inputFrameUpsyncBatch []*InputFrame
panic(fmt.Sprintf("inputFrameId=%v doesn't exist for roomId=%v! InputsBuffer=%v", inputFrameId, pR.Id, pR.InputsBufferString(false))) panic(fmt.Sprintf("inputFrameId=%v doesn't exist for roomId=%v! InputsBuffer=%v", inputFrameId, pR.Id, pR.InputsBufferString(false)))
} }
shouldBreakConfirmation := false shouldBreakConfirmation := false
inputFrameDownsync := tmp.(*InputFrameDownsync) inputFrameDownsync := tmp.(*pb.InputFrameDownsync)
if allConfirmedMask != inputFrameDownsync.ConfirmedList { if allConfirmedMask != inputFrameDownsync.ConfirmedList {
for _, player := range pR.PlayersArr { for _, player := range pR.PlayersArr {
@ -1170,7 +1155,7 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) uint64 {
if nil == tmp { if nil == tmp {
panic(fmt.Sprintf("inputFrameId=%v doesn't exist for roomId=%v! InputsBuffer=%v", j, pR.Id, pR.InputsBufferString(false))) panic(fmt.Sprintf("inputFrameId=%v doesn't exist for roomId=%v! InputsBuffer=%v", j, pR.Id, pR.InputsBufferString(false)))
} }
inputFrameDownsync := tmp.(*InputFrameDownsync) inputFrameDownsync := tmp.(*pb.InputFrameDownsync)
unconfirmedMask |= (allConfirmedMask ^ inputFrameDownsync.ConfirmedList) unconfirmedMask |= (allConfirmedMask ^ inputFrameDownsync.ConfirmedList)
inputFrameDownsync.ConfirmedList = allConfirmedMask inputFrameDownsync.ConfirmedList = allConfirmedMask
pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, -1) pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, -1)
@ -1197,7 +1182,7 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) uint64 {
return unconfirmedMask return unconfirmedMask
} }
func (pR *Room) produceInputsBufferSnapshotWithCurDynamicsRenderFrameAsRef(unconfirmedMask uint64, snapshotStFrameId, snapshotEdFrameId int32) *InputsBufferSnapshot { func (pR *Room) produceInputsBufferSnapshotWithCurDynamicsRenderFrameAsRef(unconfirmedMask uint64, snapshotStFrameId, snapshotEdFrameId int32) *pb.InputsBufferSnapshot {
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked! // [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
refRenderFrameIdIfNeeded := pR.CurDynamicsRenderFrameId - 1 refRenderFrameIdIfNeeded := pR.CurDynamicsRenderFrameId - 1
if 0 > refRenderFrameIdIfNeeded { if 0 > refRenderFrameIdIfNeeded {
@ -1206,7 +1191,7 @@ func (pR *Room) produceInputsBufferSnapshotWithCurDynamicsRenderFrameAsRef(uncon
// Duplicate downsynced inputFrameIds will be filtered out by frontend. // Duplicate downsynced inputFrameIds will be filtered out by frontend.
toSendInputFrameDownsyncs := pR.cloneInputsBuffer(snapshotStFrameId, snapshotEdFrameId) toSendInputFrameDownsyncs := pR.cloneInputsBuffer(snapshotStFrameId, snapshotEdFrameId)
return &InputsBufferSnapshot{ return &pb.InputsBufferSnapshot{
RefRenderFrameId: refRenderFrameIdIfNeeded, RefRenderFrameId: refRenderFrameIdIfNeeded,
UnconfirmedMask: unconfirmedMask, UnconfirmedMask: unconfirmedMask,
ToSendInputFrameDownsyncs: toSendInputFrameDownsyncs, ToSendInputFrameDownsyncs: toSendInputFrameDownsyncs,
@ -1228,9 +1213,9 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
if nil == currRenderFrameTmp { if nil == currRenderFrameTmp {
panic(fmt.Sprintf("collisionSysRenderFrameId=%v doesn't exist for roomId=%v, this is abnormal because it's to be used for applying dynamics to [fromRenderFrameId:%v, toRenderFrameId:%v)! RenderFrameBuffer=%v", collisionSysRenderFrameId, pR.Id, fromRenderFrameId, toRenderFrameId, pR.RenderFrameBufferString())) panic(fmt.Sprintf("collisionSysRenderFrameId=%v doesn't exist for roomId=%v, this is abnormal because it's to be used for applying dynamics to [fromRenderFrameId:%v, toRenderFrameId:%v)! RenderFrameBuffer=%v", collisionSysRenderFrameId, pR.Id, fromRenderFrameId, toRenderFrameId, pR.RenderFrameBufferString()))
} }
currRenderFrame := currRenderFrameTmp.(*RoomDownsyncFrame) currRenderFrame := currRenderFrameTmp.(*battle.RoomDownsyncFrame)
delayedInputFrameId := pR.ConvertToInputFrameId(collisionSysRenderFrameId, pR.InputDelayFrames) delayedInputFrameId := pR.ConvertToInputFrameId(collisionSysRenderFrameId, pR.InputDelayFrames)
var delayedInputFrame *InputFrameDownsync = nil var delayedInputFrame *pb.InputFrameDownsync = nil
if 0 <= delayedInputFrameId { if 0 <= delayedInputFrameId {
if delayedInputFrameId > pR.LastAllConfirmedInputFrameId { if delayedInputFrameId > pR.LastAllConfirmedInputFrameId {
panic(fmt.Sprintf("delayedInputFrameId=%v is not yet all-confirmed for roomId=%v, this is abnormal because it's to be used for applying dynamics to [fromRenderFrameId:%v, toRenderFrameId:%v) @ collisionSysRenderFrameId=%v! InputsBuffer=%v", delayedInputFrameId, pR.Id, fromRenderFrameId, toRenderFrameId, collisionSysRenderFrameId, pR.InputsBufferString(false))) panic(fmt.Sprintf("delayedInputFrameId=%v is not yet all-confirmed for roomId=%v, this is abnormal because it's to be used for applying dynamics to [fromRenderFrameId:%v, toRenderFrameId:%v) @ collisionSysRenderFrameId=%v! InputsBuffer=%v", delayedInputFrameId, pR.Id, fromRenderFrameId, toRenderFrameId, collisionSysRenderFrameId, pR.InputsBufferString(false)))
@ -1239,7 +1224,7 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
if nil == tmp { if nil == tmp {
panic(fmt.Sprintf("delayedInputFrameId=%v doesn't exist for roomId=%v, this is abnormal because it's to be used for applying dynamics to [fromRenderFrameId:%v, toRenderFrameId:%v) @ collisionSysRenderFrameId=%v! InputsBuffer=%v", delayedInputFrameId, pR.Id, fromRenderFrameId, toRenderFrameId, collisionSysRenderFrameId, pR.InputsBufferString(false))) panic(fmt.Sprintf("delayedInputFrameId=%v doesn't exist for roomId=%v, this is abnormal because it's to be used for applying dynamics to [fromRenderFrameId:%v, toRenderFrameId:%v) @ collisionSysRenderFrameId=%v! InputsBuffer=%v", delayedInputFrameId, pR.Id, fromRenderFrameId, toRenderFrameId, collisionSysRenderFrameId, pR.InputsBufferString(false)))
} }
delayedInputFrame = tmp.(*InputFrameDownsync) delayedInputFrame = tmp.(*pb.InputFrameDownsync)
// [WARNING] It's possible that by now "allConfirmedMask != delayedInputFrame.ConfirmedList && delayedInputFrameId <= pR.LastAllConfirmedInputFrameId", we trust "pR.LastAllConfirmedInputFrameId" as the TOP AUTHORITY. // [WARNING] It's possible that by now "allConfirmedMask != delayedInputFrame.ConfirmedList && delayedInputFrameId <= pR.LastAllConfirmedInputFrameId", we trust "pR.LastAllConfirmedInputFrameId" as the TOP AUTHORITY.
delayedInputFrame.ConfirmedList = allConfirmedMask delayedInputFrame.ConfirmedList = allConfirmedMask
} }
@ -1250,370 +1235,6 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
} }
} }
// TODO: Write unit-test for this function to compare with its frontend counter part
func (pR *Room) applyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSysMap map[int32]*resolv.Object) *RoomDownsyncFrame {
topPadding, bottomPadding, leftPadding, rightPadding := pR.SnapIntoPlatformOverlap, pR.SnapIntoPlatformOverlap, pR.SnapIntoPlatformOverlap, pR.SnapIntoPlatformOverlap
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
nextRenderFramePlayers := make(map[int32]*PlayerDownsync, pR.Capacity)
// Make a copy first
for playerId, currPlayerDownsync := range currRenderFrame.Players {
nextRenderFramePlayers[playerId] = &PlayerDownsync{
Id: playerId,
VirtualGridX: currPlayerDownsync.VirtualGridX,
VirtualGridY: currPlayerDownsync.VirtualGridY,
DirX: currPlayerDownsync.DirX,
DirY: currPlayerDownsync.DirY,
VelX: currPlayerDownsync.VelX,
VelY: currPlayerDownsync.VelY,
CharacterState: currPlayerDownsync.CharacterState,
InAir: true,
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
}
}
nextRenderFrameMeleeBullets := make([]*MeleeBullet, 0, len(currRenderFrame.MeleeBullets)) // Is there any better way to reduce malloc/free impact, e.g. smart prediction for fixed memory allocation?
effPushbacks := make([]Vec2D, pR.Capacity)
hardPushbackNorms := make([][]Vec2D, pR.Capacity)
// 1. Process player inputs
if nil != delayedInputFrame {
var delayedInputFrameForPrevRenderFrame *InputFrameDownsync = nil
tmp := pR.InputsBuffer.GetByFrameId(pR.ConvertToInputFrameId(currRenderFrame.Id-1, pR.InputDelayFrames))
if nil != tmp {
delayedInputFrameForPrevRenderFrame = tmp.(*InputFrameDownsync)
}
inputList := delayedInputFrame.InputList
for _, player := range pR.PlayersArr {
playerId := player.Id
joinIndex := player.JoinIndex
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
if 0 < thatPlayerInNextFrame.FramesToRecover {
continue
}
decodedInput := pR.decodeInput(inputList[joinIndex-1])
prevBtnALevel, prevBtnBLevel := int32(0), int32(0)
if nil != delayedInputFrameForPrevRenderFrame {
prevDecodedInput := pR.decodeInput(delayedInputFrameForPrevRenderFrame.InputList[joinIndex-1])
prevBtnALevel = prevDecodedInput.BtnALevel
prevBtnBLevel = prevDecodedInput.BtnBLevel
}
if decodedInput.BtnBLevel > prevBtnBLevel {
characStateAlreadyInAir := false
if ATK_CHARACTER_STATE_INAIR_IDLE1 == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_INAIR_ATK1 == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_INAIR_ATKED1 == thatPlayerInNextFrame.CharacterState {
characStateAlreadyInAir = true
}
characStateIsInterruptWaivable := false
if ATK_CHARACTER_STATE_IDLE1 == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_WALKING == thatPlayerInNextFrame.CharacterState || ATK_CHARACTER_STATE_INAIR_IDLE1 == thatPlayerInNextFrame.CharacterState {
characStateIsInterruptWaivable = true
}
if !characStateAlreadyInAir && characStateIsInterruptWaivable {
thatPlayerInNextFrame.VelY = pR.JumpingInitVelY
if 1 == currPlayerDownsync.JoinIndex {
Logger.Info(fmt.Sprintf("playerId=%v, joinIndex=%v jumped at {renderFrame.id: %d, virtualX: %d, virtualY: %d, nextVelX: %d, nextVelY: %d, nextCharacterState=%d, inAir=%v}, delayedInputFrame.id=%d", playerId, joinIndex, currRenderFrame.Id, currPlayerDownsync.VirtualGridX, currPlayerDownsync.VirtualGridY, thatPlayerInNextFrame.VelX, thatPlayerInNextFrame.VelY, thatPlayerInNextFrame.CharacterState, currPlayerDownsync.InAir, delayedInputFrame.InputFrameId))
}
}
}
if decodedInput.BtnALevel > prevBtnALevel {
punchSkillId := int32(1)
punchConfig := pR.MeleeSkillConfig[punchSkillId]
var newMeleeBullet MeleeBullet = *punchConfig
newMeleeBullet.BattleLocalId = pR.BulletBattleLocalIdCounter
pR.BulletBattleLocalIdCounter += 1
newMeleeBullet.OffenderJoinIndex = joinIndex
newMeleeBullet.OffenderPlayerId = playerId
newMeleeBullet.OriginatedRenderFrameId = currRenderFrame.Id
nextRenderFrameMeleeBullets = append(nextRenderFrameMeleeBullets, &newMeleeBullet)
thatPlayerInNextFrame.FramesToRecover = newMeleeBullet.RecoveryFrames
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATK1
if false == currPlayerDownsync.InAir {
thatPlayerInNextFrame.VelX = 0
}
Logger.Debug(fmt.Sprintf("roomId=%v, playerId=%v triggered a rising-edge of btnA at currRenderFrame.id=%v, delayedInputFrame.id=%v", pR.Id, playerId, currRenderFrame.Id, delayedInputFrame.InputFrameId))
} else if decodedInput.BtnALevel < prevBtnALevel {
Logger.Debug(fmt.Sprintf("roomId=%v, playerId=%v triggered a falling-edge of btnA at currRenderFrame.id=%v, delayedInputFrame.id=%v", pR.Id, playerId, currRenderFrame.Id, delayedInputFrame.InputFrameId))
} else {
// No bullet trigger, process movement inputs
// Note that by now "0 == thatPlayerInNextFrame.FramesToRecover", we should change "CharacterState" to "WALKING" or "IDLE" depending on player inputs
if 0 != decodedInput.Dx || 0 != decodedInput.Dy {
thatPlayerInNextFrame.DirX = decodedInput.Dx
thatPlayerInNextFrame.DirY = decodedInput.Dy
thatPlayerInNextFrame.VelX = decodedInput.Dx * currPlayerDownsync.Speed
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_WALKING
} else {
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
thatPlayerInNextFrame.VelX = 0
}
}
}
}
// 2. Process player movement
for _, player := range pR.PlayersArr {
playerId := player.Id
joinIndex := player.JoinIndex
effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y = float64(0), float64(0)
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
playerCollider := collisionSysMap[collisionPlayerIndex]
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
// Reset playerCollider position from the "virtual grid position"
newVx, newVy := currPlayerDownsync.VirtualGridX+currPlayerDownsync.VelX, currPlayerDownsync.VirtualGridY+currPlayerDownsync.VelY
if thatPlayerInNextFrame.VelY == pR.JumpingInitVelY {
newVy += thatPlayerInNextFrame.VelY
}
halfColliderWidth, halfColliderHeight := player.ColliderRadius, player.ColliderRadius+player.ColliderRadius // avoid multiplying
playerCollider.X, playerCollider.Y = VirtualGridToPolygonColliderBLPos(newVx, newVy, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, pR.VirtualGridToWorldRatio)
// Update in the collision system
playerCollider.Update()
if currPlayerDownsync.InAir {
thatPlayerInNextFrame.VelX += pR.GravityX
thatPlayerInNextFrame.VelY += pR.GravityY
}
}
// 3. Add bullet colliders into collision system
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 := float64(1.0) // By now, straight Punch offset doesn't respect "y-axis"
if 0 > offender.DirX {
xfac = float64(-1.0)
}
offenderWx, offenderWy := VirtualGridToWorldPos(offender.VirtualGridX, offender.VirtualGridY, pR.VirtualGridToWorldRatio)
bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSize.X, meleeBullet.HitboxSize.Y, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, meleeBullet, "MeleeBullet")
pR.Space.Add(newBulletCollider)
collisionSysMap[collisionBulletIndex] = newBulletCollider
bulletColliders[collisionBulletIndex] = newBulletCollider
Logger.Debug(fmt.Sprintf("roomId=%v, a meleeBullet is added to collisionSys at currRenderFrame.id=%v as start-up frames ended and active frame is not yet ended: %v, from offenderCollider=%v, xfac=%v", pR.Id, currRenderFrame.Id, ConvexPolygonStr(newBulletCollider.Shape.(*resolv.ConvexPolygon)), ConvexPolygonStr(offenderCollider.Shape.(*resolv.ConvexPolygon)), xfac))
}
}
// 4. Invoke collision system stepping (no-op for backend collision lib)
// 5. Calc pushbacks for each player (after its movement) w/o bullets
for _, player := range pR.PlayersArr {
joinIndex := player.JoinIndex
playerId := player.Id
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
playerCollider := collisionSysMap[collisionPlayerIndex]
playerShape := playerCollider.Shape.(*resolv.ConvexPolygon)
hardPushbackNorms[joinIndex-1] = pR.calcHardPushbacksNorms(playerCollider, playerShape, pR.SnapIntoPlatformOverlap, &(effPushbacks[joinIndex-1]))
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
fallStopping := false
possiblyFallStoppedOnAnotherPlayer := false
if collision := playerCollider.Check(0, 0); nil != collision {
for _, obj := range collision.Objects {
isBarrier, isAnotherPlayer, isBullet := false, false, false
switch obj.Data.(type) {
case *Barrier:
isBarrier = true
case *Player:
isAnotherPlayer = true
case *MeleeBullet:
isBullet = true
}
if isBullet {
// ignore bullets for this step
continue
}
bShape := obj.Shape.(*resolv.ConvexPolygon)
overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, bShape)
if !overlapped {
continue
}
normAlignmentWithGravity := (overlapResult.OverlapX*float64(0) + overlapResult.OverlapY*float64(-1.0))
landedOnGravityPushback := (pR.SnapIntoPlatformThreshold < normAlignmentWithGravity) // prevents false snapping on the lateral sides
if landedOnGravityPushback {
// kindly note that one player might land on top of another player, and snapping is also required in such case
pushbackX, pushbackY = (overlapResult.Overlap-pR.SnapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-pR.SnapIntoPlatformOverlap)*overlapResult.OverlapY
thatPlayerInNextFrame.InAir = false
}
if isAnotherPlayer {
// [WARNING] See comments of this substep in frontend.
pushbackX, pushbackY = (overlapResult.Overlap-pR.SnapIntoPlatformOverlap*2)*overlapResult.OverlapX, (overlapResult.Overlap-pR.SnapIntoPlatformOverlap*2)*overlapResult.OverlapY
}
for _, hardPushbackNorm := range hardPushbackNorms[joinIndex-1] {
projectedMagnitude := pushbackX*hardPushbackNorm.X + pushbackY*hardPushbackNorm.Y
if isBarrier || (isAnotherPlayer && 0 > projectedMagnitude) {
pushbackX -= projectedMagnitude * hardPushbackNorm.X
pushbackY -= projectedMagnitude * hardPushbackNorm.Y
}
}
effPushbacks[joinIndex-1].X += pushbackX
effPushbacks[joinIndex-1].Y += pushbackY
if currPlayerDownsync.InAir && landedOnGravityPushback {
fallStopping = true
if isAnotherPlayer {
possiblyFallStoppedOnAnotherPlayer = true
}
}
if 1 == joinIndex {
halfColliderWidth, halfColliderHeight := player.ColliderRadius, player.ColliderRadius+player.ColliderRadius // avoid multiplying
if fallStopping {
Logger.Debug(fmt.Sprintf("playerId=%d, joinIndex=%d fallStopping#1\n{renderFrame.id: %d, possiblyFallStoppedOnAnotherPlayer: %v}\nplayerColliderPos=%v, effPushback={%.3f, %.3f}, overlapMag=%.4f", playerId, joinIndex, currRenderFrame.Id, possiblyFallStoppedOnAnotherPlayer, RectCenterStr(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y, overlapResult.Overlap))
} else if currPlayerDownsync.InAir && isBarrier && !landedOnGravityPushback {
//Logger.Warn(fmt.Sprintf("playerId=%d, joinIndex=%d inAir & pushed back by barrier & not landed at {renderFrame.id: %d}\nplayerColliderPos=%v, effPushback={%.3f, %.3f}, overlapMag=%.4f, len(hardPushbackNorms)=%d", playerId, joinIndex, currRenderFrame.Id, RectCenterStr(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y, overlapResult.Overlap, len(hardPushbackNorms)))
} else if currPlayerDownsync.InAir && isAnotherPlayer {
//Logger.Warn(fmt.Sprintf("playerId=%d, joinIndex=%d inAir & pushed back by another player\n{renderFrame.id: %d}\nplayerColliderPos=%v, anotherPlayerColliderPos=%v, effPushback={%.3f, %.3f}, landedOnGravityPushback=%v, fallStopping=%v, overlapMag=%.4f, len(hardPushbackNorms)=%d", playerId, joinIndex, currRenderFrame.Id, RectCenterStr(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), RectCenterStr(obj, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y, landedOnGravityPushback, fallStopping, overlapResult.Overlap, len(hardPushbackNorms)))
}
}
}
}
if fallStopping {
thatPlayerInNextFrame.VelX = 0
thatPlayerInNextFrame.VelY = 0
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_IDLE1
thatPlayerInNextFrame.FramesToRecover = 0
}
if currPlayerDownsync.InAir {
oldNextCharacterState := thatPlayerInNextFrame.CharacterState
switch oldNextCharacterState {
case ATK_CHARACTER_STATE_IDLE1, ATK_CHARACTER_STATE_WALKING:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_IDLE1
case ATK_CHARACTER_STATE_ATK1:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATK1
case ATK_CHARACTER_STATE_ATKED1:
thatPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATKED1
}
}
}
// 6. Check bullet-anything collisions
for _, bulletCollider := range bulletColliders {
shouldRemove := false
meleeBullet := bulletCollider.Data.(*MeleeBullet)
collisionBulletIndex := COLLISION_BULLET_INDEX_PREFIX + meleeBullet.BattleLocalId
bulletShape := bulletCollider.Shape.(*resolv.ConvexPolygon)
if collision := bulletCollider.Check(0, 0); collision != nil {
offender := currRenderFrame.Players[meleeBullet.OffenderPlayerId]
for _, obj := range collision.Objects {
defenderShape := obj.Shape.(*resolv.ConvexPolygon)
switch t := obj.Data.(type) {
case *Player:
if meleeBullet.OffenderPlayerId != t.Id {
if overlapped, _, _, _ := CalcPushbacks(0, 0, bulletShape, defenderShape); overlapped {
joinIndex := t.JoinIndex
xfac := float64(1.0) // By now, straight Punch offset doesn't respect "y-axis"
if 0 > offender.DirX {
xfac = float64(-1.0)
}
pushbackX, pushbackY := -xfac*meleeBullet.Pushback, float64(0)
for _, hardPushbackNorm := range hardPushbackNorms[joinIndex-1] {
projectedMagnitude := pushbackX*hardPushbackNorm.X + pushbackY*hardPushbackNorm.Y
if 0 > projectedMagnitude {
//Logger.Debug(fmt.Sprintf("defenderPlayerId=%d, joinIndex=%d reducing bullet pushback={%.3f, %.3f} by {%.3f, %.3f} where hardPushbackNorm={%.3f, %.3f}, projectedMagnitude=%.3f at renderFrame.id=%d", t.Id, joinIndex, pushbackX, pushbackY, projectedMagnitude*hardPushbackNorm.X, projectedMagnitude*hardPushbackNorm.Y, hardPushbackNorm.X, hardPushbackNorm.Y, projectedMagnitude, currRenderFrame.Id))
pushbackX -= projectedMagnitude * hardPushbackNorm.X
pushbackY -= projectedMagnitude * hardPushbackNorm.Y
}
}
effPushbacks[joinIndex-1].X += pushbackX
effPushbacks[joinIndex-1].Y += pushbackY
atkedPlayerInCurFrame, atkedPlayerInNextFrame := currRenderFrame.Players[t.Id], nextRenderFramePlayers[t.Id]
atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_ATKED1
if atkedPlayerInCurFrame.InAir {
atkedPlayerInNextFrame.CharacterState = ATK_CHARACTER_STATE_INAIR_ATKED1
}
oldFramesToRecover := nextRenderFramePlayers[t.Id].FramesToRecover
if meleeBullet.HitStunFrames > oldFramesToRecover {
atkedPlayerInNextFrame.FramesToRecover = meleeBullet.HitStunFrames
}
Logger.Debug(fmt.Sprintf("roomId=%v, a meleeBullet collides w/ player at currRenderFrame.id=%v: b=%v, p=%v", pR.Id, currRenderFrame.Id, ConvexPolygonStr(bulletShape), ConvexPolygonStr(defenderShape)))
}
}
default:
Logger.Debug(fmt.Sprintf("Bullet %v collided with non-player %v: roomId=%v, currRenderFrame.Id=%v, delayedInputFrame.Id=%v, objDataType=%t, objData=%v", ConvexPolygonStr(bulletShape), ConvexPolygonStr(defenderShape), pR.Id, currRenderFrame.Id, delayedInputFrame.InputFrameId, obj.Data, obj.Data))
}
}
shouldRemove = true
}
if shouldRemove {
removedBulletsAtCurrFrame[collisionBulletIndex] = 1
}
}
// [WARNING] Remove bullets from collisionSys ANYWAY for the convenience of rollback
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
}
nextRenderFrameMeleeBullets = append(nextRenderFrameMeleeBullets, meleeBullet)
}
// 7. Get players out of stuck barriers if there's any
for _, player := range pR.PlayersArr {
joinIndex := player.JoinIndex
playerId := player.Id
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
playerCollider := collisionSysMap[collisionPlayerIndex]
// Update "virtual grid position"
currPlayerDownsync, thatPlayerInNextFrame := currRenderFrame.Players[playerId], nextRenderFramePlayers[playerId]
halfColliderWidth, halfColliderHeight := player.ColliderRadius, player.ColliderRadius+player.ColliderRadius // avoid multiplying
thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY = PolygonColliderBLToVirtualGridPos(playerCollider.X-effPushbacks[joinIndex-1].X, playerCollider.Y-effPushbacks[joinIndex-1].Y, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, pR.WorldToVirtualGridRatio)
if 1 == thatPlayerInNextFrame.JoinIndex {
if currPlayerDownsync.InAir && !thatPlayerInNextFrame.InAir {
Logger.Warn(fmt.Sprintf("playerId=%d, joinIndex=%d fallStopping#2:\n{nextRenderFrame.id: %d, nextVirtualX: %d, nextVirtualY: %d, nextVelX: %d, nextVelY: %d}\n\tcalculated from <- playerColliderPos=%v, effPushback={%.3f, %.3f}", playerId, joinIndex, currRenderFrame.Id+1, thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY, thatPlayerInNextFrame.VelX, thatPlayerInNextFrame.VelY, RectCenterStr(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y))
} else if !currPlayerDownsync.InAir && thatPlayerInNextFrame.InAir {
Logger.Warn(fmt.Sprintf("playerId=%d, joinIndex=%d took off:\n{nextRenderFrame.id: %d, nextVirtualX: %d, nextVirtualY: %d, nextVelX: %d, nextVelY: %d}\n\tcalculated from <- playerColliderPos=%v, effPushback={%.3f, %.3f}", playerId, joinIndex, currRenderFrame.Id+1, thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY, thatPlayerInNextFrame.VelX, thatPlayerInNextFrame.VelY, RectCenterStr(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y))
} else if thatPlayerInNextFrame.InAir && (0 != thatPlayerInNextFrame.VelY) {
//Logger.Info(fmt.Sprintf("playerId=%d, joinIndex=%d inAir trajectory:\n{nextRenderFrame.id: %d, nextVirtualX: %d, nextVirtualY: %d, nextVelX: %d, nextVelY: %d}\n\tcalculated from <- playerColliderPos=%v, effPushback={%.3f, %.3f}", playerId, joinIndex, currRenderFrame.Id+1, thatPlayerInNextFrame.VirtualGridX, thatPlayerInNextFrame.VirtualGridY, thatPlayerInNextFrame.VelX, thatPlayerInNextFrame.VelY, RectCenterStr(playerCollider, halfColliderWidth, halfColliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY), effPushbacks[joinIndex-1].X, effPushbacks[joinIndex-1].Y))
}
}
}
return &RoomDownsyncFrame{
Id: currRenderFrame.Id + 1,
Players: nextRenderFramePlayers,
MeleeBullets: nextRenderFrameMeleeBullets,
CountdownNanos: (pR.BattleDurationNanos - int64(currRenderFrame.Id)*pR.RollbackEstimatedDtNanos),
}
}
func (pR *Room) decodeInput(encodedInput uint64) *InputFrameDecoded {
encodedDirection := (encodedInput & uint64(15))
btnALevel := int32((encodedInput >> 4) & 1)
btnBLevel := int32((encodedInput >> 5) & 1)
return &InputFrameDecoded{
Dx: DIRECTION_DECODER[encodedDirection][0],
Dy: DIRECTION_DECODER[encodedDirection][1],
BtnALevel: btnALevel,
BtnBLevel: btnBLevel,
}
}
func (pR *Room) inputFrameIdDebuggable(inputFrameId int32) bool {
return 0 == (inputFrameId % 10)
}
func (pR *Room) refreshColliders(spaceW, spaceH int32) { func (pR *Room) refreshColliders(spaceW, spaceH int32) {
// Kindly note that by now, we've already got all the shapes in the tmx file into "pR.(Players | Barriers)" from "ParseTmxLayersAndGroups" // Kindly note that by now, we've already got all the shapes in the tmx file into "pR.(Players | Barriers)" from "ParseTmxLayersAndGroups"
@ -1621,21 +1242,30 @@ func (pR *Room) refreshColliders(spaceW, spaceH int32) {
minStep := (int(float64(pR.PlayerDefaultSpeed)*pR.VirtualGridToWorldRatio) << 3) // the approx minimum distance a player can move per frame in world coordinate minStep := (int(float64(pR.PlayerDefaultSpeed)*pR.VirtualGridToWorldRatio) << 3) // the approx minimum distance a player can move per frame in world coordinate
pR.Space = resolv.NewSpace(int(spaceW), int(spaceH), minStep, minStep) // allocate a new collision space everytime after a battle is settled pR.Space = resolv.NewSpace(int(spaceW), int(spaceH), minStep, minStep) // allocate a new collision space everytime after a battle is settled
for _, player := range pR.Players { jsPlayers := toJsPlayers(pR.Players, false)
wx, wy := VirtualGridToWorldPos(player.VirtualGridX, player.VirtualGridY, pR.VirtualGridToWorldRatio) for _, player := range jsPlayers {
wx, wy := battle.VirtualGridToWorldPos(player.VirtualGridX, player.VirtualGridY, pR.VirtualGridToWorldRatio)
colliderWidth, colliderHeight := player.ColliderRadius*2, player.ColliderRadius*4 colliderWidth, colliderHeight := player.ColliderRadius*2, player.ColliderRadius*4
playerCollider := GenerateRectCollider(wx, wy, colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, player, "Player") // the coords of all barrier boundaries are multiples of tileWidth(i.e. 16), by adding snapping y-padding when "landedOnGravityPushback" all "playerCollider.Y" would be a multiple of 1.0 playerCollider := battle.GenerateRectCollider(wx, wy, colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, player, "Player") // the coords of all barrier boundaries are multiples of tileWidth(i.e. 16), by adding snapping y-padding when "landedOnGravityPushback" all "playerCollider.Y" would be a multiple of 1.0
pR.Space.Add(playerCollider) pR.Space.Add(playerCollider)
// Keep track of the collider in "pR.CollisionSysMap" // Keep track of the collider in "pR.CollisionSysMap"
joinIndex := player.JoinIndex joinIndex := player.JoinIndex
pR.PlayersArr[joinIndex-1] = player collisionPlayerIndex := battle.COLLISION_PLAYER_INDEX_PREFIX + joinIndex
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
pR.CollisionSysMap[collisionPlayerIndex] = playerCollider pR.CollisionSysMap[collisionPlayerIndex] = playerCollider
} }
for _, barrier := range pR.Barriers { for _, player := range pR.Players {
boundaryUnaligned := barrier.Boundary joinIndex := player.JoinIndex
barrierCollider := GenerateConvexPolygonCollider(boundaryUnaligned, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, barrier, "Barrier") pR.PlayersArr[joinIndex-1] = player
}
barrierPolygon2DList := pR.TmxPolygonsMap["Barrier"]
for _, polygon2DUnaligned := range barrierPolygon2DList {
/*
// For debug-printing only.
Logger.Info("ChooseStage printing polygon2D for barrierPolygon2DList", zap.Any("barrierLocalIdInBattle", barrierLocalIdInBattle), zap.Any("polygon2D.Anchor", polygon2D.Anchor), zap.Any("polygon2D.Points", polygon2D.Points))
*/
barrierCollider := battle.GenerateConvexPolygonCollider(polygon2DUnaligned, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, nil, "Barrier")
pR.Space.Add(barrierCollider) pR.Space.Add(barrierCollider)
} }
} }
@ -1695,7 +1325,7 @@ func (pR *Room) doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRend
} }
} }
func (pR *Room) downsyncToAllPlayers(inputsBufferSnapshot *InputsBufferSnapshot) { func (pR *Room) downsyncToAllPlayers(inputsBufferSnapshot *pb.InputsBufferSnapshot) {
/* /*
[WARNING] This function MUST BE called while "pR.InputsBufferLock" is LOCKED to **preserve the order of generation of "inputsBufferSnapshot" for sending** -- see comments in "OnBattleCmdReceived" and [this issue](https://github.com/genxium/DelayNoMore/issues/12). [WARNING] This function MUST BE called while "pR.InputsBufferLock" is LOCKED to **preserve the order of generation of "inputsBufferSnapshot" for sending** -- see comments in "OnBattleCmdReceived" and [this issue](https://github.com/genxium/DelayNoMore/issues/12).
@ -1764,7 +1394,7 @@ func (pR *Room) downsyncToAllPlayers(inputsBufferSnapshot *InputsBufferSnapshot)
} }
} }
func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRenderFrameId int32, unconfirmedMask uint64, toSendInputFrameDownsyncsSnapshot []*InputFrameDownsync, shouldForceResync bool) { func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRenderFrameId int32, unconfirmedMask uint64, toSendInputFrameDownsyncsSnapshot []*pb.InputFrameDownsync, shouldForceResync bool) {
/* /*
[WARNING] This function MUST BE called while "pR.InputsBufferLock" is unlocked -- otherwise the network I/O blocking of "sendSafely" might cause significant lag for "markConfirmationIfApplicable & forceConfirmationIfApplicable"! [WARNING] This function MUST BE called while "pR.InputsBufferLock" is unlocked -- otherwise the network I/O blocking of "sendSafely" might cause significant lag for "markConfirmationIfApplicable & forceConfirmationIfApplicable"!
@ -1796,7 +1426,7 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
panic(fmt.Sprintf("Required refRenderFrameId=%v for (roomId=%v, renderFrameId=%v, playerId=%v, playerLastSentInputFrameId=%v) doesn't exist! InputsBuffer=%v, RenderFrameBuffer=%v", refRenderFrameId, pR.Id, pR.RenderFrameId, playerId, player.LastSentInputFrameId, pR.InputsBufferString(false), pR.RenderFrameBufferString())) panic(fmt.Sprintf("Required refRenderFrameId=%v for (roomId=%v, renderFrameId=%v, playerId=%v, playerLastSentInputFrameId=%v) doesn't exist! InputsBuffer=%v, RenderFrameBuffer=%v", refRenderFrameId, pR.Id, pR.RenderFrameId, playerId, player.LastSentInputFrameId, pR.InputsBufferString(false), pR.RenderFrameBufferString()))
} }
refRenderFrame := tmp.(*RoomDownsyncFrame) refRenderFrame := tmp.(*battle.RoomDownsyncFrame)
for _, player := range pR.PlayersArr { for _, player := range pR.PlayersArr {
refRenderFrame.Players[player.Id].ColliderRadius = player.ColliderRadius // hardcoded for now refRenderFrame.Players[player.Id].ColliderRadius = player.ColliderRadius // hardcoded for now
} }
@ -1818,9 +1448,9 @@ func (pR *Room) downsyncToSinglePlayer(playerId int32, player *Player, refRender
} }
} }
func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*InputFrameDownsync { func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*pb.InputFrameDownsync {
// [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked! // [WARNING] This function MUST BE called while "pR.InputsBufferLock" is locked!
cloned := make([]*InputFrameDownsync, 0, edFrameId-stFrameId) cloned := make([]*pb.InputFrameDownsync, 0, edFrameId-stFrameId)
prevFrameFound := false prevFrameFound := false
j := stFrameId j := stFrameId
for j < edFrameId { for j < edFrameId {
@ -1834,9 +1464,9 @@ func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*InputFrameDowns
} }
} }
prevFrameFound = true prevFrameFound = true
foo := tmp.(*InputFrameDownsync) foo := tmp.(*pb.InputFrameDownsync)
bar := &InputFrameDownsync{ bar := &pb.InputFrameDownsync{
InputFrameId: foo.InputFrameId, InputFrameId: foo.InputFrameId,
InputList: make([]uint64, len(foo.InputList)), InputList: make([]uint64, len(foo.InputList)),
ConfirmedList: foo.ConfirmedList, ConfirmedList: foo.ConfirmedList,
@ -1850,29 +1480,3 @@ func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*InputFrameDowns
return cloned return cloned
} }
func (pR *Room) calcHardPushbacksNorms(playerCollider *resolv.Object, playerShape *resolv.ConvexPolygon, snapIntoPlatformOverlap float64, pEffPushback *Vec2D) []Vec2D {
ret := make([]Vec2D, 0, 10) // no one would simultaneously have more than 5 hardPushbacks
collision := playerCollider.Check(0, 0)
if nil == collision {
return ret
}
for _, obj := range collision.Objects {
switch obj.Data.(type) {
case *Barrier:
barrierShape := obj.Shape.(*resolv.ConvexPolygon)
overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, barrierShape)
if !overlapped {
continue
}
// ALWAY snap into hardPushbacks!
// [OverlapX, OverlapY] is the unit vector that points into the platform
pushbackX, pushbackY = (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapX, (overlapResult.Overlap-snapIntoPlatformOverlap)*overlapResult.OverlapY
ret = append(ret, Vec2D{X: overlapResult.OverlapX, Y: overlapResult.OverlapY})
pEffPushback.X += pushbackX
pEffPushback.Y += pushbackY
default:
}
}
return ret
}

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@ package ws
import ( import (
. "battle_srv/common" . "battle_srv/common"
"battle_srv/models" "battle_srv/models"
pb "jsexport/protos" pb "battle_srv/protos"
"container/heap" "container/heap"
"fmt" "fmt"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"

View File

@ -1,50 +0,0 @@
package dnmshared
import (
. "dnmshared/sharedprotos"
"math"
)
func NormVec2D(dx, dy float64) Vec2D {
return Vec2D{X: dy, Y: -dx}
}
func AlignPolygon2DToBoundingBox(input *Polygon2D) *Polygon2D {
// Transform again to put "anchor" at the "bottom-left point (w.r.t. world space)" of the bounding box for "resolv"
boundingBoxBL := &Vec2D{
X: math.MaxFloat64,
Y: math.MaxFloat64,
}
for _, p := range input.Points {
if p.X < boundingBoxBL.X {
boundingBoxBL.X = p.X
}
if p.Y < boundingBoxBL.Y {
boundingBoxBL.Y = p.Y
}
}
// Now "input.Anchor" should move to "input.Anchor+boundingBoxBL", thus "boundingBoxBL" is also the value of the negative diff for all "input.Points"
output := &Polygon2D{
Anchor: &Vec2D{
X: input.Anchor.X + boundingBoxBL.X,
Y: input.Anchor.Y + boundingBoxBL.Y,
},
Points: make([]*Vec2D, len(input.Points)),
}
for i, p := range input.Points {
output.Points[i] = &Vec2D{
X: p.X - boundingBoxBL.X,
Y: p.Y - boundingBoxBL.Y,
}
}
return output
}
func Distance(pt1 *Vec2D, pt2 *Vec2D) float64 {
dx := pt1.X - pt2.X
dy := pt1.Y - pt2.Y
return math.Sqrt(dx*dx + dy*dy)
}

View File

@ -1,14 +1,16 @@
package dnmshared package dnmshared
import ( import (
. "dnmshared/sharedprotos" . "jsexport/battle"
"fmt" "fmt"
"github.com/kvartborg/vector"
"github.com/solarlune/resolv" "github.com/solarlune/resolv"
"math"
"strings" "strings"
) )
func NormVec2D(dx, dy float64) Vec2D {
return Vec2D{X: dy, Y: -dx}
}
func ConvexPolygonStr(body *resolv.ConvexPolygon) string { func ConvexPolygonStr(body *resolv.ConvexPolygon) string {
var s []string = make([]string, len(body.Points)) var s []string = make([]string, len(body.Points))
for i, p := range body.Points { for i, p := range body.Points {
@ -21,251 +23,3 @@ func ConvexPolygonStr(body *resolv.ConvexPolygon) string {
func RectCenterStr(body *resolv.Object, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64) string { func RectCenterStr(body *resolv.Object, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64) string {
return fmt.Sprintf("{%.2f, %.2f}", body.X+leftPadding+halfBoundingW-spaceOffsetX, body.Y+bottomPadding+halfBoundingH-spaceOffsetY) return fmt.Sprintf("{%.2f, %.2f}", body.X+leftPadding+halfBoundingW-spaceOffsetX, body.Y+bottomPadding+halfBoundingH-spaceOffsetY)
} }
func GenerateRectCollider(wx, wy, w, h, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64, data interface{}, tag string) *resolv.Object {
blX, blY := WorldToPolygonColliderBLPos(wx, wy, w*0.5, h*0.5, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY)
return generateRectColliderInCollisionSpace(blX, blY, leftPadding+w+rightPadding, bottomPadding+h+topPadding, data, tag)
}
func generateRectColliderInCollisionSpace(blX, blY, w, h float64, data interface{}, tag string) *resolv.Object {
collider := resolv.NewObject(blX, blY, w, h, tag) // Unlike its frontend counter part, the position of a "resolv.Object" must be specified by "bottom-left point" because "w" and "h" must be positive, see "resolv.Object.BoundsToSpace" for details
shape := resolv.NewRectangle(0, 0, w, h)
collider.SetShape(shape)
collider.Data = data
return collider
}
func GenerateConvexPolygonCollider(unalignedSrc *Polygon2D, spaceOffsetX, spaceOffsetY float64, data interface{}, tag string) *resolv.Object {
aligned := AlignPolygon2DToBoundingBox(unalignedSrc)
var w, h float64 = 0, 0
shape := resolv.NewConvexPolygon()
for i, pi := range aligned.Points {
for j, pj := range aligned.Points {
if i == j {
continue
}
if math.Abs(pj.X-pi.X) > w {
w = math.Abs(pj.X - pi.X)
}
if math.Abs(pj.Y-pi.Y) > h {
h = math.Abs(pj.Y - pi.Y)
}
}
}
for i := 0; i < len(aligned.Points); i++ {
p := aligned.Points[i]
shape.AddPoints(p.X, p.Y)
}
collider := resolv.NewObject(aligned.Anchor.X+spaceOffsetX, aligned.Anchor.Y+spaceOffsetY, w, h, tag)
collider.SetShape(shape)
collider.Data = data
return collider
}
func CalcPushbacks(oldDx, oldDy float64, playerShape, barrierShape *resolv.ConvexPolygon) (bool, float64, float64, *SatResult) {
origX, origY := playerShape.Position()
defer func() {
playerShape.SetPosition(origX, origY)
}()
playerShape.SetPosition(origX+oldDx, origY+oldDy)
overlapResult := &SatResult{
Overlap: 0,
OverlapX: 0,
OverlapY: 0,
AContainedInB: true,
BContainedInA: true,
Axis: vector.Vector{0, 0},
}
if overlapped := isPolygonPairOverlapped(playerShape, barrierShape, overlapResult); overlapped {
pushbackX, pushbackY := overlapResult.Overlap*overlapResult.OverlapX, overlapResult.Overlap*overlapResult.OverlapY
return true, pushbackX, pushbackY, overlapResult
} else {
return false, 0, 0, overlapResult
}
}
type SatResult struct {
Overlap float64
OverlapX float64
OverlapY float64
AContainedInB bool
BContainedInA bool
Axis vector.Vector
}
func isPolygonPairOverlapped(a, b *resolv.ConvexPolygon, result *SatResult) bool {
aCnt, bCnt := len(a.Points), len(b.Points)
// Single point case
if 1 == aCnt && 1 == bCnt {
if nil != result {
result.Overlap = 0
}
return a.Points[0][0] == b.Points[0][0] && a.Points[0][1] == b.Points[0][1]
}
//Logger.Info(fmt.Sprintf("Checking collision between a=%v, b=%v", ConvexPolygonStr(a), ConvexPolygonStr(b)))
if 1 < aCnt {
for _, axis := range a.SATAxes() {
if isPolygonPairSeparatedByDir(a, b, axis.Unit(), result) {
return false
}
}
}
if 1 < bCnt {
for _, axis := range b.SATAxes() {
if isPolygonPairSeparatedByDir(a, b, axis.Unit(), result) {
return false
}
}
}
//Logger.Info(fmt.Sprintf("a=%v and b=%v are overlapped", ConvexPolygonStr(a), ConvexPolygonStr(b)))
return true
}
func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e vector.Vector, result *SatResult) bool {
/*
[WARNING] This function is deliberately made private, it shouldn't be used alone (i.e. not along the norms of a polygon), otherwise the pushbacks calculated would be meaningless.
Consider the following example
a: {
anchor: [1337.19 1696.74]
points: [[0 0] [24 0] [24 24] [0 24]]
},
b: {
anchor: [1277.72 1570.56]
points: [[642.57 319.16] [0 319.16] [5.73 0] [643.75 0.90]]
}
e = (-2.98, 1.49).Unit()
*/
//Logger.Info(fmt.Sprintf("Checking separation between a=%v, b=%v along axis e={%.3f, %.3f}#1", ConvexPolygonStr(a), ConvexPolygonStr(b), e[0], e[1]))
var aStart, aEnd, bStart, bEnd float64 = math.MaxFloat64, -math.MaxFloat64, math.MaxFloat64, -math.MaxFloat64
for _, p := range a.Points {
dot := (p[0]+a.X)*e[0] + (p[1]+a.Y)*e[1]
if aStart > dot {
aStart = dot
}
if aEnd < dot {
aEnd = dot
}
}
for _, p := range b.Points {
dot := (p[0]+b.X)*e[0] + (p[1]+b.Y)*e[1]
if bStart > dot {
bStart = dot
}
if bEnd < dot {
bEnd = dot
}
}
if aStart > bEnd || aEnd < bStart {
// Separated by unit vector "e"
return true
}
if nil != result {
overlap := float64(0)
if aStart < bStart {
result.AContainedInB = false
if aEnd < bEnd {
overlap = aEnd - bStart
result.BContainedInA = false
} else {
option1 := aEnd - bStart
option2 := bEnd - aStart
if option1 < option2 {
overlap = option1
} else {
overlap = -option2
}
}
} else {
result.BContainedInA = false
if aEnd > bEnd {
overlap = aStart - bEnd
result.AContainedInB = false
} else {
option1 := aEnd - bStart
option2 := bEnd - aStart
if option1 < option2 {
overlap = option1
} else {
overlap = -option2
}
}
}
currentOverlap := result.Overlap
absoluteOverlap := overlap
if overlap < 0 {
absoluteOverlap = -overlap
}
if (0 == result.Axis[0] && 0 == result.Axis[1]) || currentOverlap > absoluteOverlap {
var sign float64 = 1
if overlap < 0 {
sign = -1
}
result.Overlap = absoluteOverlap
result.OverlapX = e[0] * sign
result.OverlapY = e[1] * sign
}
result.Axis = e
//Logger.Info(fmt.Sprintf("Checking separation between a=%v, b=%v along axis e={%.3f, %.3f}#2: aStart=%.3f, aEnd=%.3f, bStart=%.3f, bEnd=%.3f, overlap=%.3f, currentOverlap=%.3f, absoluteOverlap=%.3f, result=%v", ConvexPolygonStr(a), ConvexPolygonStr(b), e[0], e[1], aStart, aEnd, bStart, bEnd, overlap, currentOverlap, absoluteOverlap, result))
}
// the specified unit vector "e" doesn't separate "a" and "b", overlap result is generated
return false
}
func WorldToVirtualGridPos(wx, wy, worldToVirtualGridRatio float64) (int32, int32) {
// [WARNING] Introduces loss of precision!
// In JavaScript floating numbers suffer from seemingly non-deterministic arithmetics, and even if certain libs solved this issue by approaches such as fixed-point-number, they might not be used in other libs -- e.g. the "collision libs" we're interested in -- thus couldn't kill all pains.
var virtualGridX int32 = int32(math.Round(wx * worldToVirtualGridRatio))
var virtualGridY int32 = int32(math.Round(wy * worldToVirtualGridRatio))
return virtualGridX, virtualGridY
}
func VirtualGridToWorldPos(vx, vy int32, virtualGridToWorldRatio float64) (float64, float64) {
// No loss of precision
var wx float64 = float64(vx) * virtualGridToWorldRatio
var wy float64 = float64(vy) * virtualGridToWorldRatio
return wx, wy
}
func WorldToPolygonColliderBLPos(wx, wy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) {
return wx - halfBoundingW - leftPadding + collisionSpaceOffsetX, wy - halfBoundingH - bottomPadding + collisionSpaceOffsetY
}
func PolygonColliderBLToWorldPos(cx, cy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64) (float64, float64) {
return cx + halfBoundingW + leftPadding - collisionSpaceOffsetX, cy + halfBoundingH + bottomPadding - collisionSpaceOffsetY
}
func PolygonColliderBLToVirtualGridPos(cx, cy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64, worldToVirtualGridRatio float64) (int32, int32) {
wx, wy := PolygonColliderBLToWorldPos(cx, cy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY)
return WorldToVirtualGridPos(wx, wy, worldToVirtualGridRatio)
}
func VirtualGridToPolygonColliderBLPos(vx, vy int32, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY float64, virtualGridToWorldRatio float64) (float64, float64) {
wx, wy := VirtualGridToWorldPos(vx, vy, virtualGridToWorldRatio)
return WorldToPolygonColliderBLPos(wx, wy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY)
}

View File

@ -3,13 +3,13 @@ package dnmshared
import ( import (
"bytes" "bytes"
"compress/zlib" "compress/zlib"
. "dnmshared/sharedprotos"
"encoding/base64" "encoding/base64"
"encoding/xml" "encoding/xml"
"errors" "errors"
"fmt" "fmt"
"go.uber.org/zap" "go.uber.org/zap"
"io/ioutil" "io/ioutil"
. "jsexport/battle"
"math" "math"
"strconv" "strconv"
"strings" "strings"
@ -175,8 +175,8 @@ func (l *TmxLayer) decodeBase64() ([]uint32, error) {
return gids, nil return gids, nil
} }
type StrToVec2DListMap map[string]*Vec2DList type StrToVec2DListMap map[string]([]*Vec2D)
type StrToPolygon2DListMap map[string]*Polygon2DList type StrToPolygon2DListMap map[string]([]*Polygon2D)
func tmxPolylineToPolygon2D(pTmxMapIns *TmxMap, singleObjInTmxFile *TmxOrTsxObject, targetPolyline *TmxOrTsxPolyline) (*Polygon2D, error) { func tmxPolylineToPolygon2D(pTmxMapIns *TmxMap, singleObjInTmxFile *TmxOrTsxObject, targetPolyline *TmxOrTsxPolyline) (*Polygon2D, error) {
if nil == targetPolyline { if nil == targetPolyline {
@ -321,13 +321,11 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f
theStrToPolygon2DListMap = gidBoundariesMap[globalGid] theStrToPolygon2DListMap = gidBoundariesMap[globalGid]
} }
var pThePolygon2DList *Polygon2DList var pThePolygon2DList []*Polygon2D
if _, ok := theStrToPolygon2DListMap[key]; ok { if _, ok := theStrToPolygon2DListMap[key]; ok {
pThePolygon2DList = theStrToPolygon2DListMap[key] pThePolygon2DList = theStrToPolygon2DListMap[key]
} else { } else {
pThePolygon2DList = &Polygon2DList{ pThePolygon2DList = make([]*Polygon2D, 0)
Eles: make([]*Polygon2D, 0),
}
theStrToPolygon2DListMap[key] = pThePolygon2DList theStrToPolygon2DListMap[key] = pThePolygon2DList
} }
@ -335,7 +333,7 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f
if nil != err { if nil != err {
panic(err) panic(err)
} }
pThePolygon2DList.Eles = append(pThePolygon2DList.Eles, thePolygon2DFromPolyline) pThePolygon2DList = append(pThePolygon2DList, thePolygon2DFromPolyline)
} }
} }
return nil return nil
@ -348,12 +346,10 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMap map[int]StrToP
for _, objGroup := range pTmxMapIns.ObjectGroups { for _, objGroup := range pTmxMapIns.ObjectGroups {
switch objGroup.Name { switch objGroup.Name {
case "PlayerStartingPos": case "PlayerStartingPos":
var pTheVec2DListToCache *Vec2DList var pTheVec2DListToCache []*Vec2D
_, ok := toRetStrToVec2DListMap[objGroup.Name] _, ok := toRetStrToVec2DListMap[objGroup.Name]
if false == ok { if false == ok {
pTheVec2DListToCache = &Vec2DList{ pTheVec2DListToCache = make([]*Vec2D, 0)
Eles: make([]*Vec2D, 0),
}
toRetStrToVec2DListMap[objGroup.Name] = pTheVec2DListToCache toRetStrToVec2DListMap[objGroup.Name] = pTheVec2DListToCache
} }
pTheVec2DListToCache = toRetStrToVec2DListMap[objGroup.Name] pTheVec2DListToCache = toRetStrToVec2DListMap[objGroup.Name]
@ -363,16 +359,14 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMap map[int]StrToP
Y: singleObjInTmxFile.Y, Y: singleObjInTmxFile.Y,
} }
thePosInWorld := pTmxMapIns.continuousObjLayerOffsetToContinuousMapNodePos(theUntransformedPos) thePosInWorld := pTmxMapIns.continuousObjLayerOffsetToContinuousMapNodePos(theUntransformedPos)
pTheVec2DListToCache.Eles = append(pTheVec2DListToCache.Eles, &thePosInWorld) pTheVec2DListToCache = append(pTheVec2DListToCache, &thePosInWorld)
} }
case "Barrier": case "Barrier":
// Note that in this case, the "Polygon2D.Anchor" of each "TmxOrTsxObject" is exactly overlapping with "Polygon2D.Points[0]". // Note that in this case, the "Polygon2D.Anchor" of each "TmxOrTsxObject" is exactly overlapping with "Polygon2D.Points[0]".
var pThePolygon2DListToCache *Polygon2DList var pThePolygon2DListToCache []*Polygon2D
_, ok := toRetStrToPolygon2DListMap[objGroup.Name] _, ok := toRetStrToPolygon2DListMap[objGroup.Name]
if false == ok { if false == ok {
pThePolygon2DListToCache = &Polygon2DList{ pThePolygon2DListToCache = make([]*Polygon2D, 0)
Eles: make([]*Polygon2D, 0),
}
toRetStrToPolygon2DListMap[objGroup.Name] = pThePolygon2DListToCache toRetStrToPolygon2DListMap[objGroup.Name] = pThePolygon2DListToCache
} }
@ -408,7 +402,7 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMap map[int]StrToP
if nil != err { if nil != err {
panic(err) panic(err)
} }
pThePolygon2DListToCache.Eles = append(pThePolygon2DListToCache.Eles, thePolygon2DInWorld) pThePolygon2DListToCache = append(pThePolygon2DListToCache, thePolygon2DInWorld)
} }
default: default:
} }

File diff suppressed because one or more lines are too long

View File

@ -79,10 +79,6 @@ message InputsBufferSnapshot {
bool shouldForceResync = 4; bool shouldForceResync = 4;
} }
message Barrier {
sharedprotos.Polygon2D boundary = 1;
}
message MeleeBullet { message MeleeBullet {
// Jargon reference https://www.thegamer.com/fighting-games-frame-data-explained/ // Jargon reference https://www.thegamer.com/fighting-games-frame-data-explained/
// ALL lengths are in world coordinate // ALL lengths are in world coordinate
@ -94,60 +90,62 @@ message MeleeBullet {
int32 recoveryFrames = 4; int32 recoveryFrames = 4;
int32 recoveryFramesOnBlock = 5; int32 recoveryFramesOnBlock = 5;
int32 recoveryFramesOnHit = 6; int32 recoveryFramesOnHit = 6;
sharedprotos.Vec2D moveforward = 7; double hitboxOffset = 7;
double hitboxOffset = 8; int32 originatedRenderFrameId = 8;
sharedprotos.Vec2D hitboxSize = 9;
int32 originatedRenderFrameId = 10;
// for defender // for defender
int32 hitStunFrames = 11; int32 hitStunFrames = 9;
int32 blockStunFrames = 12; int32 blockStunFrames = 10;
double pushback = 13; double pushback = 11;
int32 releaseTriggerType = 14; // 1: rising-edge, 2: falling-edge int32 releaseTriggerType = 12; // 1: rising-edge, 2: falling-edge
int32 damage = 15; int32 damage = 13;
int32 offenderJoinIndex = 16; int32 offenderJoinIndex = 14;
int32 offenderPlayerId = 17; int32 offenderPlayerId = 15;
double hitboxSizeX = 16;
double hitboxSizeY = 17;
double selfMoveforwardX = 18;
double selfMoveforwardY = 19;
} }
message BattleColliderInfo { message BattleColliderInfo {
string stageName = 1; string stageName = 1;
map<string, sharedprotos.Vec2DList> strToVec2DListMap = 2; int32 stageDiscreteW = 2;
map<string, sharedprotos.Polygon2DList> strToPolygon2DListMap = 3; int32 stageDiscreteH = 3;
int32 stageDiscreteW = 4; int32 stageTileW = 4;
int32 stageDiscreteH = 5; int32 stageTileH = 5;
int32 stageTileW = 6;
int32 stageTileH = 7;
int32 intervalToPing = 8; int32 intervalToPing = 6;
int32 willKickIfInactiveFor = 9; int32 willKickIfInactiveFor = 7;
int32 boundRoomId = 10; int32 boundRoomId = 8;
int32 battleDurationFrames = 12; int32 battleDurationFrames = 9;
int64 battleDurationNanos = 13; int64 battleDurationNanos = 10;
int32 serverFps = 14; int32 serverFps = 11;
int32 inputDelayFrames = 15; // in the count of render frames int32 inputDelayFrames = 12; // in the count of render frames
uint32 inputScaleFrames = 16; // inputDelayedAndScaledFrameId = ((originalFrameId - InputDelayFrames) >> InputScaleFrames) uint32 inputScaleFrames = 13; // inputDelayedAndScaledFrameId = ((originalFrameId - InputDelayFrames) >> InputScaleFrames)
int32 nstDelayFrames = 17; // network-single-trip delay in the count of render frames, proposed to be (InputDelayFrames >> 1) because we expect a round-trip delay to be exactly "InputDelayFrames" int32 nstDelayFrames = 14; // network-single-trip delay in the count of render frames, proposed to be (InputDelayFrames >> 1) because we expect a round-trip delay to be exactly "InputDelayFrames"
int32 inputFrameUpsyncDelayTolerance = 18; int32 inputFrameUpsyncDelayTolerance = 15;
int32 maxChasingRenderFramesPerUpdate = 19; int32 maxChasingRenderFramesPerUpdate = 16;
int32 playerBattleState = 20; int32 playerBattleState = 17;
double rollbackEstimatedDtMillis = 21; double rollbackEstimatedDtMillis = 18;
int64 rollbackEstimatedDtNanos = 22; int64 rollbackEstimatedDtNanos = 19;
double worldToVirtualGridRatio = 23; double worldToVirtualGridRatio = 20;
double virtualGridToWorldRatio = 24; double virtualGridToWorldRatio = 21;
int32 spAtkLookupFrames = 25; int32 spAtkLookupFrames = 22;
int32 renderCacheSize = 26; int32 renderCacheSize = 23;
map<int32, MeleeBullet> meleeSkillConfig = 27; // skillId -> skill map<int32, MeleeBullet> meleeSkillConfig = 24; // skillId -> skill
double snapIntoPlatformOverlap = 28; double snapIntoPlatformOverlap = 25;
double snapIntoPlatformThreshold = 29; double snapIntoPlatformThreshold = 26;
int32 jumpingInitVelY = 30; int32 jumpingInitVelY = 27;
int32 gravityX = 31; int32 gravityX = 28;
int32 gravityY = 32; int32 gravityY = 29;
} }
message RoomDownsyncFrame { message RoomDownsyncFrame {

View File

@ -294,11 +294,9 @@ cc.Class({
throw `Failed to get cached delayedInputFrame for i=${i}, j=${j}, renderFrameId=${self.renderFrameId}, lastUpsyncInputFrameId=${self.lastUpsyncInputFrameId}, lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}, chaserRenderFrameId=${self.chaserRenderFrameId}; recentRenderCache=${self._stringifyRecentRenderCache(false)}, recentInputCache=${self._stringifyRecentInputCache(false)}`; throw `Failed to get cached delayedInputFrame for i=${i}, j=${j}, renderFrameId=${self.renderFrameId}, lastUpsyncInputFrameId=${self.lastUpsyncInputFrameId}, lastAllConfirmedInputFrameId=${self.lastAllConfirmedInputFrameId}, chaserRenderFrameId=${self.chaserRenderFrameId}; recentRenderCache=${self._stringifyRecentRenderCache(false)}, recentInputCache=${self._stringifyRecentInputCache(false)}`;
} }
const delayedInputFrameJs = gopkgs.NewInputFrameDownsyncJs(j, delayedInputFrame.inputList, delayedInputFrame.confirmedList);
const jPrev = self._convertToInputFrameId(i - 1, self.inputDelayFrames); const jPrev = self._convertToInputFrameId(i - 1, self.inputDelayFrames);
const delayedInputFrameForPrevRenderFrame = self.recentInputCache.getByFrameId(jPrev); const delayedInputFrameForPrevRenderFrame = self.recentInputCache.getByFrameId(jPrev);
const delayedInputFrameForPrevRenderFrameJs = gopkgs.NewInputFrameDownsyncJs(jPrev, delayedInputFrameForPrevRenderFrame.inputList, delayedInputFrameForPrevRenderFrame.confirmedList); const nextRdf = gopkgs.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrameJs(delayedInputFrame.inputList, (null == delayedInputFrameForPrevRenderFrame ? null : delayedInputFrameForPrevRenderFrame.inputList), currRdf, collisionSys, collisionSysMap, self.gravityX, self.gravityY, self.jumpingInitVelY, self.inputDelayFrames, self.inputScaleFrames, self.spaceOffsetX, self.spaceOffsetY, self.snapIntoPlatformOverlap, self.snapIntoPlatformThreshold, self.worldToVirtualGridRatio, self.virtualGridToWorldRatio);
const nextRdf = gopkgs.ApplyInputFrameDownsyncDynamicsOnSingleRenderFrameJs(delayedInputFrameJs, delayedInputFrameForPrevRenderFrameJs, currRdf, collisionSys, collisionSysMap, self.gravityX, self.gravityY, self.jumpingInitVelY, self.inputDelayFrames, self.inputScaleFrames, self.spaceOffsetX, self.spaceOffsetY, self.snapIntoPlatformOverlap, self.snapIntoPlatformThreshold, self.worldToVirtualGridRatio, self.virtualGridToWorldRatio);
if (true == isChasing) { if (true == isChasing) {
// [WARNING] Move the cursor "self.chaserRenderFrameId" when "true == isChasing", keep in mind that "self.chaserRenderFrameId" is not monotonic! // [WARNING] Move the cursor "self.chaserRenderFrameId" when "true == isChasing", keep in mind that "self.chaserRenderFrameId" is not monotonic!

View File

@ -3954,214 +3954,6 @@ $root.protos = (function() {
return InputsBufferSnapshot; return InputsBufferSnapshot;
})(); })();
protos.Barrier = (function() {
/**
* Properties of a Barrier.
* @memberof protos
* @interface IBarrier
* @property {sharedprotos.Polygon2D|null} [boundary] Barrier boundary
*/
/**
* Constructs a new Barrier.
* @memberof protos
* @classdesc Represents a Barrier.
* @implements IBarrier
* @constructor
* @param {protos.IBarrier=} [properties] Properties to set
*/
function Barrier(properties) {
if (properties)
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null)
this[keys[i]] = properties[keys[i]];
}
/**
* Barrier boundary.
* @member {sharedprotos.Polygon2D|null|undefined} boundary
* @memberof protos.Barrier
* @instance
*/
Barrier.prototype.boundary = null;
/**
* Creates a new Barrier instance using the specified properties.
* @function create
* @memberof protos.Barrier
* @static
* @param {protos.IBarrier=} [properties] Properties to set
* @returns {protos.Barrier} Barrier instance
*/
Barrier.create = function create(properties) {
return new Barrier(properties);
};
/**
* Encodes the specified Barrier message. Does not implicitly {@link protos.Barrier.verify|verify} messages.
* @function encode
* @memberof protos.Barrier
* @static
* @param {protos.Barrier} message Barrier message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Barrier.encode = function encode(message, writer) {
if (!writer)
writer = $Writer.create();
if (message.boundary != null && Object.hasOwnProperty.call(message, "boundary"))
$root.sharedprotos.Polygon2D.encode(message.boundary, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim();
return writer;
};
/**
* Encodes the specified Barrier message, length delimited. Does not implicitly {@link protos.Barrier.verify|verify} messages.
* @function encodeDelimited
* @memberof protos.Barrier
* @static
* @param {protos.Barrier} message Barrier message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Barrier.encodeDelimited = function encodeDelimited(message, writer) {
return this.encode(message, writer).ldelim();
};
/**
* Decodes a Barrier message from the specified reader or buffer.
* @function decode
* @memberof protos.Barrier
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @param {number} [length] Message length if known beforehand
* @returns {protos.Barrier} Barrier
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
Barrier.decode = function decode(reader, length) {
if (!(reader instanceof $Reader))
reader = $Reader.create(reader);
var end = length === undefined ? reader.len : reader.pos + length, message = new $root.protos.Barrier();
while (reader.pos < end) {
var tag = reader.uint32();
switch (tag >>> 3) {
case 1: {
message.boundary = $root.sharedprotos.Polygon2D.decode(reader, reader.uint32());
break;
}
default:
reader.skipType(tag & 7);
break;
}
}
return message;
};
/**
* Decodes a Barrier message from the specified reader or buffer, length delimited.
* @function decodeDelimited
* @memberof protos.Barrier
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @returns {protos.Barrier} Barrier
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
Barrier.decodeDelimited = function decodeDelimited(reader) {
if (!(reader instanceof $Reader))
reader = new $Reader(reader);
return this.decode(reader, reader.uint32());
};
/**
* Verifies a Barrier message.
* @function verify
* @memberof protos.Barrier
* @static
* @param {Object.<string,*>} message Plain object to verify
* @returns {string|null} `null` if valid, otherwise the reason why it is not
*/
Barrier.verify = function verify(message) {
if (typeof message !== "object" || message === null)
return "object expected";
if (message.boundary != null && message.hasOwnProperty("boundary")) {
var error = $root.sharedprotos.Polygon2D.verify(message.boundary);
if (error)
return "boundary." + error;
}
return null;
};
/**
* Creates a Barrier message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof protos.Barrier
* @static
* @param {Object.<string,*>} object Plain object
* @returns {protos.Barrier} Barrier
*/
Barrier.fromObject = function fromObject(object) {
if (object instanceof $root.protos.Barrier)
return object;
var message = new $root.protos.Barrier();
if (object.boundary != null) {
if (typeof object.boundary !== "object")
throw TypeError(".protos.Barrier.boundary: object expected");
message.boundary = $root.sharedprotos.Polygon2D.fromObject(object.boundary);
}
return message;
};
/**
* Creates a plain object from a Barrier message. Also converts values to other types if specified.
* @function toObject
* @memberof protos.Barrier
* @static
* @param {protos.Barrier} message Barrier
* @param {$protobuf.IConversionOptions} [options] Conversion options
* @returns {Object.<string,*>} Plain object
*/
Barrier.toObject = function toObject(message, options) {
if (!options)
options = {};
var object = {};
if (options.defaults)
object.boundary = null;
if (message.boundary != null && message.hasOwnProperty("boundary"))
object.boundary = $root.sharedprotos.Polygon2D.toObject(message.boundary, options);
return object;
};
/**
* Converts this Barrier to JSON.
* @function toJSON
* @memberof protos.Barrier
* @instance
* @returns {Object.<string,*>} JSON object
*/
Barrier.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
/**
* Gets the default type url for Barrier
* @function getTypeUrl
* @memberof protos.Barrier
* @static
* @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
* @returns {string} The default type url
*/
Barrier.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
if (typeUrlPrefix === undefined) {
typeUrlPrefix = "type.googleapis.com";
}
return typeUrlPrefix + "/protos.Barrier";
};
return Barrier;
})();
protos.MeleeBullet = (function() { protos.MeleeBullet = (function() {
/** /**
@ -4174,9 +3966,7 @@ $root.protos = (function() {
* @property {number|null} [recoveryFrames] MeleeBullet recoveryFrames * @property {number|null} [recoveryFrames] MeleeBullet recoveryFrames
* @property {number|null} [recoveryFramesOnBlock] MeleeBullet recoveryFramesOnBlock * @property {number|null} [recoveryFramesOnBlock] MeleeBullet recoveryFramesOnBlock
* @property {number|null} [recoveryFramesOnHit] MeleeBullet recoveryFramesOnHit * @property {number|null} [recoveryFramesOnHit] MeleeBullet recoveryFramesOnHit
* @property {sharedprotos.Vec2D|null} [moveforward] MeleeBullet moveforward
* @property {number|null} [hitboxOffset] MeleeBullet hitboxOffset * @property {number|null} [hitboxOffset] MeleeBullet hitboxOffset
* @property {sharedprotos.Vec2D|null} [hitboxSize] MeleeBullet hitboxSize
* @property {number|null} [originatedRenderFrameId] MeleeBullet originatedRenderFrameId * @property {number|null} [originatedRenderFrameId] MeleeBullet originatedRenderFrameId
* @property {number|null} [hitStunFrames] MeleeBullet hitStunFrames * @property {number|null} [hitStunFrames] MeleeBullet hitStunFrames
* @property {number|null} [blockStunFrames] MeleeBullet blockStunFrames * @property {number|null} [blockStunFrames] MeleeBullet blockStunFrames
@ -4185,6 +3975,10 @@ $root.protos = (function() {
* @property {number|null} [damage] MeleeBullet damage * @property {number|null} [damage] MeleeBullet damage
* @property {number|null} [offenderJoinIndex] MeleeBullet offenderJoinIndex * @property {number|null} [offenderJoinIndex] MeleeBullet offenderJoinIndex
* @property {number|null} [offenderPlayerId] MeleeBullet offenderPlayerId * @property {number|null} [offenderPlayerId] MeleeBullet offenderPlayerId
* @property {number|null} [hitboxSizeX] MeleeBullet hitboxSizeX
* @property {number|null} [hitboxSizeY] MeleeBullet hitboxSizeY
* @property {number|null} [selfMoveforwardX] MeleeBullet selfMoveforwardX
* @property {number|null} [selfMoveforwardY] MeleeBullet selfMoveforwardY
*/ */
/** /**
@ -4250,14 +4044,6 @@ $root.protos = (function() {
*/ */
MeleeBullet.prototype.recoveryFramesOnHit = 0; MeleeBullet.prototype.recoveryFramesOnHit = 0;
/**
* MeleeBullet moveforward.
* @member {sharedprotos.Vec2D|null|undefined} moveforward
* @memberof protos.MeleeBullet
* @instance
*/
MeleeBullet.prototype.moveforward = null;
/** /**
* MeleeBullet hitboxOffset. * MeleeBullet hitboxOffset.
* @member {number} hitboxOffset * @member {number} hitboxOffset
@ -4266,14 +4052,6 @@ $root.protos = (function() {
*/ */
MeleeBullet.prototype.hitboxOffset = 0; MeleeBullet.prototype.hitboxOffset = 0;
/**
* MeleeBullet hitboxSize.
* @member {sharedprotos.Vec2D|null|undefined} hitboxSize
* @memberof protos.MeleeBullet
* @instance
*/
MeleeBullet.prototype.hitboxSize = null;
/** /**
* MeleeBullet originatedRenderFrameId. * MeleeBullet originatedRenderFrameId.
* @member {number} originatedRenderFrameId * @member {number} originatedRenderFrameId
@ -4338,6 +4116,38 @@ $root.protos = (function() {
*/ */
MeleeBullet.prototype.offenderPlayerId = 0; MeleeBullet.prototype.offenderPlayerId = 0;
/**
* MeleeBullet hitboxSizeX.
* @member {number} hitboxSizeX
* @memberof protos.MeleeBullet
* @instance
*/
MeleeBullet.prototype.hitboxSizeX = 0;
/**
* MeleeBullet hitboxSizeY.
* @member {number} hitboxSizeY
* @memberof protos.MeleeBullet
* @instance
*/
MeleeBullet.prototype.hitboxSizeY = 0;
/**
* MeleeBullet selfMoveforwardX.
* @member {number} selfMoveforwardX
* @memberof protos.MeleeBullet
* @instance
*/
MeleeBullet.prototype.selfMoveforwardX = 0;
/**
* MeleeBullet selfMoveforwardY.
* @member {number} selfMoveforwardY
* @memberof protos.MeleeBullet
* @instance
*/
MeleeBullet.prototype.selfMoveforwardY = 0;
/** /**
* Creates a new MeleeBullet instance using the specified properties. * Creates a new MeleeBullet instance using the specified properties.
* @function create * @function create
@ -4374,28 +4184,32 @@ $root.protos = (function() {
writer.uint32(/* id 5, wireType 0 =*/40).int32(message.recoveryFramesOnBlock); writer.uint32(/* id 5, wireType 0 =*/40).int32(message.recoveryFramesOnBlock);
if (message.recoveryFramesOnHit != null && Object.hasOwnProperty.call(message, "recoveryFramesOnHit")) if (message.recoveryFramesOnHit != null && Object.hasOwnProperty.call(message, "recoveryFramesOnHit"))
writer.uint32(/* id 6, wireType 0 =*/48).int32(message.recoveryFramesOnHit); writer.uint32(/* id 6, wireType 0 =*/48).int32(message.recoveryFramesOnHit);
if (message.moveforward != null && Object.hasOwnProperty.call(message, "moveforward"))
$root.sharedprotos.Vec2D.encode(message.moveforward, writer.uint32(/* id 7, wireType 2 =*/58).fork()).ldelim();
if (message.hitboxOffset != null && Object.hasOwnProperty.call(message, "hitboxOffset")) if (message.hitboxOffset != null && Object.hasOwnProperty.call(message, "hitboxOffset"))
writer.uint32(/* id 8, wireType 1 =*/65).double(message.hitboxOffset); writer.uint32(/* id 7, wireType 1 =*/57).double(message.hitboxOffset);
if (message.hitboxSize != null && Object.hasOwnProperty.call(message, "hitboxSize"))
$root.sharedprotos.Vec2D.encode(message.hitboxSize, writer.uint32(/* id 9, wireType 2 =*/74).fork()).ldelim();
if (message.originatedRenderFrameId != null && Object.hasOwnProperty.call(message, "originatedRenderFrameId")) if (message.originatedRenderFrameId != null && Object.hasOwnProperty.call(message, "originatedRenderFrameId"))
writer.uint32(/* id 10, wireType 0 =*/80).int32(message.originatedRenderFrameId); writer.uint32(/* id 8, wireType 0 =*/64).int32(message.originatedRenderFrameId);
if (message.hitStunFrames != null && Object.hasOwnProperty.call(message, "hitStunFrames")) if (message.hitStunFrames != null && Object.hasOwnProperty.call(message, "hitStunFrames"))
writer.uint32(/* id 11, wireType 0 =*/88).int32(message.hitStunFrames); writer.uint32(/* id 9, wireType 0 =*/72).int32(message.hitStunFrames);
if (message.blockStunFrames != null && Object.hasOwnProperty.call(message, "blockStunFrames")) if (message.blockStunFrames != null && Object.hasOwnProperty.call(message, "blockStunFrames"))
writer.uint32(/* id 12, wireType 0 =*/96).int32(message.blockStunFrames); writer.uint32(/* id 10, wireType 0 =*/80).int32(message.blockStunFrames);
if (message.pushback != null && Object.hasOwnProperty.call(message, "pushback")) if (message.pushback != null && Object.hasOwnProperty.call(message, "pushback"))
writer.uint32(/* id 13, wireType 1 =*/105).double(message.pushback); writer.uint32(/* id 11, wireType 1 =*/89).double(message.pushback);
if (message.releaseTriggerType != null && Object.hasOwnProperty.call(message, "releaseTriggerType")) if (message.releaseTriggerType != null && Object.hasOwnProperty.call(message, "releaseTriggerType"))
writer.uint32(/* id 14, wireType 0 =*/112).int32(message.releaseTriggerType); writer.uint32(/* id 12, wireType 0 =*/96).int32(message.releaseTriggerType);
if (message.damage != null && Object.hasOwnProperty.call(message, "damage")) if (message.damage != null && Object.hasOwnProperty.call(message, "damage"))
writer.uint32(/* id 15, wireType 0 =*/120).int32(message.damage); writer.uint32(/* id 13, wireType 0 =*/104).int32(message.damage);
if (message.offenderJoinIndex != null && Object.hasOwnProperty.call(message, "offenderJoinIndex")) if (message.offenderJoinIndex != null && Object.hasOwnProperty.call(message, "offenderJoinIndex"))
writer.uint32(/* id 16, wireType 0 =*/128).int32(message.offenderJoinIndex); writer.uint32(/* id 14, wireType 0 =*/112).int32(message.offenderJoinIndex);
if (message.offenderPlayerId != null && Object.hasOwnProperty.call(message, "offenderPlayerId")) if (message.offenderPlayerId != null && Object.hasOwnProperty.call(message, "offenderPlayerId"))
writer.uint32(/* id 17, wireType 0 =*/136).int32(message.offenderPlayerId); writer.uint32(/* id 15, wireType 0 =*/120).int32(message.offenderPlayerId);
if (message.hitboxSizeX != null && Object.hasOwnProperty.call(message, "hitboxSizeX"))
writer.uint32(/* id 16, wireType 1 =*/129).double(message.hitboxSizeX);
if (message.hitboxSizeY != null && Object.hasOwnProperty.call(message, "hitboxSizeY"))
writer.uint32(/* id 17, wireType 1 =*/137).double(message.hitboxSizeY);
if (message.selfMoveforwardX != null && Object.hasOwnProperty.call(message, "selfMoveforwardX"))
writer.uint32(/* id 18, wireType 1 =*/145).double(message.selfMoveforwardX);
if (message.selfMoveforwardY != null && Object.hasOwnProperty.call(message, "selfMoveforwardY"))
writer.uint32(/* id 19, wireType 1 =*/153).double(message.selfMoveforwardY);
return writer; return writer;
}; };
@ -4455,49 +4269,57 @@ $root.protos = (function() {
break; break;
} }
case 7: { case 7: {
message.moveforward = $root.sharedprotos.Vec2D.decode(reader, reader.uint32());
break;
}
case 8: {
message.hitboxOffset = reader.double(); message.hitboxOffset = reader.double();
break; break;
} }
case 9: { case 8: {
message.hitboxSize = $root.sharedprotos.Vec2D.decode(reader, reader.uint32());
break;
}
case 10: {
message.originatedRenderFrameId = reader.int32(); message.originatedRenderFrameId = reader.int32();
break; break;
} }
case 11: { case 9: {
message.hitStunFrames = reader.int32(); message.hitStunFrames = reader.int32();
break; break;
} }
case 12: { case 10: {
message.blockStunFrames = reader.int32(); message.blockStunFrames = reader.int32();
break; break;
} }
case 13: { case 11: {
message.pushback = reader.double(); message.pushback = reader.double();
break; break;
} }
case 14: { case 12: {
message.releaseTriggerType = reader.int32(); message.releaseTriggerType = reader.int32();
break; break;
} }
case 15: { case 13: {
message.damage = reader.int32(); message.damage = reader.int32();
break; break;
} }
case 16: { case 14: {
message.offenderJoinIndex = reader.int32(); message.offenderJoinIndex = reader.int32();
break; break;
} }
case 17: { case 15: {
message.offenderPlayerId = reader.int32(); message.offenderPlayerId = reader.int32();
break; break;
} }
case 16: {
message.hitboxSizeX = reader.double();
break;
}
case 17: {
message.hitboxSizeY = reader.double();
break;
}
case 18: {
message.selfMoveforwardX = reader.double();
break;
}
case 19: {
message.selfMoveforwardY = reader.double();
break;
}
default: default:
reader.skipType(tag & 7); reader.skipType(tag & 7);
break; break;
@ -4551,19 +4373,9 @@ $root.protos = (function() {
if (message.recoveryFramesOnHit != null && message.hasOwnProperty("recoveryFramesOnHit")) if (message.recoveryFramesOnHit != null && message.hasOwnProperty("recoveryFramesOnHit"))
if (!$util.isInteger(message.recoveryFramesOnHit)) if (!$util.isInteger(message.recoveryFramesOnHit))
return "recoveryFramesOnHit: integer expected"; return "recoveryFramesOnHit: integer expected";
if (message.moveforward != null && message.hasOwnProperty("moveforward")) {
var error = $root.sharedprotos.Vec2D.verify(message.moveforward);
if (error)
return "moveforward." + error;
}
if (message.hitboxOffset != null && message.hasOwnProperty("hitboxOffset")) if (message.hitboxOffset != null && message.hasOwnProperty("hitboxOffset"))
if (typeof message.hitboxOffset !== "number") if (typeof message.hitboxOffset !== "number")
return "hitboxOffset: number expected"; return "hitboxOffset: number expected";
if (message.hitboxSize != null && message.hasOwnProperty("hitboxSize")) {
var error = $root.sharedprotos.Vec2D.verify(message.hitboxSize);
if (error)
return "hitboxSize." + error;
}
if (message.originatedRenderFrameId != null && message.hasOwnProperty("originatedRenderFrameId")) if (message.originatedRenderFrameId != null && message.hasOwnProperty("originatedRenderFrameId"))
if (!$util.isInteger(message.originatedRenderFrameId)) if (!$util.isInteger(message.originatedRenderFrameId))
return "originatedRenderFrameId: integer expected"; return "originatedRenderFrameId: integer expected";
@ -4588,6 +4400,18 @@ $root.protos = (function() {
if (message.offenderPlayerId != null && message.hasOwnProperty("offenderPlayerId")) if (message.offenderPlayerId != null && message.hasOwnProperty("offenderPlayerId"))
if (!$util.isInteger(message.offenderPlayerId)) if (!$util.isInteger(message.offenderPlayerId))
return "offenderPlayerId: integer expected"; return "offenderPlayerId: integer expected";
if (message.hitboxSizeX != null && message.hasOwnProperty("hitboxSizeX"))
if (typeof message.hitboxSizeX !== "number")
return "hitboxSizeX: number expected";
if (message.hitboxSizeY != null && message.hasOwnProperty("hitboxSizeY"))
if (typeof message.hitboxSizeY !== "number")
return "hitboxSizeY: number expected";
if (message.selfMoveforwardX != null && message.hasOwnProperty("selfMoveforwardX"))
if (typeof message.selfMoveforwardX !== "number")
return "selfMoveforwardX: number expected";
if (message.selfMoveforwardY != null && message.hasOwnProperty("selfMoveforwardY"))
if (typeof message.selfMoveforwardY !== "number")
return "selfMoveforwardY: number expected";
return null; return null;
}; };
@ -4615,18 +4439,8 @@ $root.protos = (function() {
message.recoveryFramesOnBlock = object.recoveryFramesOnBlock | 0; message.recoveryFramesOnBlock = object.recoveryFramesOnBlock | 0;
if (object.recoveryFramesOnHit != null) if (object.recoveryFramesOnHit != null)
message.recoveryFramesOnHit = object.recoveryFramesOnHit | 0; message.recoveryFramesOnHit = object.recoveryFramesOnHit | 0;
if (object.moveforward != null) {
if (typeof object.moveforward !== "object")
throw TypeError(".protos.MeleeBullet.moveforward: object expected");
message.moveforward = $root.sharedprotos.Vec2D.fromObject(object.moveforward);
}
if (object.hitboxOffset != null) if (object.hitboxOffset != null)
message.hitboxOffset = Number(object.hitboxOffset); message.hitboxOffset = Number(object.hitboxOffset);
if (object.hitboxSize != null) {
if (typeof object.hitboxSize !== "object")
throw TypeError(".protos.MeleeBullet.hitboxSize: object expected");
message.hitboxSize = $root.sharedprotos.Vec2D.fromObject(object.hitboxSize);
}
if (object.originatedRenderFrameId != null) if (object.originatedRenderFrameId != null)
message.originatedRenderFrameId = object.originatedRenderFrameId | 0; message.originatedRenderFrameId = object.originatedRenderFrameId | 0;
if (object.hitStunFrames != null) if (object.hitStunFrames != null)
@ -4643,6 +4457,14 @@ $root.protos = (function() {
message.offenderJoinIndex = object.offenderJoinIndex | 0; message.offenderJoinIndex = object.offenderJoinIndex | 0;
if (object.offenderPlayerId != null) if (object.offenderPlayerId != null)
message.offenderPlayerId = object.offenderPlayerId | 0; message.offenderPlayerId = object.offenderPlayerId | 0;
if (object.hitboxSizeX != null)
message.hitboxSizeX = Number(object.hitboxSizeX);
if (object.hitboxSizeY != null)
message.hitboxSizeY = Number(object.hitboxSizeY);
if (object.selfMoveforwardX != null)
message.selfMoveforwardX = Number(object.selfMoveforwardX);
if (object.selfMoveforwardY != null)
message.selfMoveforwardY = Number(object.selfMoveforwardY);
return message; return message;
}; };
@ -4666,9 +4488,7 @@ $root.protos = (function() {
object.recoveryFrames = 0; object.recoveryFrames = 0;
object.recoveryFramesOnBlock = 0; object.recoveryFramesOnBlock = 0;
object.recoveryFramesOnHit = 0; object.recoveryFramesOnHit = 0;
object.moveforward = null;
object.hitboxOffset = 0; object.hitboxOffset = 0;
object.hitboxSize = null;
object.originatedRenderFrameId = 0; object.originatedRenderFrameId = 0;
object.hitStunFrames = 0; object.hitStunFrames = 0;
object.blockStunFrames = 0; object.blockStunFrames = 0;
@ -4677,6 +4497,10 @@ $root.protos = (function() {
object.damage = 0; object.damage = 0;
object.offenderJoinIndex = 0; object.offenderJoinIndex = 0;
object.offenderPlayerId = 0; object.offenderPlayerId = 0;
object.hitboxSizeX = 0;
object.hitboxSizeY = 0;
object.selfMoveforwardX = 0;
object.selfMoveforwardY = 0;
} }
if (message.battleLocalId != null && message.hasOwnProperty("battleLocalId")) if (message.battleLocalId != null && message.hasOwnProperty("battleLocalId"))
object.battleLocalId = message.battleLocalId; object.battleLocalId = message.battleLocalId;
@ -4690,12 +4514,8 @@ $root.protos = (function() {
object.recoveryFramesOnBlock = message.recoveryFramesOnBlock; object.recoveryFramesOnBlock = message.recoveryFramesOnBlock;
if (message.recoveryFramesOnHit != null && message.hasOwnProperty("recoveryFramesOnHit")) if (message.recoveryFramesOnHit != null && message.hasOwnProperty("recoveryFramesOnHit"))
object.recoveryFramesOnHit = message.recoveryFramesOnHit; object.recoveryFramesOnHit = message.recoveryFramesOnHit;
if (message.moveforward != null && message.hasOwnProperty("moveforward"))
object.moveforward = $root.sharedprotos.Vec2D.toObject(message.moveforward, options);
if (message.hitboxOffset != null && message.hasOwnProperty("hitboxOffset")) if (message.hitboxOffset != null && message.hasOwnProperty("hitboxOffset"))
object.hitboxOffset = options.json && !isFinite(message.hitboxOffset) ? String(message.hitboxOffset) : message.hitboxOffset; object.hitboxOffset = options.json && !isFinite(message.hitboxOffset) ? String(message.hitboxOffset) : message.hitboxOffset;
if (message.hitboxSize != null && message.hasOwnProperty("hitboxSize"))
object.hitboxSize = $root.sharedprotos.Vec2D.toObject(message.hitboxSize, options);
if (message.originatedRenderFrameId != null && message.hasOwnProperty("originatedRenderFrameId")) if (message.originatedRenderFrameId != null && message.hasOwnProperty("originatedRenderFrameId"))
object.originatedRenderFrameId = message.originatedRenderFrameId; object.originatedRenderFrameId = message.originatedRenderFrameId;
if (message.hitStunFrames != null && message.hasOwnProperty("hitStunFrames")) if (message.hitStunFrames != null && message.hasOwnProperty("hitStunFrames"))
@ -4712,6 +4532,14 @@ $root.protos = (function() {
object.offenderJoinIndex = message.offenderJoinIndex; object.offenderJoinIndex = message.offenderJoinIndex;
if (message.offenderPlayerId != null && message.hasOwnProperty("offenderPlayerId")) if (message.offenderPlayerId != null && message.hasOwnProperty("offenderPlayerId"))
object.offenderPlayerId = message.offenderPlayerId; object.offenderPlayerId = message.offenderPlayerId;
if (message.hitboxSizeX != null && message.hasOwnProperty("hitboxSizeX"))
object.hitboxSizeX = options.json && !isFinite(message.hitboxSizeX) ? String(message.hitboxSizeX) : message.hitboxSizeX;
if (message.hitboxSizeY != null && message.hasOwnProperty("hitboxSizeY"))
object.hitboxSizeY = options.json && !isFinite(message.hitboxSizeY) ? String(message.hitboxSizeY) : message.hitboxSizeY;
if (message.selfMoveforwardX != null && message.hasOwnProperty("selfMoveforwardX"))
object.selfMoveforwardX = options.json && !isFinite(message.selfMoveforwardX) ? String(message.selfMoveforwardX) : message.selfMoveforwardX;
if (message.selfMoveforwardY != null && message.hasOwnProperty("selfMoveforwardY"))
object.selfMoveforwardY = options.json && !isFinite(message.selfMoveforwardY) ? String(message.selfMoveforwardY) : message.selfMoveforwardY;
return object; return object;
}; };
@ -4751,8 +4579,6 @@ $root.protos = (function() {
* @memberof protos * @memberof protos
* @interface IBattleColliderInfo * @interface IBattleColliderInfo
* @property {string|null} [stageName] BattleColliderInfo stageName * @property {string|null} [stageName] BattleColliderInfo stageName
* @property {Object.<string,sharedprotos.Vec2DList>|null} [strToVec2DListMap] BattleColliderInfo strToVec2DListMap
* @property {Object.<string,sharedprotos.Polygon2DList>|null} [strToPolygon2DListMap] BattleColliderInfo strToPolygon2DListMap
* @property {number|null} [stageDiscreteW] BattleColliderInfo stageDiscreteW * @property {number|null} [stageDiscreteW] BattleColliderInfo stageDiscreteW
* @property {number|null} [stageDiscreteH] BattleColliderInfo stageDiscreteH * @property {number|null} [stageDiscreteH] BattleColliderInfo stageDiscreteH
* @property {number|null} [stageTileW] BattleColliderInfo stageTileW * @property {number|null} [stageTileW] BattleColliderInfo stageTileW
@ -4792,8 +4618,6 @@ $root.protos = (function() {
* @param {protos.IBattleColliderInfo=} [properties] Properties to set * @param {protos.IBattleColliderInfo=} [properties] Properties to set
*/ */
function BattleColliderInfo(properties) { function BattleColliderInfo(properties) {
this.strToVec2DListMap = {};
this.strToPolygon2DListMap = {};
this.meleeSkillConfig = {}; this.meleeSkillConfig = {};
if (properties) if (properties)
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
@ -4809,22 +4633,6 @@ $root.protos = (function() {
*/ */
BattleColliderInfo.prototype.stageName = ""; BattleColliderInfo.prototype.stageName = "";
/**
* BattleColliderInfo strToVec2DListMap.
* @member {Object.<string,sharedprotos.Vec2DList>} strToVec2DListMap
* @memberof protos.BattleColliderInfo
* @instance
*/
BattleColliderInfo.prototype.strToVec2DListMap = $util.emptyObject;
/**
* BattleColliderInfo strToPolygon2DListMap.
* @member {Object.<string,sharedprotos.Polygon2DList>} strToPolygon2DListMap
* @memberof protos.BattleColliderInfo
* @instance
*/
BattleColliderInfo.prototype.strToPolygon2DListMap = $util.emptyObject;
/** /**
* BattleColliderInfo stageDiscreteW. * BattleColliderInfo stageDiscreteW.
* @member {number} stageDiscreteW * @member {number} stageDiscreteW
@ -5075,75 +4883,65 @@ $root.protos = (function() {
writer = $Writer.create(); writer = $Writer.create();
if (message.stageName != null && Object.hasOwnProperty.call(message, "stageName")) if (message.stageName != null && Object.hasOwnProperty.call(message, "stageName"))
writer.uint32(/* id 1, wireType 2 =*/10).string(message.stageName); writer.uint32(/* id 1, wireType 2 =*/10).string(message.stageName);
if (message.strToVec2DListMap != null && Object.hasOwnProperty.call(message, "strToVec2DListMap"))
for (var keys = Object.keys(message.strToVec2DListMap), i = 0; i < keys.length; ++i) {
writer.uint32(/* id 2, wireType 2 =*/18).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]);
$root.sharedprotos.Vec2DList.encode(message.strToVec2DListMap[keys[i]], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim().ldelim();
}
if (message.strToPolygon2DListMap != null && Object.hasOwnProperty.call(message, "strToPolygon2DListMap"))
for (var keys = Object.keys(message.strToPolygon2DListMap), i = 0; i < keys.length; ++i) {
writer.uint32(/* id 3, wireType 2 =*/26).fork().uint32(/* id 1, wireType 2 =*/10).string(keys[i]);
$root.sharedprotos.Polygon2DList.encode(message.strToPolygon2DListMap[keys[i]], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim().ldelim();
}
if (message.stageDiscreteW != null && Object.hasOwnProperty.call(message, "stageDiscreteW")) if (message.stageDiscreteW != null && Object.hasOwnProperty.call(message, "stageDiscreteW"))
writer.uint32(/* id 4, wireType 0 =*/32).int32(message.stageDiscreteW); writer.uint32(/* id 2, wireType 0 =*/16).int32(message.stageDiscreteW);
if (message.stageDiscreteH != null && Object.hasOwnProperty.call(message, "stageDiscreteH")) if (message.stageDiscreteH != null && Object.hasOwnProperty.call(message, "stageDiscreteH"))
writer.uint32(/* id 5, wireType 0 =*/40).int32(message.stageDiscreteH); writer.uint32(/* id 3, wireType 0 =*/24).int32(message.stageDiscreteH);
if (message.stageTileW != null && Object.hasOwnProperty.call(message, "stageTileW")) if (message.stageTileW != null && Object.hasOwnProperty.call(message, "stageTileW"))
writer.uint32(/* id 6, wireType 0 =*/48).int32(message.stageTileW); writer.uint32(/* id 4, wireType 0 =*/32).int32(message.stageTileW);
if (message.stageTileH != null && Object.hasOwnProperty.call(message, "stageTileH")) if (message.stageTileH != null && Object.hasOwnProperty.call(message, "stageTileH"))
writer.uint32(/* id 7, wireType 0 =*/56).int32(message.stageTileH); writer.uint32(/* id 5, wireType 0 =*/40).int32(message.stageTileH);
if (message.intervalToPing != null && Object.hasOwnProperty.call(message, "intervalToPing")) if (message.intervalToPing != null && Object.hasOwnProperty.call(message, "intervalToPing"))
writer.uint32(/* id 8, wireType 0 =*/64).int32(message.intervalToPing); writer.uint32(/* id 6, wireType 0 =*/48).int32(message.intervalToPing);
if (message.willKickIfInactiveFor != null && Object.hasOwnProperty.call(message, "willKickIfInactiveFor")) if (message.willKickIfInactiveFor != null && Object.hasOwnProperty.call(message, "willKickIfInactiveFor"))
writer.uint32(/* id 9, wireType 0 =*/72).int32(message.willKickIfInactiveFor); writer.uint32(/* id 7, wireType 0 =*/56).int32(message.willKickIfInactiveFor);
if (message.boundRoomId != null && Object.hasOwnProperty.call(message, "boundRoomId")) if (message.boundRoomId != null && Object.hasOwnProperty.call(message, "boundRoomId"))
writer.uint32(/* id 10, wireType 0 =*/80).int32(message.boundRoomId); writer.uint32(/* id 8, wireType 0 =*/64).int32(message.boundRoomId);
if (message.battleDurationFrames != null && Object.hasOwnProperty.call(message, "battleDurationFrames")) if (message.battleDurationFrames != null && Object.hasOwnProperty.call(message, "battleDurationFrames"))
writer.uint32(/* id 12, wireType 0 =*/96).int32(message.battleDurationFrames); writer.uint32(/* id 9, wireType 0 =*/72).int32(message.battleDurationFrames);
if (message.battleDurationNanos != null && Object.hasOwnProperty.call(message, "battleDurationNanos")) if (message.battleDurationNanos != null && Object.hasOwnProperty.call(message, "battleDurationNanos"))
writer.uint32(/* id 13, wireType 0 =*/104).int64(message.battleDurationNanos); writer.uint32(/* id 10, wireType 0 =*/80).int64(message.battleDurationNanos);
if (message.serverFps != null && Object.hasOwnProperty.call(message, "serverFps")) if (message.serverFps != null && Object.hasOwnProperty.call(message, "serverFps"))
writer.uint32(/* id 14, wireType 0 =*/112).int32(message.serverFps); writer.uint32(/* id 11, wireType 0 =*/88).int32(message.serverFps);
if (message.inputDelayFrames != null && Object.hasOwnProperty.call(message, "inputDelayFrames")) if (message.inputDelayFrames != null && Object.hasOwnProperty.call(message, "inputDelayFrames"))
writer.uint32(/* id 15, wireType 0 =*/120).int32(message.inputDelayFrames); writer.uint32(/* id 12, wireType 0 =*/96).int32(message.inputDelayFrames);
if (message.inputScaleFrames != null && Object.hasOwnProperty.call(message, "inputScaleFrames")) if (message.inputScaleFrames != null && Object.hasOwnProperty.call(message, "inputScaleFrames"))
writer.uint32(/* id 16, wireType 0 =*/128).uint32(message.inputScaleFrames); writer.uint32(/* id 13, wireType 0 =*/104).uint32(message.inputScaleFrames);
if (message.nstDelayFrames != null && Object.hasOwnProperty.call(message, "nstDelayFrames")) if (message.nstDelayFrames != null && Object.hasOwnProperty.call(message, "nstDelayFrames"))
writer.uint32(/* id 17, wireType 0 =*/136).int32(message.nstDelayFrames); writer.uint32(/* id 14, wireType 0 =*/112).int32(message.nstDelayFrames);
if (message.inputFrameUpsyncDelayTolerance != null && Object.hasOwnProperty.call(message, "inputFrameUpsyncDelayTolerance")) if (message.inputFrameUpsyncDelayTolerance != null && Object.hasOwnProperty.call(message, "inputFrameUpsyncDelayTolerance"))
writer.uint32(/* id 18, wireType 0 =*/144).int32(message.inputFrameUpsyncDelayTolerance); writer.uint32(/* id 15, wireType 0 =*/120).int32(message.inputFrameUpsyncDelayTolerance);
if (message.maxChasingRenderFramesPerUpdate != null && Object.hasOwnProperty.call(message, "maxChasingRenderFramesPerUpdate")) if (message.maxChasingRenderFramesPerUpdate != null && Object.hasOwnProperty.call(message, "maxChasingRenderFramesPerUpdate"))
writer.uint32(/* id 19, wireType 0 =*/152).int32(message.maxChasingRenderFramesPerUpdate); writer.uint32(/* id 16, wireType 0 =*/128).int32(message.maxChasingRenderFramesPerUpdate);
if (message.playerBattleState != null && Object.hasOwnProperty.call(message, "playerBattleState")) if (message.playerBattleState != null && Object.hasOwnProperty.call(message, "playerBattleState"))
writer.uint32(/* id 20, wireType 0 =*/160).int32(message.playerBattleState); writer.uint32(/* id 17, wireType 0 =*/136).int32(message.playerBattleState);
if (message.rollbackEstimatedDtMillis != null && Object.hasOwnProperty.call(message, "rollbackEstimatedDtMillis")) if (message.rollbackEstimatedDtMillis != null && Object.hasOwnProperty.call(message, "rollbackEstimatedDtMillis"))
writer.uint32(/* id 21, wireType 1 =*/169).double(message.rollbackEstimatedDtMillis); writer.uint32(/* id 18, wireType 1 =*/145).double(message.rollbackEstimatedDtMillis);
if (message.rollbackEstimatedDtNanos != null && Object.hasOwnProperty.call(message, "rollbackEstimatedDtNanos")) if (message.rollbackEstimatedDtNanos != null && Object.hasOwnProperty.call(message, "rollbackEstimatedDtNanos"))
writer.uint32(/* id 22, wireType 0 =*/176).int64(message.rollbackEstimatedDtNanos); writer.uint32(/* id 19, wireType 0 =*/152).int64(message.rollbackEstimatedDtNanos);
if (message.worldToVirtualGridRatio != null && Object.hasOwnProperty.call(message, "worldToVirtualGridRatio")) if (message.worldToVirtualGridRatio != null && Object.hasOwnProperty.call(message, "worldToVirtualGridRatio"))
writer.uint32(/* id 23, wireType 1 =*/185).double(message.worldToVirtualGridRatio); writer.uint32(/* id 20, wireType 1 =*/161).double(message.worldToVirtualGridRatio);
if (message.virtualGridToWorldRatio != null && Object.hasOwnProperty.call(message, "virtualGridToWorldRatio")) if (message.virtualGridToWorldRatio != null && Object.hasOwnProperty.call(message, "virtualGridToWorldRatio"))
writer.uint32(/* id 24, wireType 1 =*/193).double(message.virtualGridToWorldRatio); writer.uint32(/* id 21, wireType 1 =*/169).double(message.virtualGridToWorldRatio);
if (message.spAtkLookupFrames != null && Object.hasOwnProperty.call(message, "spAtkLookupFrames")) if (message.spAtkLookupFrames != null && Object.hasOwnProperty.call(message, "spAtkLookupFrames"))
writer.uint32(/* id 25, wireType 0 =*/200).int32(message.spAtkLookupFrames); writer.uint32(/* id 22, wireType 0 =*/176).int32(message.spAtkLookupFrames);
if (message.renderCacheSize != null && Object.hasOwnProperty.call(message, "renderCacheSize")) if (message.renderCacheSize != null && Object.hasOwnProperty.call(message, "renderCacheSize"))
writer.uint32(/* id 26, wireType 0 =*/208).int32(message.renderCacheSize); writer.uint32(/* id 23, wireType 0 =*/184).int32(message.renderCacheSize);
if (message.meleeSkillConfig != null && Object.hasOwnProperty.call(message, "meleeSkillConfig")) if (message.meleeSkillConfig != null && Object.hasOwnProperty.call(message, "meleeSkillConfig"))
for (var keys = Object.keys(message.meleeSkillConfig), i = 0; i < keys.length; ++i) { for (var keys = Object.keys(message.meleeSkillConfig), i = 0; i < keys.length; ++i) {
writer.uint32(/* id 27, wireType 2 =*/218).fork().uint32(/* id 1, wireType 0 =*/8).int32(keys[i]); writer.uint32(/* id 24, wireType 2 =*/194).fork().uint32(/* id 1, wireType 0 =*/8).int32(keys[i]);
$root.protos.MeleeBullet.encode(message.meleeSkillConfig[keys[i]], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim().ldelim(); $root.protos.MeleeBullet.encode(message.meleeSkillConfig[keys[i]], writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim().ldelim();
} }
if (message.snapIntoPlatformOverlap != null && Object.hasOwnProperty.call(message, "snapIntoPlatformOverlap")) if (message.snapIntoPlatformOverlap != null && Object.hasOwnProperty.call(message, "snapIntoPlatformOverlap"))
writer.uint32(/* id 28, wireType 1 =*/225).double(message.snapIntoPlatformOverlap); writer.uint32(/* id 25, wireType 1 =*/201).double(message.snapIntoPlatformOverlap);
if (message.snapIntoPlatformThreshold != null && Object.hasOwnProperty.call(message, "snapIntoPlatformThreshold")) if (message.snapIntoPlatformThreshold != null && Object.hasOwnProperty.call(message, "snapIntoPlatformThreshold"))
writer.uint32(/* id 29, wireType 1 =*/233).double(message.snapIntoPlatformThreshold); writer.uint32(/* id 26, wireType 1 =*/209).double(message.snapIntoPlatformThreshold);
if (message.jumpingInitVelY != null && Object.hasOwnProperty.call(message, "jumpingInitVelY")) if (message.jumpingInitVelY != null && Object.hasOwnProperty.call(message, "jumpingInitVelY"))
writer.uint32(/* id 30, wireType 0 =*/240).int32(message.jumpingInitVelY); writer.uint32(/* id 27, wireType 0 =*/216).int32(message.jumpingInitVelY);
if (message.gravityX != null && Object.hasOwnProperty.call(message, "gravityX")) if (message.gravityX != null && Object.hasOwnProperty.call(message, "gravityX"))
writer.uint32(/* id 31, wireType 0 =*/248).int32(message.gravityX); writer.uint32(/* id 28, wireType 0 =*/224).int32(message.gravityX);
if (message.gravityY != null && Object.hasOwnProperty.call(message, "gravityY")) if (message.gravityY != null && Object.hasOwnProperty.call(message, "gravityY"))
writer.uint32(/* id 32, wireType 0 =*/256).int32(message.gravityY); writer.uint32(/* id 29, wireType 0 =*/232).int32(message.gravityY);
return writer; return writer;
}; };
@ -5183,140 +4981,94 @@ $root.protos = (function() {
break; break;
} }
case 2: { case 2: {
if (message.strToVec2DListMap === $util.emptyObject)
message.strToVec2DListMap = {};
var end2 = reader.uint32() + reader.pos;
key = "";
value = null;
while (reader.pos < end2) {
var tag2 = reader.uint32();
switch (tag2 >>> 3) {
case 1:
key = reader.string();
break;
case 2:
value = $root.sharedprotos.Vec2DList.decode(reader, reader.uint32());
break;
default:
reader.skipType(tag2 & 7);
break;
}
}
message.strToVec2DListMap[key] = value;
break;
}
case 3: {
if (message.strToPolygon2DListMap === $util.emptyObject)
message.strToPolygon2DListMap = {};
var end2 = reader.uint32() + reader.pos;
key = "";
value = null;
while (reader.pos < end2) {
var tag2 = reader.uint32();
switch (tag2 >>> 3) {
case 1:
key = reader.string();
break;
case 2:
value = $root.sharedprotos.Polygon2DList.decode(reader, reader.uint32());
break;
default:
reader.skipType(tag2 & 7);
break;
}
}
message.strToPolygon2DListMap[key] = value;
break;
}
case 4: {
message.stageDiscreteW = reader.int32(); message.stageDiscreteW = reader.int32();
break; break;
} }
case 5: { case 3: {
message.stageDiscreteH = reader.int32(); message.stageDiscreteH = reader.int32();
break; break;
} }
case 6: { case 4: {
message.stageTileW = reader.int32(); message.stageTileW = reader.int32();
break; break;
} }
case 7: { case 5: {
message.stageTileH = reader.int32(); message.stageTileH = reader.int32();
break; break;
} }
case 8: { case 6: {
message.intervalToPing = reader.int32(); message.intervalToPing = reader.int32();
break; break;
} }
case 9: { case 7: {
message.willKickIfInactiveFor = reader.int32(); message.willKickIfInactiveFor = reader.int32();
break; break;
} }
case 10: { case 8: {
message.boundRoomId = reader.int32(); message.boundRoomId = reader.int32();
break; break;
} }
case 12: { case 9: {
message.battleDurationFrames = reader.int32(); message.battleDurationFrames = reader.int32();
break; break;
} }
case 13: { case 10: {
message.battleDurationNanos = reader.int64(); message.battleDurationNanos = reader.int64();
break; break;
} }
case 14: { case 11: {
message.serverFps = reader.int32(); message.serverFps = reader.int32();
break; break;
} }
case 15: { case 12: {
message.inputDelayFrames = reader.int32(); message.inputDelayFrames = reader.int32();
break; break;
} }
case 16: { case 13: {
message.inputScaleFrames = reader.uint32(); message.inputScaleFrames = reader.uint32();
break; break;
} }
case 17: { case 14: {
message.nstDelayFrames = reader.int32(); message.nstDelayFrames = reader.int32();
break; break;
} }
case 18: { case 15: {
message.inputFrameUpsyncDelayTolerance = reader.int32(); message.inputFrameUpsyncDelayTolerance = reader.int32();
break; break;
} }
case 19: { case 16: {
message.maxChasingRenderFramesPerUpdate = reader.int32(); message.maxChasingRenderFramesPerUpdate = reader.int32();
break; break;
} }
case 20: { case 17: {
message.playerBattleState = reader.int32(); message.playerBattleState = reader.int32();
break; break;
} }
case 21: { case 18: {
message.rollbackEstimatedDtMillis = reader.double(); message.rollbackEstimatedDtMillis = reader.double();
break; break;
} }
case 22: { case 19: {
message.rollbackEstimatedDtNanos = reader.int64(); message.rollbackEstimatedDtNanos = reader.int64();
break; break;
} }
case 23: { case 20: {
message.worldToVirtualGridRatio = reader.double(); message.worldToVirtualGridRatio = reader.double();
break; break;
} }
case 24: { case 21: {
message.virtualGridToWorldRatio = reader.double(); message.virtualGridToWorldRatio = reader.double();
break; break;
} }
case 25: { case 22: {
message.spAtkLookupFrames = reader.int32(); message.spAtkLookupFrames = reader.int32();
break; break;
} }
case 26: { case 23: {
message.renderCacheSize = reader.int32(); message.renderCacheSize = reader.int32();
break; break;
} }
case 27: { case 24: {
if (message.meleeSkillConfig === $util.emptyObject) if (message.meleeSkillConfig === $util.emptyObject)
message.meleeSkillConfig = {}; message.meleeSkillConfig = {};
var end2 = reader.uint32() + reader.pos; var end2 = reader.uint32() + reader.pos;
@ -5339,23 +5091,23 @@ $root.protos = (function() {
message.meleeSkillConfig[key] = value; message.meleeSkillConfig[key] = value;
break; break;
} }
case 28: { case 25: {
message.snapIntoPlatformOverlap = reader.double(); message.snapIntoPlatformOverlap = reader.double();
break; break;
} }
case 29: { case 26: {
message.snapIntoPlatformThreshold = reader.double(); message.snapIntoPlatformThreshold = reader.double();
break; break;
} }
case 30: { case 27: {
message.jumpingInitVelY = reader.int32(); message.jumpingInitVelY = reader.int32();
break; break;
} }
case 31: { case 28: {
message.gravityX = reader.int32(); message.gravityX = reader.int32();
break; break;
} }
case 32: { case 29: {
message.gravityY = reader.int32(); message.gravityY = reader.int32();
break; break;
} }
@ -5397,26 +5149,6 @@ $root.protos = (function() {
if (message.stageName != null && message.hasOwnProperty("stageName")) if (message.stageName != null && message.hasOwnProperty("stageName"))
if (!$util.isString(message.stageName)) if (!$util.isString(message.stageName))
return "stageName: string expected"; return "stageName: string expected";
if (message.strToVec2DListMap != null && message.hasOwnProperty("strToVec2DListMap")) {
if (!$util.isObject(message.strToVec2DListMap))
return "strToVec2DListMap: object expected";
var key = Object.keys(message.strToVec2DListMap);
for (var i = 0; i < key.length; ++i) {
var error = $root.sharedprotos.Vec2DList.verify(message.strToVec2DListMap[key[i]]);
if (error)
return "strToVec2DListMap." + error;
}
}
if (message.strToPolygon2DListMap != null && message.hasOwnProperty("strToPolygon2DListMap")) {
if (!$util.isObject(message.strToPolygon2DListMap))
return "strToPolygon2DListMap: object expected";
var key = Object.keys(message.strToPolygon2DListMap);
for (var i = 0; i < key.length; ++i) {
var error = $root.sharedprotos.Polygon2DList.verify(message.strToPolygon2DListMap[key[i]]);
if (error)
return "strToPolygon2DListMap." + error;
}
}
if (message.stageDiscreteW != null && message.hasOwnProperty("stageDiscreteW")) if (message.stageDiscreteW != null && message.hasOwnProperty("stageDiscreteW"))
if (!$util.isInteger(message.stageDiscreteW)) if (!$util.isInteger(message.stageDiscreteW))
return "stageDiscreteW: integer expected"; return "stageDiscreteW: integer expected";
@ -5529,26 +5261,6 @@ $root.protos = (function() {
var message = new $root.protos.BattleColliderInfo(); var message = new $root.protos.BattleColliderInfo();
if (object.stageName != null) if (object.stageName != null)
message.stageName = String(object.stageName); message.stageName = String(object.stageName);
if (object.strToVec2DListMap) {
if (typeof object.strToVec2DListMap !== "object")
throw TypeError(".protos.BattleColliderInfo.strToVec2DListMap: object expected");
message.strToVec2DListMap = {};
for (var keys = Object.keys(object.strToVec2DListMap), i = 0; i < keys.length; ++i) {
if (typeof object.strToVec2DListMap[keys[i]] !== "object")
throw TypeError(".protos.BattleColliderInfo.strToVec2DListMap: object expected");
message.strToVec2DListMap[keys[i]] = $root.sharedprotos.Vec2DList.fromObject(object.strToVec2DListMap[keys[i]]);
}
}
if (object.strToPolygon2DListMap) {
if (typeof object.strToPolygon2DListMap !== "object")
throw TypeError(".protos.BattleColliderInfo.strToPolygon2DListMap: object expected");
message.strToPolygon2DListMap = {};
for (var keys = Object.keys(object.strToPolygon2DListMap), i = 0; i < keys.length; ++i) {
if (typeof object.strToPolygon2DListMap[keys[i]] !== "object")
throw TypeError(".protos.BattleColliderInfo.strToPolygon2DListMap: object expected");
message.strToPolygon2DListMap[keys[i]] = $root.sharedprotos.Polygon2DList.fromObject(object.strToPolygon2DListMap[keys[i]]);
}
}
if (object.stageDiscreteW != null) if (object.stageDiscreteW != null)
message.stageDiscreteW = object.stageDiscreteW | 0; message.stageDiscreteW = object.stageDiscreteW | 0;
if (object.stageDiscreteH != null) if (object.stageDiscreteH != null)
@ -5643,11 +5355,8 @@ $root.protos = (function() {
if (!options) if (!options)
options = {}; options = {};
var object = {}; var object = {};
if (options.objects || options.defaults) { if (options.objects || options.defaults)
object.strToVec2DListMap = {};
object.strToPolygon2DListMap = {};
object.meleeSkillConfig = {}; object.meleeSkillConfig = {};
}
if (options.defaults) { if (options.defaults) {
object.stageName = ""; object.stageName = "";
object.stageDiscreteW = 0; object.stageDiscreteW = 0;
@ -5688,17 +5397,6 @@ $root.protos = (function() {
} }
if (message.stageName != null && message.hasOwnProperty("stageName")) if (message.stageName != null && message.hasOwnProperty("stageName"))
object.stageName = message.stageName; object.stageName = message.stageName;
var keys2;
if (message.strToVec2DListMap && (keys2 = Object.keys(message.strToVec2DListMap)).length) {
object.strToVec2DListMap = {};
for (var j = 0; j < keys2.length; ++j)
object.strToVec2DListMap[keys2[j]] = $root.sharedprotos.Vec2DList.toObject(message.strToVec2DListMap[keys2[j]], options);
}
if (message.strToPolygon2DListMap && (keys2 = Object.keys(message.strToPolygon2DListMap)).length) {
object.strToPolygon2DListMap = {};
for (var j = 0; j < keys2.length; ++j)
object.strToPolygon2DListMap[keys2[j]] = $root.sharedprotos.Polygon2DList.toObject(message.strToPolygon2DListMap[keys2[j]], options);
}
if (message.stageDiscreteW != null && message.hasOwnProperty("stageDiscreteW")) if (message.stageDiscreteW != null && message.hasOwnProperty("stageDiscreteW"))
object.stageDiscreteW = message.stageDiscreteW; object.stageDiscreteW = message.stageDiscreteW;
if (message.stageDiscreteH != null && message.hasOwnProperty("stageDiscreteH")) if (message.stageDiscreteH != null && message.hasOwnProperty("stageDiscreteH"))
@ -5749,6 +5447,7 @@ $root.protos = (function() {
object.spAtkLookupFrames = message.spAtkLookupFrames; object.spAtkLookupFrames = message.spAtkLookupFrames;
if (message.renderCacheSize != null && message.hasOwnProperty("renderCacheSize")) if (message.renderCacheSize != null && message.hasOwnProperty("renderCacheSize"))
object.renderCacheSize = message.renderCacheSize; object.renderCacheSize = message.renderCacheSize;
var keys2;
if (message.meleeSkillConfig && (keys2 = Object.keys(message.meleeSkillConfig)).length) { if (message.meleeSkillConfig && (keys2 = Object.keys(message.meleeSkillConfig)).length) {
object.meleeSkillConfig = {}; object.meleeSkillConfig = {};
for (var j = 0; j < keys2.length; ++j) for (var j = 0; j < keys2.length; ++j)

View File

@ -43,7 +43,7 @@ func ConvertToInputFrameId(renderFrameId int32, inputDelayFrames int32, inputSca
return ((renderFrameId - inputDelayFrames) >> inputScaleFrames) return ((renderFrameId - inputDelayFrames) >> inputScaleFrames)
} }
func DecodeInput(encodedInput uint64) *InputFrameDecoded { func decodeInput(encodedInput uint64) *InputFrameDecoded {
encodedDirection := (encodedInput & uint64(15)) encodedDirection := (encodedInput & uint64(15))
btnALevel := int32((encodedInput >> 4) & 1) btnALevel := int32((encodedInput >> 4) & 1)
btnBLevel := int32((encodedInput >> 5) & 1) btnBLevel := int32((encodedInput >> 5) & 1)
@ -255,7 +255,7 @@ func VirtualGridToPolygonColliderBLPos(vx, vy int32, halfBoundingW, halfBounding
return WorldToPolygonColliderBLPos(wx, wy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY) return WorldToPolygonColliderBLPos(wx, wy, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, collisionSpaceOffsetX, collisionSpaceOffsetY)
} }
func CalcHardPushbacksNorms(playerCollider *resolv.Object, playerShape *resolv.ConvexPolygon, snapIntoPlatformOverlap float64, pEffPushback *Vec2D) []Vec2D { func calcHardPushbacksNorms(playerCollider *resolv.Object, playerShape *resolv.ConvexPolygon, snapIntoPlatformOverlap float64, pEffPushback *Vec2D) []Vec2D {
ret := make([]Vec2D, 0, 10) // no one would simultaneously have more than 5 hardPushbacks ret := make([]Vec2D, 0, 10) // no one would simultaneously have more than 5 hardPushbacks
collision := playerCollider.Check(0, 0) collision := playerCollider.Check(0, 0)
if nil == collision { if nil == collision {
@ -281,8 +281,9 @@ func CalcHardPushbacksNorms(playerCollider *resolv.Object, playerShape *resolv.C
return ret return ret
} }
func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, delayedInputFrameForPrevRenderFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames int32, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio float64) *RoomDownsyncFrame { // [WARNING] The params of this method is carefully tuned such that only "battle.RoomDownsyncFrame" is a necessary custom struct.
// [WARNING] This function MUST BE called while "InputsBufferLock" is locked! func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputList, delayedInputListForPrevRenderFrame []uint64, currRenderFrame *RoomDownsyncFrame, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames int32, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio float64) *RoomDownsyncFrame {
// [WARNING] On backend this function MUST BE called while "InputsBufferLock" is locked!
roomCapacity := len(currRenderFrame.PlayersArr) roomCapacity := len(currRenderFrame.PlayersArr)
nextRenderFramePlayers := make([]*PlayerDownsync, roomCapacity) nextRenderFramePlayers := make([]*PlayerDownsync, roomCapacity)
// Make a copy first // Make a copy first
@ -315,18 +316,17 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, delay
hardPushbackNorms := make([][]Vec2D, roomCapacity) hardPushbackNorms := make([][]Vec2D, roomCapacity)
// 1. Process player inputs // 1. Process player inputs
if nil != delayedInputFrame { if nil != delayedInputList {
inputList := delayedInputFrame.InputList
for i, currPlayerDownsync := range currRenderFrame.PlayersArr { for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
joinIndex := currPlayerDownsync.JoinIndex joinIndex := currPlayerDownsync.JoinIndex
thatPlayerInNextFrame := nextRenderFramePlayers[i] thatPlayerInNextFrame := nextRenderFramePlayers[i]
if 0 < thatPlayerInNextFrame.FramesToRecover { if 0 < thatPlayerInNextFrame.FramesToRecover {
continue continue
} }
decodedInput := DecodeInput(inputList[joinIndex-1]) decodedInput := decodeInput(delayedInputList[joinIndex-1])
prevBtnBLevel := int32(0) prevBtnBLevel := int32(0)
if nil != delayedInputFrameForPrevRenderFrame { if nil != delayedInputListForPrevRenderFrame {
prevDecodedInput := DecodeInput(delayedInputFrameForPrevRenderFrame.InputList[joinIndex-1]) prevDecodedInput := decodeInput(delayedInputListForPrevRenderFrame[joinIndex-1])
prevBtnBLevel = prevDecodedInput.BtnBLevel prevBtnBLevel = prevDecodedInput.BtnBLevel
} }
@ -386,7 +386,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, delay
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
playerCollider := collisionSysMap[collisionPlayerIndex] playerCollider := collisionSysMap[collisionPlayerIndex]
playerShape := playerCollider.Shape.(*resolv.ConvexPolygon) playerShape := playerCollider.Shape.(*resolv.ConvexPolygon)
hardPushbackNorms[joinIndex-1] = CalcHardPushbacksNorms(playerCollider, playerShape, snapIntoPlatformOverlap, &(effPushbacks[joinIndex-1])) hardPushbackNorms[joinIndex-1] = calcHardPushbacksNorms(playerCollider, playerShape, snapIntoPlatformOverlap, &(effPushbacks[joinIndex-1]))
thatPlayerInNextFrame := nextRenderFramePlayers[i] thatPlayerInNextFrame := nextRenderFramePlayers[i]
fallStopping := false fallStopping := false
if collision := playerCollider.Check(0, 0); nil != collision { if collision := playerCollider.Check(0, 0); nil != collision {
@ -394,12 +394,13 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, delay
isBarrier, isAnotherPlayer, isBullet := false, false, false isBarrier, isAnotherPlayer, isBullet := false, false, false
// TODO: Make this part work in JavaScript without having to expose all types Barrier/PlayerDownsync/MeleeBullet by js.MakeWrapper. // TODO: Make this part work in JavaScript without having to expose all types Barrier/PlayerDownsync/MeleeBullet by js.MakeWrapper.
switch obj.Data.(type) { switch obj.Data.(type) {
case *Barrier:
isBarrier = true
case *PlayerDownsync: case *PlayerDownsync:
isAnotherPlayer = true isAnotherPlayer = true
case *MeleeBullet: case *MeleeBullet:
isBullet = true isBullet = true
default:
// By default it's a regular barrier, even if data is nil
isBarrier = true
} }
if isBullet { if isBullet {
// ignore bullets for this step // ignore bullets for this step

View File

@ -47,12 +47,6 @@ type InputFrameUpsync struct {
Encoded uint64 Encoded uint64
} }
type InputFrameDownsync struct {
InputFrameId int32
InputList []uint64
ConfirmedList uint64
}
type Barrier struct { type Barrier struct {
Boundary *Polygon2D Boundary *Polygon2D
} }

View File

@ -58,14 +58,6 @@ func NewRoomDownsyncFrameJs(id int32, playersArr []*PlayerDownsync, meleeBullets
}) })
} }
func NewInputFrameDownsyncJs(inputFrameId int32, inputList []uint64, confirmedList uint64) *js.Object {
return js.MakeFullWrapper(&InputFrameDownsync{
InputFrameId: inputFrameId,
InputList: inputList,
ConfirmedList: confirmedList,
})
}
func GetCollisionSpaceObjsJs(space *resolv.Space) []*js.Object { func GetCollisionSpaceObjsJs(space *resolv.Space) []*js.Object {
objs := space.Objects() objs := space.Objects()
ret := make([]*js.Object, 0, len(objs)) ret := make([]*js.Object, 0, len(objs))
@ -110,9 +102,9 @@ func CheckCollisionJs(obj *resolv.Object, dx, dy float64) *js.Object {
return js.MakeFullWrapper(obj.Check(dx, dy)) return js.MakeFullWrapper(obj.Check(dx, dy))
} }
func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrameJs(delayedInputFrame, delayedInputFrameForPrevRenderFrame *InputFrameDownsync, currRenderFrame *RoomDownsyncFrame, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames int32, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio float64) *js.Object { func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrameJs(delayedInputList, delayedInputListForPrevRenderFrame []uint64, currRenderFrame *RoomDownsyncFrame, collisionSys *resolv.Space, collisionSysMap map[int32]*resolv.Object, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames int32, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio float64) *js.Object {
// We need access to all fields of RoomDownsyncFrame for displaying in frontend // We need access to all fields of RoomDownsyncFrame for displaying in frontend
return js.MakeFullWrapper(ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, delayedInputFrameForPrevRenderFrame, currRenderFrame, collisionSys, collisionSysMap, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio)) return js.MakeFullWrapper(ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputList, delayedInputListForPrevRenderFrame, currRenderFrame, collisionSys, collisionSysMap, gravityX, gravityY, jumpingInitVelY, inputDelayFrames, inputScaleFrames, collisionSpaceOffsetX, collisionSpaceOffsetY, snapIntoPlatformOverlap, snapIntoPlatformThreshold, worldToVirtualGridRatio, virtualGridToWorldRatio))
} }
func main() { func main() {
@ -123,7 +115,6 @@ func main() {
"NewPlayerDownsyncJs": NewPlayerDownsyncJs, "NewPlayerDownsyncJs": NewPlayerDownsyncJs,
"NewRoomDownsyncFrameJs": NewRoomDownsyncFrameJs, "NewRoomDownsyncFrameJs": NewRoomDownsyncFrameJs,
"NewCollisionSpaceJs": NewCollisionSpaceJs, "NewCollisionSpaceJs": NewCollisionSpaceJs,
"NewInputFrameDownsyncJs": NewInputFrameDownsyncJs,
"GenerateRectColliderJs": GenerateRectColliderJs, "GenerateRectColliderJs": GenerateRectColliderJs,
"GenerateConvexPolygonColliderJs": GenerateConvexPolygonColliderJs, "GenerateConvexPolygonColliderJs": GenerateConvexPolygonColliderJs,
"GetPlayersArrJs": GetPlayersArrJs, "GetPlayersArrJs": GetPlayersArrJs,

View File

@ -6,7 +6,7 @@
golang_basedir_1=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/dnmshared golang_basedir_1=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/dnmshared
protoc -I=$golang_basedir_1/../frontend/assets/resources/pbfiles/ --go_out=. geometry.proto protoc -I=$golang_basedir_1/../frontend/assets/resources/pbfiles/ --go_out=. geometry.proto
echo "GOLANG part 1 done" echo "GOLANG part 1 done" # [WARNING] The output of "part 1" is DEPRECATED, the codes are not using it anymore.
# [WARNING] The following "room_downsync_frame.proto" is generated in another Go package than "geometry.proto", but the generated Go codes are also required to work with imports correctly! # [WARNING] The following "room_downsync_frame.proto" is generated in another Go package than "geometry.proto", but the generated Go codes are also required to work with imports correctly!
golang_basedir_2=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/battle_srv golang_basedir_2=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/battle_srv