mirror of
https://github.com/genxium/DelayNoMore
synced 2024-12-25 03:08:57 +00:00
Temp broken commit, refactoring battle_srv to use jsexport.
This commit is contained in:
parent
013c1ea312
commit
9ffcc6fbd8
@ -5,7 +5,7 @@ import (
|
||||
. "battle_srv/common"
|
||||
"battle_srv/common/utils"
|
||||
"battle_srv/models"
|
||||
. "jsexport/protos"
|
||||
. "battle_srv/protos"
|
||||
"battle_srv/storage"
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
. "battle_srv/common"
|
||||
"battle_srv/common/utils"
|
||||
"battle_srv/models"
|
||||
. "jsexport/protos"
|
||||
. "battle_srv/protos"
|
||||
"battle_srv/storage"
|
||||
. "dnmshared"
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
. "battle_srv/common"
|
||||
"battle_srv/common/utils"
|
||||
"battle_srv/models"
|
||||
. "jsexport/protos"
|
||||
. "battle_srv/protos"
|
||||
"battle_srv/storage"
|
||||
. "dnmshared"
|
||||
|
||||
|
@ -1,17 +1,52 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
. "jsexport/protos"
|
||||
pb "battle_srv/protos"
|
||||
"jsexport/battle"
|
||||
)
|
||||
|
||||
func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) map[int32]*PlayerDownsync {
|
||||
toRet := make(map[int32]*PlayerDownsync, 0)
|
||||
func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) map[int32]*pb.PlayerDownsync {
|
||||
toRet := make(map[int32]*pb.PlayerDownsync, 0)
|
||||
if nil == modelInstances {
|
||||
return toRet
|
||||
}
|
||||
|
||||
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,
|
||||
VirtualGridX: last.VirtualGridX,
|
||||
VirtualGridY: last.VirtualGridY,
|
||||
|
@ -1,7 +1,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
. "jsexport/protos"
|
||||
. "battle_srv/protos"
|
||||
"battle_srv/storage"
|
||||
. "dnmshared"
|
||||
"fmt"
|
||||
|
@ -3,10 +3,8 @@ package models
|
||||
import (
|
||||
. "battle_srv/common"
|
||||
"battle_srv/common/utils"
|
||||
. "jsexport/protos"
|
||||
. "jsexport/models"
|
||||
pb "battle_srv/protos"
|
||||
. "dnmshared"
|
||||
. "dnmshared/sharedprotos"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"github.com/golang/protobuf/proto"
|
||||
@ -14,6 +12,7 @@ import (
|
||||
"github.com/solarlune/resolv"
|
||||
"go.uber.org/zap"
|
||||
"io/ioutil"
|
||||
"jsexport/battle"
|
||||
"math/rand"
|
||||
"os"
|
||||
"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).
|
||||
*/
|
||||
PlayerDownsyncSessionDict map[int32]*websocket.Conn
|
||||
PlayerDownsyncChanDict map[int32](chan InputsBufferSnapshot)
|
||||
PlayerDownsyncChanDict map[int32](chan pb.InputsBufferSnapshot)
|
||||
PlayerActiveWatchdogDict map[int32](*Watchdog)
|
||||
PlayerSignalToCloseDict map[int32]SignalToCloseConnCbType
|
||||
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
|
||||
EffectivePlayerCount int32
|
||||
DismissalWaitGroup sync.WaitGroup
|
||||
Barriers map[int32]*Barrier
|
||||
InputsBuffer *RingBuffer // Indices are STRICTLY consecutive
|
||||
InputsBufferLock sync.Mutex // Guards [InputsBuffer, LatestPlayerUpsyncedInputFrameId, LastAllConfirmedInputFrameId, LastAllConfirmedInputList, LastAllConfirmedInputFrameIdWithChange]
|
||||
RenderFrameBuffer *RingBuffer // Indices are STRICTLY consecutive
|
||||
@ -144,7 +142,10 @@ type Room struct {
|
||||
BulletBattleLocalIdCounter int32
|
||||
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() {
|
||||
@ -287,24 +288,8 @@ func (pR *Room) ChooseStage() error {
|
||||
pR.StageDiscreteH = stageDiscreteH
|
||||
pR.StageTileW = stageTileW
|
||||
pR.StageTileH = stageTileH
|
||||
pR.StrToVec2DListMap = strToVec2DListMap
|
||||
pR.StrToPolygon2DListMap = 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++
|
||||
}
|
||||
pR.TmxPointsMap = strToVec2DListMap
|
||||
pR.TmxPolygonsMap = strToPolygon2DListMap
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -345,7 +330,7 @@ func (pR *Room) InputsBufferString(allDetails bool) string {
|
||||
if nil == tmp {
|
||||
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))
|
||||
}
|
||||
|
||||
@ -365,12 +350,12 @@ func (pR *Room) StartBattle() {
|
||||
|
||||
// Initialize the "collisionSys" as well as "RenderFrameBuffer"
|
||||
pR.CurDynamicsRenderFrameId = 0
|
||||
kickoffFrame := &RoomDownsyncFrame{
|
||||
kickoffFrameJs := &battle.RoomDownsyncFrame{
|
||||
Id: pR.RenderFrameId,
|
||||
Players: toPbPlayers(pR.Players, false),
|
||||
Players: toJsPlayers(pR.Players, false),
|
||||
CountdownNanos: pR.BattleDurationNanos,
|
||||
}
|
||||
pR.RenderFrameBuffer.Put(kickoffFrame)
|
||||
pR.RenderFrameBuffer.Put(kickoffFrameJs)
|
||||
|
||||
// Refresh "Colliders"
|
||||
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:
|
||||
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)
|
||||
}
|
||||
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() {
|
||||
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))
|
||||
@ -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.
|
||||
*/
|
||||
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])
|
||||
}
|
||||
|
||||
@ -509,7 +498,7 @@ func (pR *Room) toDiscreteInputsBufferIndex(inputFrameId int32, joinIndex int32)
|
||||
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!
|
||||
|
||||
@ -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!
|
||||
inputFrameId := inputFrameDownsync.InputFrameId
|
||||
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))
|
||||
pR.RenderFrameId++
|
||||
for playerId, _ := range pR.Players {
|
||||
assembledFrame := RoomDownsyncFrame{
|
||||
assembledFrame := pb.RoomDownsyncFrame{
|
||||
Id: pR.RenderFrameId,
|
||||
Players: toPbPlayers(pR.Players, false),
|
||||
CountdownNanos: -1, // TODO: Replace this magic constant!
|
||||
@ -629,7 +618,7 @@ func (pR *Room) onBattlePrepare(cb BattleStartCbType) {
|
||||
pR.State = RoomBattleStateIns.PREPARE
|
||||
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,
|
||||
Players: toPbPlayers(pR.Players, true),
|
||||
CountdownNanos: pR.BattleDurationNanos,
|
||||
@ -714,10 +703,9 @@ func (pR *Room) OnDismissed() {
|
||||
for _, oldChan := range pR.PlayerDownsyncChanDict {
|
||||
close(oldChan)
|
||||
}
|
||||
pR.PlayerDownsyncChanDict = make(map[int32](chan InputsBufferSnapshot))
|
||||
pR.PlayerDownsyncChanDict = make(map[int32](chan pb.InputsBufferSnapshot))
|
||||
pR.PlayerSignalToCloseDict = make(map[int32]SignalToCloseConnCbType)
|
||||
pR.JoinIndexBooleanArr = make([]bool, pR.Capacity)
|
||||
pR.Barriers = make(map[int32]*Barrier)
|
||||
pR.RenderCacheSize = 1024
|
||||
pR.RenderFrameBuffer = NewRingBuffer(pR.RenderCacheSize)
|
||||
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.ForceAllResyncOnAnyActiveSlowTicker = true // See tradeoff discussion in "downsyncToAllPlayers"
|
||||
punchSkillId := int32(1)
|
||||
pR.MeleeSkillConfig = make(map[int32]*MeleeBullet, 0)
|
||||
pR.MeleeSkillConfig[punchSkillId] = &MeleeBullet{
|
||||
pR.MeleeSkillConfig = make(map[int32]*pb.MeleeBullet, 0)
|
||||
pR.MeleeSkillConfig[punchSkillId] = &pb.MeleeBullet{
|
||||
// for offender
|
||||
StartupFrames: int32(10),
|
||||
ActiveFrames: int32(10),
|
||||
RecoveryFrames: int32(34),
|
||||
RecoveryFramesOnBlock: int32(34),
|
||||
RecoveryFramesOnHit: int32(34),
|
||||
Moveforward: &Vec2D{
|
||||
X: 0,
|
||||
Y: 0,
|
||||
},
|
||||
HitboxOffset: float64(12.0), // should be about the radius of the PlayerCollider
|
||||
HitboxSize: &Vec2D{
|
||||
X: float64(24.0),
|
||||
Y: float64(32.0),
|
||||
},
|
||||
HitboxOffset: float64(12.0), // should be about the radius of the PlayerCollider
|
||||
|
||||
// for defender
|
||||
HitStunFrames: int32(18),
|
||||
@ -769,6 +749,11 @@ func (pR *Room) OnDismissed() {
|
||||
Pushback: float64(8.0),
|
||||
ReleaseTriggerType: int32(1), // 1: rising-edge, 2: falling-edge
|
||||
Damage: int32(5),
|
||||
|
||||
SelfMoveforwardX: 0,
|
||||
SelfMoveforwardY: 0,
|
||||
HitboxSizeX: 24.0,
|
||||
HitboxSizeY: 32.0,
|
||||
}
|
||||
|
||||
pR.SnapIntoPlatformOverlap = float64(0.1)
|
||||
@ -893,16 +878,16 @@ func (pR *Room) onPlayerAdded(playerId int32) {
|
||||
pR.JoinIndexBooleanArr[index] = true
|
||||
|
||||
// Lazily assign the initial position of "Player" for "RoomDownsyncFrame".
|
||||
playerPosList := *(pR.StrToVec2DListMap["PlayerStartingPos"])
|
||||
if index > len(playerPosList.Eles) {
|
||||
playerPosList := pR.TmxPointsMap["PlayerStartingPos"]
|
||||
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))
|
||||
}
|
||||
playerPos := playerPosList.Eles[index]
|
||||
playerPos := playerPosList[index]
|
||||
|
||||
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))
|
||||
}
|
||||
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
|
||||
if 0 == (pR.Players[playerId].JoinIndex % 2) {
|
||||
pR.Players[playerId].DirX = -2
|
||||
@ -942,7 +927,7 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
|
||||
targetPlayerBattleState := atomic.LoadInt32(&(targetPlayer.BattleState))
|
||||
switch targetPlayerBattleState {
|
||||
case PlayerBattleStateIns.ADDED_PENDING_BATTLE_COLLIDER_ACK:
|
||||
playerAckedFrame := &RoomDownsyncFrame{
|
||||
playerAckedFrame := &pb.RoomDownsyncFrame{
|
||||
Id: pR.RenderFrameId,
|
||||
Players: toPbPlayers(pR.Players, true),
|
||||
}
|
||||
@ -995,7 +980,7 @@ func (pR *Room) OnPlayerBattleColliderAcked(playerId int32) bool {
|
||||
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() {
|
||||
if r := recover(); r != nil {
|
||||
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 {
|
||||
pResp := &WsResp{
|
||||
pResp := &pb.WsResp{
|
||||
Ret: int32(Constants.RetCode.Ok),
|
||||
Act: act,
|
||||
Rdf: roomDownsyncFrame,
|
||||
@ -1030,7 +1015,7 @@ func (pR *Room) shouldPrefabInputFrameDownsync(prevRenderFrameId int32, renderFr
|
||||
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.
|
||||
|
||||
@ -1039,12 +1024,12 @@ func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *InputFrameDow
|
||||
- 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)"
|
||||
if nil == tmp1 {
|
||||
for pR.InputsBuffer.EdFrameId <= inputFrameId {
|
||||
j := pR.InputsBuffer.EdFrameId
|
||||
currInputFrameDownsync = &InputFrameDownsync{
|
||||
currInputFrameDownsync = &pb.InputFrameDownsync{
|
||||
InputFrameId: j,
|
||||
InputList: make([]uint64, pR.Capacity),
|
||||
ConfirmedList: uint64(0),
|
||||
@ -1056,7 +1041,7 @@ func (pR *Room) getOrPrefabInputFrameDownsync(inputFrameId int32) *InputFrameDow
|
||||
}
|
||||
tmp2 := pR.InputsBuffer.GetByFrameId(j2)
|
||||
if nil != tmp2 {
|
||||
prevInputFrameDownsync := tmp2.(*InputFrameDownsync)
|
||||
prevInputFrameDownsync := tmp2.(*pb.InputFrameDownsync)
|
||||
for i, _ := range currInputFrameDownsync.InputList {
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
currInputFrameDownsync = tmp1.(*InputFrameDownsync)
|
||||
currInputFrameDownsync = tmp1.(*pb.InputFrameDownsync)
|
||||
}
|
||||
|
||||
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!
|
||||
// Step#1, put the received "inputFrameUpsyncBatch" into "pR.InputsBuffer"
|
||||
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)))
|
||||
}
|
||||
shouldBreakConfirmation := false
|
||||
inputFrameDownsync := tmp.(*InputFrameDownsync)
|
||||
inputFrameDownsync := tmp.(*pb.InputFrameDownsync)
|
||||
|
||||
if allConfirmedMask != inputFrameDownsync.ConfirmedList {
|
||||
for _, player := range pR.PlayersArr {
|
||||
@ -1170,7 +1155,7 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) uint64 {
|
||||
if nil == tmp {
|
||||
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)
|
||||
inputFrameDownsync.ConfirmedList = allConfirmedMask
|
||||
pR.onInputFrameDownsyncAllConfirmed(inputFrameDownsync, -1)
|
||||
@ -1197,7 +1182,7 @@ func (pR *Room) forceConfirmationIfApplicable(prevRenderFrameId int32) uint64 {
|
||||
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!
|
||||
refRenderFrameIdIfNeeded := pR.CurDynamicsRenderFrameId - 1
|
||||
if 0 > refRenderFrameIdIfNeeded {
|
||||
@ -1206,7 +1191,7 @@ func (pR *Room) produceInputsBufferSnapshotWithCurDynamicsRenderFrameAsRef(uncon
|
||||
// Duplicate downsynced inputFrameIds will be filtered out by frontend.
|
||||
toSendInputFrameDownsyncs := pR.cloneInputsBuffer(snapshotStFrameId, snapshotEdFrameId)
|
||||
|
||||
return &InputsBufferSnapshot{
|
||||
return &pb.InputsBufferSnapshot{
|
||||
RefRenderFrameId: refRenderFrameIdIfNeeded,
|
||||
UnconfirmedMask: unconfirmedMask,
|
||||
ToSendInputFrameDownsyncs: toSendInputFrameDownsyncs,
|
||||
@ -1228,9 +1213,9 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
|
||||
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()))
|
||||
}
|
||||
currRenderFrame := currRenderFrameTmp.(*RoomDownsyncFrame)
|
||||
currRenderFrame := currRenderFrameTmp.(*battle.RoomDownsyncFrame)
|
||||
delayedInputFrameId := pR.ConvertToInputFrameId(collisionSysRenderFrameId, pR.InputDelayFrames)
|
||||
var delayedInputFrame *InputFrameDownsync = nil
|
||||
var delayedInputFrame *pb.InputFrameDownsync = nil
|
||||
if 0 <= delayedInputFrameId {
|
||||
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)))
|
||||
@ -1239,7 +1224,7 @@ func (pR *Room) applyInputFrameDownsyncDynamics(fromRenderFrameId int32, toRende
|
||||
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)))
|
||||
}
|
||||
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.
|
||||
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) {
|
||||
// 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
|
||||
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 {
|
||||
wx, wy := VirtualGridToWorldPos(player.VirtualGridX, player.VirtualGridY, pR.VirtualGridToWorldRatio)
|
||||
jsPlayers := toJsPlayers(pR.Players, false)
|
||||
for _, player := range jsPlayers {
|
||||
wx, wy := battle.VirtualGridToWorldPos(player.VirtualGridX, player.VirtualGridY, pR.VirtualGridToWorldRatio)
|
||||
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)
|
||||
// Keep track of the collider in "pR.CollisionSysMap"
|
||||
joinIndex := player.JoinIndex
|
||||
pR.PlayersArr[joinIndex-1] = player
|
||||
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
||||
collisionPlayerIndex := battle.COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
||||
pR.CollisionSysMap[collisionPlayerIndex] = playerCollider
|
||||
}
|
||||
|
||||
for _, barrier := range pR.Barriers {
|
||||
boundaryUnaligned := barrier.Boundary
|
||||
barrierCollider := GenerateConvexPolygonCollider(boundaryUnaligned, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, barrier, "Barrier")
|
||||
for _, player := range pR.Players {
|
||||
joinIndex := player.JoinIndex
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -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).
|
||||
|
||||
@ -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"!
|
||||
|
||||
@ -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()))
|
||||
}
|
||||
|
||||
refRenderFrame := tmp.(*RoomDownsyncFrame)
|
||||
refRenderFrame := tmp.(*battle.RoomDownsyncFrame)
|
||||
for _, player := range pR.PlayersArr {
|
||||
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!
|
||||
cloned := make([]*InputFrameDownsync, 0, edFrameId-stFrameId)
|
||||
cloned := make([]*pb.InputFrameDownsync, 0, edFrameId-stFrameId)
|
||||
prevFrameFound := false
|
||||
j := stFrameId
|
||||
for j < edFrameId {
|
||||
@ -1834,9 +1464,9 @@ func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*InputFrameDowns
|
||||
}
|
||||
}
|
||||
prevFrameFound = true
|
||||
foo := tmp.(*InputFrameDownsync)
|
||||
foo := tmp.(*pb.InputFrameDownsync)
|
||||
|
||||
bar := &InputFrameDownsync{
|
||||
bar := &pb.InputFrameDownsync{
|
||||
InputFrameId: foo.InputFrameId,
|
||||
InputList: make([]uint64, len(foo.InputList)),
|
||||
ConfirmedList: foo.ConfirmedList,
|
||||
@ -1850,29 +1480,3 @@ func (pR *Room) cloneInputsBuffer(stFrameId, edFrameId int32) []*InputFrameDowns
|
||||
|
||||
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
|
||||
}
|
||||
|
1797
battle_srv/protos/room_downsync_frame.pb.go
Normal file
1797
battle_srv/protos/room_downsync_frame.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@ package ws
|
||||
import (
|
||||
. "battle_srv/common"
|
||||
"battle_srv/models"
|
||||
pb "jsexport/protos"
|
||||
pb "battle_srv/protos"
|
||||
"container/heap"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
@ -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)
|
||||
}
|
@ -1,14 +1,16 @@
|
||||
package dnmshared
|
||||
|
||||
import (
|
||||
. "dnmshared/sharedprotos"
|
||||
. "jsexport/battle"
|
||||
"fmt"
|
||||
"github.com/kvartborg/vector"
|
||||
"github.com/solarlune/resolv"
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func NormVec2D(dx, dy float64) Vec2D {
|
||||
return Vec2D{X: dy, Y: -dx}
|
||||
}
|
||||
|
||||
func ConvexPolygonStr(body *resolv.ConvexPolygon) string {
|
||||
var s []string = make([]string, len(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 {
|
||||
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)
|
||||
}
|
||||
|
@ -3,13 +3,13 @@ package dnmshared
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
. "dnmshared/sharedprotos"
|
||||
"encoding/base64"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
"io/ioutil"
|
||||
. "jsexport/battle"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -175,8 +175,8 @@ func (l *TmxLayer) decodeBase64() ([]uint32, error) {
|
||||
return gids, nil
|
||||
}
|
||||
|
||||
type StrToVec2DListMap map[string]*Vec2DList
|
||||
type StrToPolygon2DListMap map[string]*Polygon2DList
|
||||
type StrToVec2DListMap map[string]([]*Vec2D)
|
||||
type StrToPolygon2DListMap map[string]([]*Polygon2D)
|
||||
|
||||
func tmxPolylineToPolygon2D(pTmxMapIns *TmxMap, singleObjInTmxFile *TmxOrTsxObject, targetPolyline *TmxOrTsxPolyline) (*Polygon2D, error) {
|
||||
if nil == targetPolyline {
|
||||
@ -321,13 +321,11 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f
|
||||
theStrToPolygon2DListMap = gidBoundariesMap[globalGid]
|
||||
}
|
||||
|
||||
var pThePolygon2DList *Polygon2DList
|
||||
var pThePolygon2DList []*Polygon2D
|
||||
if _, ok := theStrToPolygon2DListMap[key]; ok {
|
||||
pThePolygon2DList = theStrToPolygon2DListMap[key]
|
||||
} else {
|
||||
pThePolygon2DList = &Polygon2DList{
|
||||
Eles: make([]*Polygon2D, 0),
|
||||
}
|
||||
pThePolygon2DList = make([]*Polygon2D, 0)
|
||||
theStrToPolygon2DListMap[key] = pThePolygon2DList
|
||||
}
|
||||
|
||||
@ -335,7 +333,7 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
pThePolygon2DList.Eles = append(pThePolygon2DList.Eles, thePolygon2DFromPolyline)
|
||||
pThePolygon2DList = append(pThePolygon2DList, thePolygon2DFromPolyline)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -348,12 +346,10 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMap map[int]StrToP
|
||||
for _, objGroup := range pTmxMapIns.ObjectGroups {
|
||||
switch objGroup.Name {
|
||||
case "PlayerStartingPos":
|
||||
var pTheVec2DListToCache *Vec2DList
|
||||
var pTheVec2DListToCache []*Vec2D
|
||||
_, ok := toRetStrToVec2DListMap[objGroup.Name]
|
||||
if false == ok {
|
||||
pTheVec2DListToCache = &Vec2DList{
|
||||
Eles: make([]*Vec2D, 0),
|
||||
}
|
||||
pTheVec2DListToCache = make([]*Vec2D, 0)
|
||||
toRetStrToVec2DListMap[objGroup.Name] = pTheVec2DListToCache
|
||||
}
|
||||
pTheVec2DListToCache = toRetStrToVec2DListMap[objGroup.Name]
|
||||
@ -363,16 +359,14 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMap map[int]StrToP
|
||||
Y: singleObjInTmxFile.Y,
|
||||
}
|
||||
thePosInWorld := pTmxMapIns.continuousObjLayerOffsetToContinuousMapNodePos(theUntransformedPos)
|
||||
pTheVec2DListToCache.Eles = append(pTheVec2DListToCache.Eles, &thePosInWorld)
|
||||
pTheVec2DListToCache = append(pTheVec2DListToCache, &thePosInWorld)
|
||||
}
|
||||
case "Barrier":
|
||||
// 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]
|
||||
if false == ok {
|
||||
pThePolygon2DListToCache = &Polygon2DList{
|
||||
Eles: make([]*Polygon2D, 0),
|
||||
}
|
||||
pThePolygon2DListToCache = make([]*Polygon2D, 0)
|
||||
toRetStrToPolygon2DListMap[objGroup.Name] = pThePolygon2DListToCache
|
||||
}
|
||||
|
||||
@ -408,7 +402,7 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMap map[int]StrToP
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
pThePolygon2DListToCache.Eles = append(pThePolygon2DListToCache.Eles, thePolygon2DInWorld)
|
||||
pThePolygon2DListToCache = append(pThePolygon2DListToCache, thePolygon2DInWorld)
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -79,10 +79,6 @@ message InputsBufferSnapshot {
|
||||
bool shouldForceResync = 4;
|
||||
}
|
||||
|
||||
message Barrier {
|
||||
sharedprotos.Polygon2D boundary = 1;
|
||||
}
|
||||
|
||||
message MeleeBullet {
|
||||
// Jargon reference https://www.thegamer.com/fighting-games-frame-data-explained/
|
||||
// ALL lengths are in world coordinate
|
||||
@ -94,60 +90,62 @@ message MeleeBullet {
|
||||
int32 recoveryFrames = 4;
|
||||
int32 recoveryFramesOnBlock = 5;
|
||||
int32 recoveryFramesOnHit = 6;
|
||||
sharedprotos.Vec2D moveforward = 7;
|
||||
double hitboxOffset = 8;
|
||||
sharedprotos.Vec2D hitboxSize = 9;
|
||||
int32 originatedRenderFrameId = 10;
|
||||
double hitboxOffset = 7;
|
||||
int32 originatedRenderFrameId = 8;
|
||||
|
||||
// for defender
|
||||
int32 hitStunFrames = 11;
|
||||
int32 blockStunFrames = 12;
|
||||
double pushback = 13;
|
||||
int32 hitStunFrames = 9;
|
||||
int32 blockStunFrames = 10;
|
||||
double pushback = 11;
|
||||
|
||||
int32 releaseTriggerType = 14; // 1: rising-edge, 2: falling-edge
|
||||
int32 damage = 15;
|
||||
int32 releaseTriggerType = 12; // 1: rising-edge, 2: falling-edge
|
||||
int32 damage = 13;
|
||||
|
||||
int32 offenderJoinIndex = 16;
|
||||
int32 offenderPlayerId = 17;
|
||||
int32 offenderJoinIndex = 14;
|
||||
int32 offenderPlayerId = 15;
|
||||
|
||||
double hitboxSizeX = 16;
|
||||
double hitboxSizeY = 17;
|
||||
|
||||
double selfMoveforwardX = 18;
|
||||
double selfMoveforwardY = 19;
|
||||
}
|
||||
|
||||
message BattleColliderInfo {
|
||||
string stageName = 1;
|
||||
map<string, sharedprotos.Vec2DList> strToVec2DListMap = 2;
|
||||
map<string, sharedprotos.Polygon2DList> strToPolygon2DListMap = 3;
|
||||
int32 stageDiscreteW = 4;
|
||||
int32 stageDiscreteH = 5;
|
||||
int32 stageTileW = 6;
|
||||
int32 stageTileH = 7;
|
||||
int32 stageDiscreteW = 2;
|
||||
int32 stageDiscreteH = 3;
|
||||
int32 stageTileW = 4;
|
||||
int32 stageTileH = 5;
|
||||
|
||||
int32 intervalToPing = 8;
|
||||
int32 willKickIfInactiveFor = 9;
|
||||
int32 boundRoomId = 10;
|
||||
int32 battleDurationFrames = 12;
|
||||
int64 battleDurationNanos = 13;
|
||||
int32 serverFps = 14;
|
||||
int32 inputDelayFrames = 15; // in the count of render frames
|
||||
uint32 inputScaleFrames = 16; // 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 inputFrameUpsyncDelayTolerance = 18;
|
||||
int32 maxChasingRenderFramesPerUpdate = 19;
|
||||
int32 playerBattleState = 20;
|
||||
double rollbackEstimatedDtMillis = 21;
|
||||
int64 rollbackEstimatedDtNanos = 22;
|
||||
int32 intervalToPing = 6;
|
||||
int32 willKickIfInactiveFor = 7;
|
||||
int32 boundRoomId = 8;
|
||||
int32 battleDurationFrames = 9;
|
||||
int64 battleDurationNanos = 10;
|
||||
int32 serverFps = 11;
|
||||
int32 inputDelayFrames = 12; // in the count of render frames
|
||||
uint32 inputScaleFrames = 13; // inputDelayedAndScaledFrameId = ((originalFrameId - InputDelayFrames) >> InputScaleFrames)
|
||||
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 = 15;
|
||||
int32 maxChasingRenderFramesPerUpdate = 16;
|
||||
int32 playerBattleState = 17;
|
||||
double rollbackEstimatedDtMillis = 18;
|
||||
int64 rollbackEstimatedDtNanos = 19;
|
||||
|
||||
double worldToVirtualGridRatio = 23;
|
||||
double virtualGridToWorldRatio = 24;
|
||||
double worldToVirtualGridRatio = 20;
|
||||
double virtualGridToWorldRatio = 21;
|
||||
|
||||
int32 spAtkLookupFrames = 25;
|
||||
int32 renderCacheSize = 26;
|
||||
int32 spAtkLookupFrames = 22;
|
||||
int32 renderCacheSize = 23;
|
||||
|
||||
map<int32, MeleeBullet> meleeSkillConfig = 27; // skillId -> skill
|
||||
map<int32, MeleeBullet> meleeSkillConfig = 24; // skillId -> skill
|
||||
|
||||
double snapIntoPlatformOverlap = 28;
|
||||
double snapIntoPlatformThreshold = 29;
|
||||
int32 jumpingInitVelY = 30;
|
||||
int32 gravityX = 31;
|
||||
int32 gravityY = 32;
|
||||
double snapIntoPlatformOverlap = 25;
|
||||
double snapIntoPlatformThreshold = 26;
|
||||
int32 jumpingInitVelY = 27;
|
||||
int32 gravityX = 28;
|
||||
int32 gravityY = 29;
|
||||
}
|
||||
|
||||
message RoomDownsyncFrame {
|
||||
|
@ -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)}`;
|
||||
}
|
||||
|
||||
const delayedInputFrameJs = gopkgs.NewInputFrameDownsyncJs(j, delayedInputFrame.inputList, delayedInputFrame.confirmedList);
|
||||
const jPrev = self._convertToInputFrameId(i - 1, self.inputDelayFrames);
|
||||
const delayedInputFrameForPrevRenderFrame = self.recentInputCache.getByFrameId(jPrev);
|
||||
const delayedInputFrameForPrevRenderFrameJs = gopkgs.NewInputFrameDownsyncJs(jPrev, delayedInputFrameForPrevRenderFrame.inputList, delayedInputFrameForPrevRenderFrame.confirmedList);
|
||||
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);
|
||||
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);
|
||||
|
||||
if (true == isChasing) {
|
||||
// [WARNING] Move the cursor "self.chaserRenderFrameId" when "true == isChasing", keep in mind that "self.chaserRenderFrameId" is not monotonic!
|
||||
|
@ -3954,214 +3954,6 @@ $root.protos = (function() {
|
||||
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() {
|
||||
|
||||
/**
|
||||
@ -4174,9 +3966,7 @@ $root.protos = (function() {
|
||||
* @property {number|null} [recoveryFrames] MeleeBullet recoveryFrames
|
||||
* @property {number|null} [recoveryFramesOnBlock] MeleeBullet recoveryFramesOnBlock
|
||||
* @property {number|null} [recoveryFramesOnHit] MeleeBullet recoveryFramesOnHit
|
||||
* @property {sharedprotos.Vec2D|null} [moveforward] MeleeBullet moveforward
|
||||
* @property {number|null} [hitboxOffset] MeleeBullet hitboxOffset
|
||||
* @property {sharedprotos.Vec2D|null} [hitboxSize] MeleeBullet hitboxSize
|
||||
* @property {number|null} [originatedRenderFrameId] MeleeBullet originatedRenderFrameId
|
||||
* @property {number|null} [hitStunFrames] MeleeBullet hitStunFrames
|
||||
* @property {number|null} [blockStunFrames] MeleeBullet blockStunFrames
|
||||
@ -4185,6 +3975,10 @@ $root.protos = (function() {
|
||||
* @property {number|null} [damage] MeleeBullet damage
|
||||
* @property {number|null} [offenderJoinIndex] MeleeBullet offenderJoinIndex
|
||||
* @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 moveforward.
|
||||
* @member {sharedprotos.Vec2D|null|undefined} moveforward
|
||||
* @memberof protos.MeleeBullet
|
||||
* @instance
|
||||
*/
|
||||
MeleeBullet.prototype.moveforward = null;
|
||||
|
||||
/**
|
||||
* MeleeBullet hitboxOffset.
|
||||
* @member {number} hitboxOffset
|
||||
@ -4266,14 +4052,6 @@ $root.protos = (function() {
|
||||
*/
|
||||
MeleeBullet.prototype.hitboxOffset = 0;
|
||||
|
||||
/**
|
||||
* MeleeBullet hitboxSize.
|
||||
* @member {sharedprotos.Vec2D|null|undefined} hitboxSize
|
||||
* @memberof protos.MeleeBullet
|
||||
* @instance
|
||||
*/
|
||||
MeleeBullet.prototype.hitboxSize = null;
|
||||
|
||||
/**
|
||||
* MeleeBullet originatedRenderFrameId.
|
||||
* @member {number} originatedRenderFrameId
|
||||
@ -4338,6 +4116,38 @@ $root.protos = (function() {
|
||||
*/
|
||||
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.
|
||||
* @function create
|
||||
@ -4374,28 +4184,32 @@ $root.protos = (function() {
|
||||
writer.uint32(/* id 5, wireType 0 =*/40).int32(message.recoveryFramesOnBlock);
|
||||
if (message.recoveryFramesOnHit != null && Object.hasOwnProperty.call(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"))
|
||||
writer.uint32(/* id 8, wireType 1 =*/65).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();
|
||||
writer.uint32(/* id 7, wireType 1 =*/57).double(message.hitboxOffset);
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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;
|
||||
};
|
||||
|
||||
@ -4455,49 +4269,57 @@ $root.protos = (function() {
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
message.moveforward = $root.sharedprotos.Vec2D.decode(reader, reader.uint32());
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
message.hitboxOffset = reader.double();
|
||||
break;
|
||||
}
|
||||
case 9: {
|
||||
message.hitboxSize = $root.sharedprotos.Vec2D.decode(reader, reader.uint32());
|
||||
break;
|
||||
}
|
||||
case 10: {
|
||||
case 8: {
|
||||
message.originatedRenderFrameId = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 11: {
|
||||
case 9: {
|
||||
message.hitStunFrames = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 12: {
|
||||
case 10: {
|
||||
message.blockStunFrames = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 13: {
|
||||
case 11: {
|
||||
message.pushback = reader.double();
|
||||
break;
|
||||
}
|
||||
case 14: {
|
||||
case 12: {
|
||||
message.releaseTriggerType = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 15: {
|
||||
case 13: {
|
||||
message.damage = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 16: {
|
||||
case 14: {
|
||||
message.offenderJoinIndex = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 17: {
|
||||
case 15: {
|
||||
message.offenderPlayerId = reader.int32();
|
||||
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:
|
||||
reader.skipType(tag & 7);
|
||||
break;
|
||||
@ -4551,19 +4373,9 @@ $root.protos = (function() {
|
||||
if (message.recoveryFramesOnHit != null && message.hasOwnProperty("recoveryFramesOnHit"))
|
||||
if (!$util.isInteger(message.recoveryFramesOnHit))
|
||||
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 (typeof message.hitboxOffset !== "number")
|
||||
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 (!$util.isInteger(message.originatedRenderFrameId))
|
||||
return "originatedRenderFrameId: integer expected";
|
||||
@ -4588,6 +4400,18 @@ $root.protos = (function() {
|
||||
if (message.offenderPlayerId != null && message.hasOwnProperty("offenderPlayerId"))
|
||||
if (!$util.isInteger(message.offenderPlayerId))
|
||||
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;
|
||||
};
|
||||
|
||||
@ -4615,18 +4439,8 @@ $root.protos = (function() {
|
||||
message.recoveryFramesOnBlock = object.recoveryFramesOnBlock | 0;
|
||||
if (object.recoveryFramesOnHit != null)
|
||||
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)
|
||||
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)
|
||||
message.originatedRenderFrameId = object.originatedRenderFrameId | 0;
|
||||
if (object.hitStunFrames != null)
|
||||
@ -4643,6 +4457,14 @@ $root.protos = (function() {
|
||||
message.offenderJoinIndex = object.offenderJoinIndex | 0;
|
||||
if (object.offenderPlayerId != null)
|
||||
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;
|
||||
};
|
||||
|
||||
@ -4666,9 +4488,7 @@ $root.protos = (function() {
|
||||
object.recoveryFrames = 0;
|
||||
object.recoveryFramesOnBlock = 0;
|
||||
object.recoveryFramesOnHit = 0;
|
||||
object.moveforward = null;
|
||||
object.hitboxOffset = 0;
|
||||
object.hitboxSize = null;
|
||||
object.originatedRenderFrameId = 0;
|
||||
object.hitStunFrames = 0;
|
||||
object.blockStunFrames = 0;
|
||||
@ -4677,6 +4497,10 @@ $root.protos = (function() {
|
||||
object.damage = 0;
|
||||
object.offenderJoinIndex = 0;
|
||||
object.offenderPlayerId = 0;
|
||||
object.hitboxSizeX = 0;
|
||||
object.hitboxSizeY = 0;
|
||||
object.selfMoveforwardX = 0;
|
||||
object.selfMoveforwardY = 0;
|
||||
}
|
||||
if (message.battleLocalId != null && message.hasOwnProperty("battleLocalId"))
|
||||
object.battleLocalId = message.battleLocalId;
|
||||
@ -4690,12 +4514,8 @@ $root.protos = (function() {
|
||||
object.recoveryFramesOnBlock = message.recoveryFramesOnBlock;
|
||||
if (message.recoveryFramesOnHit != null && message.hasOwnProperty("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"))
|
||||
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"))
|
||||
object.originatedRenderFrameId = message.originatedRenderFrameId;
|
||||
if (message.hitStunFrames != null && message.hasOwnProperty("hitStunFrames"))
|
||||
@ -4712,6 +4532,14 @@ $root.protos = (function() {
|
||||
object.offenderJoinIndex = message.offenderJoinIndex;
|
||||
if (message.offenderPlayerId != null && message.hasOwnProperty("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;
|
||||
};
|
||||
|
||||
@ -4751,8 +4579,6 @@ $root.protos = (function() {
|
||||
* @memberof protos
|
||||
* @interface IBattleColliderInfo
|
||||
* @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} [stageDiscreteH] BattleColliderInfo stageDiscreteH
|
||||
* @property {number|null} [stageTileW] BattleColliderInfo stageTileW
|
||||
@ -4792,8 +4618,6 @@ $root.protos = (function() {
|
||||
* @param {protos.IBattleColliderInfo=} [properties] Properties to set
|
||||
*/
|
||||
function BattleColliderInfo(properties) {
|
||||
this.strToVec2DListMap = {};
|
||||
this.strToPolygon2DListMap = {};
|
||||
this.meleeSkillConfig = {};
|
||||
if (properties)
|
||||
for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i)
|
||||
@ -4809,22 +4633,6 @@ $root.protos = (function() {
|
||||
*/
|
||||
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.
|
||||
* @member {number} stageDiscreteW
|
||||
@ -5075,75 +4883,65 @@ $root.protos = (function() {
|
||||
writer = $Writer.create();
|
||||
if (message.stageName != null && Object.hasOwnProperty.call(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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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();
|
||||
}
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
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"))
|
||||
writer.uint32(/* id 32, wireType 0 =*/256).int32(message.gravityY);
|
||||
writer.uint32(/* id 29, wireType 0 =*/232).int32(message.gravityY);
|
||||
return writer;
|
||||
};
|
||||
|
||||
@ -5183,140 +4981,94 @@ $root.protos = (function() {
|
||||
break;
|
||||
}
|
||||
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();
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
case 3: {
|
||||
message.stageDiscreteH = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
case 4: {
|
||||
message.stageTileW = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
case 5: {
|
||||
message.stageTileH = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
case 6: {
|
||||
message.intervalToPing = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 9: {
|
||||
case 7: {
|
||||
message.willKickIfInactiveFor = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 10: {
|
||||
case 8: {
|
||||
message.boundRoomId = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 12: {
|
||||
case 9: {
|
||||
message.battleDurationFrames = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 13: {
|
||||
case 10: {
|
||||
message.battleDurationNanos = reader.int64();
|
||||
break;
|
||||
}
|
||||
case 14: {
|
||||
case 11: {
|
||||
message.serverFps = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 15: {
|
||||
case 12: {
|
||||
message.inputDelayFrames = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 16: {
|
||||
case 13: {
|
||||
message.inputScaleFrames = reader.uint32();
|
||||
break;
|
||||
}
|
||||
case 17: {
|
||||
case 14: {
|
||||
message.nstDelayFrames = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
case 15: {
|
||||
message.inputFrameUpsyncDelayTolerance = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 19: {
|
||||
case 16: {
|
||||
message.maxChasingRenderFramesPerUpdate = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 20: {
|
||||
case 17: {
|
||||
message.playerBattleState = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 21: {
|
||||
case 18: {
|
||||
message.rollbackEstimatedDtMillis = reader.double();
|
||||
break;
|
||||
}
|
||||
case 22: {
|
||||
case 19: {
|
||||
message.rollbackEstimatedDtNanos = reader.int64();
|
||||
break;
|
||||
}
|
||||
case 23: {
|
||||
case 20: {
|
||||
message.worldToVirtualGridRatio = reader.double();
|
||||
break;
|
||||
}
|
||||
case 24: {
|
||||
case 21: {
|
||||
message.virtualGridToWorldRatio = reader.double();
|
||||
break;
|
||||
}
|
||||
case 25: {
|
||||
case 22: {
|
||||
message.spAtkLookupFrames = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 26: {
|
||||
case 23: {
|
||||
message.renderCacheSize = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 27: {
|
||||
case 24: {
|
||||
if (message.meleeSkillConfig === $util.emptyObject)
|
||||
message.meleeSkillConfig = {};
|
||||
var end2 = reader.uint32() + reader.pos;
|
||||
@ -5339,23 +5091,23 @@ $root.protos = (function() {
|
||||
message.meleeSkillConfig[key] = value;
|
||||
break;
|
||||
}
|
||||
case 28: {
|
||||
case 25: {
|
||||
message.snapIntoPlatformOverlap = reader.double();
|
||||
break;
|
||||
}
|
||||
case 29: {
|
||||
case 26: {
|
||||
message.snapIntoPlatformThreshold = reader.double();
|
||||
break;
|
||||
}
|
||||
case 30: {
|
||||
case 27: {
|
||||
message.jumpingInitVelY = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 31: {
|
||||
case 28: {
|
||||
message.gravityX = reader.int32();
|
||||
break;
|
||||
}
|
||||
case 32: {
|
||||
case 29: {
|
||||
message.gravityY = reader.int32();
|
||||
break;
|
||||
}
|
||||
@ -5397,26 +5149,6 @@ $root.protos = (function() {
|
||||
if (message.stageName != null && message.hasOwnProperty("stageName"))
|
||||
if (!$util.isString(message.stageName))
|
||||
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 (!$util.isInteger(message.stageDiscreteW))
|
||||
return "stageDiscreteW: integer expected";
|
||||
@ -5529,26 +5261,6 @@ $root.protos = (function() {
|
||||
var message = new $root.protos.BattleColliderInfo();
|
||||
if (object.stageName != null)
|
||||
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)
|
||||
message.stageDiscreteW = object.stageDiscreteW | 0;
|
||||
if (object.stageDiscreteH != null)
|
||||
@ -5643,11 +5355,8 @@ $root.protos = (function() {
|
||||
if (!options)
|
||||
options = {};
|
||||
var object = {};
|
||||
if (options.objects || options.defaults) {
|
||||
object.strToVec2DListMap = {};
|
||||
object.strToPolygon2DListMap = {};
|
||||
if (options.objects || options.defaults)
|
||||
object.meleeSkillConfig = {};
|
||||
}
|
||||
if (options.defaults) {
|
||||
object.stageName = "";
|
||||
object.stageDiscreteW = 0;
|
||||
@ -5688,17 +5397,6 @@ $root.protos = (function() {
|
||||
}
|
||||
if (message.stageName != null && message.hasOwnProperty("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"))
|
||||
object.stageDiscreteW = message.stageDiscreteW;
|
||||
if (message.stageDiscreteH != null && message.hasOwnProperty("stageDiscreteH"))
|
||||
@ -5749,6 +5447,7 @@ $root.protos = (function() {
|
||||
object.spAtkLookupFrames = message.spAtkLookupFrames;
|
||||
if (message.renderCacheSize != null && message.hasOwnProperty("renderCacheSize"))
|
||||
object.renderCacheSize = message.renderCacheSize;
|
||||
var keys2;
|
||||
if (message.meleeSkillConfig && (keys2 = Object.keys(message.meleeSkillConfig)).length) {
|
||||
object.meleeSkillConfig = {};
|
||||
for (var j = 0; j < keys2.length; ++j)
|
||||
|
@ -43,7 +43,7 @@ func ConvertToInputFrameId(renderFrameId int32, inputDelayFrames int32, inputSca
|
||||
return ((renderFrameId - inputDelayFrames) >> inputScaleFrames)
|
||||
}
|
||||
|
||||
func DecodeInput(encodedInput uint64) *InputFrameDecoded {
|
||||
func decodeInput(encodedInput uint64) *InputFrameDecoded {
|
||||
encodedDirection := (encodedInput & uint64(15))
|
||||
btnALevel := int32((encodedInput >> 4) & 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)
|
||||
}
|
||||
|
||||
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
|
||||
collision := playerCollider.Check(0, 0)
|
||||
if nil == collision {
|
||||
@ -281,8 +281,9 @@ func CalcHardPushbacksNorms(playerCollider *resolv.Object, playerShape *resolv.C
|
||||
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] This function MUST BE called while "InputsBufferLock" is locked!
|
||||
// [WARNING] The params of this method is carefully tuned such that only "battle.RoomDownsyncFrame" is a necessary custom struct.
|
||||
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)
|
||||
nextRenderFramePlayers := make([]*PlayerDownsync, roomCapacity)
|
||||
// Make a copy first
|
||||
@ -315,18 +316,17 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, delay
|
||||
hardPushbackNorms := make([][]Vec2D, roomCapacity)
|
||||
|
||||
// 1. Process player inputs
|
||||
if nil != delayedInputFrame {
|
||||
inputList := delayedInputFrame.InputList
|
||||
if nil != delayedInputList {
|
||||
for i, currPlayerDownsync := range currRenderFrame.PlayersArr {
|
||||
joinIndex := currPlayerDownsync.JoinIndex
|
||||
thatPlayerInNextFrame := nextRenderFramePlayers[i]
|
||||
if 0 < thatPlayerInNextFrame.FramesToRecover {
|
||||
continue
|
||||
}
|
||||
decodedInput := DecodeInput(inputList[joinIndex-1])
|
||||
decodedInput := decodeInput(delayedInputList[joinIndex-1])
|
||||
prevBtnBLevel := int32(0)
|
||||
if nil != delayedInputFrameForPrevRenderFrame {
|
||||
prevDecodedInput := DecodeInput(delayedInputFrameForPrevRenderFrame.InputList[joinIndex-1])
|
||||
if nil != delayedInputListForPrevRenderFrame {
|
||||
prevDecodedInput := decodeInput(delayedInputListForPrevRenderFrame[joinIndex-1])
|
||||
prevBtnBLevel = prevDecodedInput.BtnBLevel
|
||||
}
|
||||
|
||||
@ -386,7 +386,7 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, delay
|
||||
collisionPlayerIndex := COLLISION_PLAYER_INDEX_PREFIX + joinIndex
|
||||
playerCollider := collisionSysMap[collisionPlayerIndex]
|
||||
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]
|
||||
fallStopping := false
|
||||
if collision := playerCollider.Check(0, 0); nil != collision {
|
||||
@ -394,12 +394,13 @@ func ApplyInputFrameDownsyncDynamicsOnSingleRenderFrame(delayedInputFrame, delay
|
||||
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.
|
||||
switch obj.Data.(type) {
|
||||
case *Barrier:
|
||||
isBarrier = true
|
||||
case *PlayerDownsync:
|
||||
isAnotherPlayer = true
|
||||
case *MeleeBullet:
|
||||
isBullet = true
|
||||
default:
|
||||
// By default it's a regular barrier, even if data is nil
|
||||
isBarrier = true
|
||||
}
|
||||
if isBullet {
|
||||
// ignore bullets for this step
|
||||
|
@ -47,12 +47,6 @@ type InputFrameUpsync struct {
|
||||
Encoded uint64
|
||||
}
|
||||
|
||||
type InputFrameDownsync struct {
|
||||
InputFrameId int32
|
||||
InputList []uint64
|
||||
ConfirmedList uint64
|
||||
}
|
||||
|
||||
type Barrier struct {
|
||||
Boundary *Polygon2D
|
||||
}
|
||||
|
@ -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 {
|
||||
objs := space.Objects()
|
||||
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))
|
||||
}
|
||||
|
||||
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
|
||||
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() {
|
||||
@ -123,7 +115,6 @@ func main() {
|
||||
"NewPlayerDownsyncJs": NewPlayerDownsyncJs,
|
||||
"NewRoomDownsyncFrameJs": NewRoomDownsyncFrameJs,
|
||||
"NewCollisionSpaceJs": NewCollisionSpaceJs,
|
||||
"NewInputFrameDownsyncJs": NewInputFrameDownsyncJs,
|
||||
"GenerateRectColliderJs": GenerateRectColliderJs,
|
||||
"GenerateConvexPolygonColliderJs": GenerateConvexPolygonColliderJs,
|
||||
"GetPlayersArrJs": GetPlayersArrJs,
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
golang_basedir_1=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/dnmshared
|
||||
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!
|
||||
golang_basedir_2=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/battle_srv
|
||||
|
Loading…
Reference in New Issue
Block a user