diff --git a/README.md b/README.md index 94d44af..b72ae1d 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ This project is a demo for a websocket-based rollback netcode inspired by [GGPO](https://github.com/pond3r/ggpo/blob/master/doc/README.md). -_(the following gif is sped up to ~1.33x for file size reduction, kindly note that around ~8s countdown, the attack animation is resumed from a partial progress)_ +_(the following [v0.8.8](https://github.com/genxium/DelayNoMore/releases/tag/v0.8.8) gif is sped up to ~1.33x for file size reduction, kindly note that around ~8s countdown, the attack animation is resumed from a partial progress)_ -![gif_demo](./charts/smooth_melee_attack_spedup.gif) +![gif_demo](./charts/smooth_melee_attack_spedup_v088.gif) Please also checkout [this demo video](https://pan.baidu.com/s/172AmIKxbFgGXZzWVqxNUPA?pwd=e2tp) to see how this demo carries out a full 60fps synchronization with the help of _batched input upsync/downsync_ for satisfying network I/O performance. diff --git a/battle_srv/models/room.go b/battle_srv/models/room.go index 140385e..f368a31 100644 --- a/battle_srv/models/room.go +++ b/battle_srv/models/room.go @@ -1520,7 +1520,7 @@ func (pR *Room) refreshColliders(spaceW, spaceH int32) { 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) - colliderWidth, colliderHeight := player.ColliderRadius*2, player.ColliderRadius*3 + colliderWidth, colliderHeight := player.ColliderRadius*2, player.ColliderRadius*4 playerCollider := GenerateRectCollider(wx, wy, colliderWidth, colliderHeight, pR.collisionSpaceOffsetX, pR.collisionSpaceOffsetY, "Player") playerCollider.Data = player pR.Space.Add(playerCollider) @@ -1579,12 +1579,22 @@ func (pR *Room) doBattleMainLoopPerTickBackendDynamicsWithProperLocking(prevRend func (pR *Room) downsyncToAllPlayers(inputsBufferSnapshot *InputsBufferSnapshot) { /* - [WARNING] This function MUST BE called while "pR.InputsBufferLock" is LOCKED for preserving the order of generation of "inputsBufferSnapshot" -- see comments in "OnBattleCmdReceived" and [this issue](https://github.com/genxium/DelayNoMore/issues/12). + [WARNING] This function MUST BE called while "pR.InputsBufferLock" is LOCKED to **preserve the order of generation of "inputsBufferSnapshot" for sending** -- see comments in "OnBattleCmdReceived" and [this issue](https://github.com/genxium/DelayNoMore/issues/12). Actually if each player session were both intrinsically thread-safe & non-blocking for writing (like Java NIO), I could've just called "playerSession.WriteMessage" while holding "pR.InputsBufferLock" -- but the ws session provided by Gorilla library is neither thread-safe nor non-blocking for writing, which is fine because it creates a chance for the users to solve an interesting problem :) - */ - /* - Moreover, we're downsyncing a same "inputsBufferSnapshot" for all players in the same battle and this is by design, i.e. not respecting "player.LastSentInputFrameId" because "new all-confirmed inputFrameDownsyncs" are the same for all players and ws is TCP-based (no loss of consecutive packets except for reconnection -- which is already handled by READDED_BATTLE_COLLIDER_ACKED) + + Moreover, we're downsyncing a same "inputsBufferSnapshot" for all players in the same battle and this is by design, i.e. not respecting "player.LastSentInputFrameId" because "new all-confirmed inputFrameDownsyncs" are the same for all players and ws is TCP-based (no loss of consecutive packets except for reconnection -- which is already handled by READDED_BATTLE_COLLIDER_ACKED) + + Lastly noting just for fun, if in "OnBattleCmdReceived" we need downsync to a single specific player (keeping **the order of generation of "inputsBufferSnapshot" preserved for sending** of course), in theory it's better to do it by the following order. + 1. lock "InputsBuffer"; + 2. generate downsync msg; + 3. lock "pR.PlayerDownsyncChanDict[playerId]"; + 4. put downsync msg to "pR.PlayerDownsyncChanDict[playerId]"; + 5. unlock "InputsBuffer"; + 6. now other threads are allowed to lock "inputsBuffer", and we can do "other things" on "pR.PlayerDownsyncChanDict[playerId]"; + 7. unlock "pR.PlayerDownsyncChanDict[playerId]". + + The difference from our current approach is that the "pR.PlayerDownsyncChanDict[playerId]" in use is a Golang channel, i.e. when executing #4 it automatically executes #3 (before) & #7 (after) as well, thus we couldn't do #5 & #6 in between. */ for playerId, playerDownsyncChan := range pR.PlayerDownsyncChanDict { /* diff --git a/battle_srv/protos/room_downsync_frame.pb.go b/battle_srv/protos/room_downsync_frame.pb.go index 7b8f1f9..f4ab9eb 100644 --- a/battle_srv/protos/room_downsync_frame.pb.go +++ b/battle_srv/protos/room_downsync_frame.pb.go @@ -933,6 +933,11 @@ type BattleColliderInfo struct { SpAtkLookupFrames int32 `protobuf:"varint,25,opt,name=spAtkLookupFrames,proto3" json:"spAtkLookupFrames,omitempty"` RenderCacheSize int32 `protobuf:"varint,26,opt,name=renderCacheSize,proto3" json:"renderCacheSize,omitempty"` MeleeSkillConfig map[int32]*MeleeBullet `protobuf:"bytes,27,rep,name=meleeSkillConfig,proto3" json:"meleeSkillConfig,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // skillId -> skill + SnapIntoPlatformOverlap float64 `protobuf:"fixed64,28,opt,name=snapIntoPlatformOverlap,proto3" json:"snapIntoPlatformOverlap,omitempty"` + SnapIntoPlatformThreshold float64 `protobuf:"fixed64,29,opt,name=snapIntoPlatformThreshold,proto3" json:"snapIntoPlatformThreshold,omitempty"` + JumpingInitVelY int32 `protobuf:"varint,30,opt,name=jumpingInitVelY,proto3" json:"jumpingInitVelY,omitempty"` + GravityX int32 `protobuf:"varint,31,opt,name=gravityX,proto3" json:"gravityX,omitempty"` + GravityY int32 `protobuf:"varint,32,opt,name=gravityY,proto3" json:"gravityY,omitempty"` } func (x *BattleColliderInfo) Reset() { @@ -1149,6 +1154,41 @@ func (x *BattleColliderInfo) GetMeleeSkillConfig() map[int32]*MeleeBullet { return nil } +func (x *BattleColliderInfo) GetSnapIntoPlatformOverlap() float64 { + if x != nil { + return x.SnapIntoPlatformOverlap + } + return 0 +} + +func (x *BattleColliderInfo) GetSnapIntoPlatformThreshold() float64 { + if x != nil { + return x.SnapIntoPlatformThreshold + } + return 0 +} + +func (x *BattleColliderInfo) GetJumpingInitVelY() int32 { + if x != nil { + return x.JumpingInitVelY + } + return 0 +} + +func (x *BattleColliderInfo) GetGravityX() int32 { + if x != nil { + return x.GravityX + } + return 0 +} + +func (x *BattleColliderInfo) GetGravityY() int32 { + if x != nil { + return x.GravityY + } + return 0 +} + type RoomDownsyncFrame struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1392,7 +1432,7 @@ var file_room_downsync_frame_proto_rawDesc = []byte{ 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x2a, 0x0a, 0x10, 0x6f, 0x66, 0x66, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x05, 0x52, 0x10, 0x6f, 0x66, 0x66, 0x65, - 0x6e, 0x64, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x22, 0x98, 0x0d, 0x0a, + 0x6e, 0x64, 0x65, 0x72, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64, 0x22, 0xf2, 0x0e, 0x0a, 0x12, 0x42, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x74, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, @@ -1480,48 +1520,62 @@ var file_room_downsync_frame_proto_rawDesc = []byte{ 0x74, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6c, 0x69, 0x64, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x53, 0x6b, 0x69, 0x6c, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x10, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x53, 0x6b, 0x69, 0x6c, - 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x5d, 0x0a, 0x16, 0x53, 0x74, 0x72, 0x54, 0x6f, - 0x56, 0x65, 0x63, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x73, 0x2e, 0x56, 0x65, 0x63, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x65, 0x0a, 0x1a, 0x53, 0x74, 0x72, 0x54, 0x6f, 0x50, - 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x58, 0x0a, - 0x15, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x53, 0x6b, 0x69, 0x6c, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x29, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, - 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd2, 0x02, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, - 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x40, 0x0a, - 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, - 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, - 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, - 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, - 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, - 0x65, 0x74, 0x52, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, - 0x12, 0x36, 0x0a, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x16, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x1a, 0x52, 0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x79, - 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x73, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, - 0x63, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x13, 0x5a, 0x11, - 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x5f, 0x73, 0x72, 0x76, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x38, 0x0a, 0x17, 0x73, 0x6e, 0x61, 0x70, 0x49, + 0x6e, 0x74, 0x6f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x4f, 0x76, 0x65, 0x72, 0x6c, + 0x61, 0x70, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x01, 0x52, 0x17, 0x73, 0x6e, 0x61, 0x70, 0x49, 0x6e, + 0x74, 0x6f, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x4f, 0x76, 0x65, 0x72, 0x6c, 0x61, + 0x70, 0x12, 0x3c, 0x0a, 0x19, 0x73, 0x6e, 0x61, 0x70, 0x49, 0x6e, 0x74, 0x6f, 0x50, 0x6c, 0x61, + 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x1d, + 0x20, 0x01, 0x28, 0x01, 0x52, 0x19, 0x73, 0x6e, 0x61, 0x70, 0x49, 0x6e, 0x74, 0x6f, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, + 0x28, 0x0a, 0x0f, 0x6a, 0x75, 0x6d, 0x70, 0x69, 0x6e, 0x67, 0x49, 0x6e, 0x69, 0x74, 0x56, 0x65, + 0x6c, 0x59, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x6a, 0x75, 0x6d, 0x70, 0x69, 0x6e, + 0x67, 0x49, 0x6e, 0x69, 0x74, 0x56, 0x65, 0x6c, 0x59, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x61, + 0x76, 0x69, 0x74, 0x79, 0x58, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x67, 0x72, 0x61, + 0x76, 0x69, 0x74, 0x79, 0x58, 0x12, 0x1a, 0x0a, 0x08, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x79, + 0x59, 0x18, 0x20, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x79, + 0x59, 0x1a, 0x5d, 0x0a, 0x16, 0x53, 0x74, 0x72, 0x54, 0x6f, 0x56, 0x65, 0x63, 0x32, 0x44, 0x4c, + 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, + 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x56, 0x65, 0x63, 0x32, + 0x44, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x1a, 0x65, 0x0a, 0x1a, 0x53, 0x74, 0x72, 0x54, 0x6f, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, + 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x31, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, + 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x58, 0x0a, 0x15, 0x4d, 0x65, 0x6c, 0x65, 0x65, + 0x53, 0x6b, 0x69, 0x6c, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x29, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, + 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0xd2, 0x02, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, + 0x6e, 0x63, 0x46, 0x72, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x40, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, + 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x73, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x46, 0x72, + 0x61, 0x6d, 0x65, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x07, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x4e, 0x61, 0x6e, 0x6f, + 0x73, 0x12, 0x37, 0x0a, 0x0c, 0x6d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, + 0x2e, 0x4d, 0x65, 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x52, 0x0c, 0x6d, 0x65, + 0x6c, 0x65, 0x65, 0x42, 0x75, 0x6c, 0x6c, 0x65, 0x74, 0x73, 0x12, 0x36, 0x0a, 0x16, 0x62, 0x61, + 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, + 0x4d, 0x61, 0x73, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x62, 0x61, 0x63, 0x6b, + 0x65, 0x6e, 0x64, 0x55, 0x6e, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x72, 0x6d, 0x65, 0x64, 0x4d, 0x61, + 0x73, 0x6b, 0x1a, 0x52, 0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6c, 0x61, + 0x79, 0x65, 0x72, 0x44, 0x6f, 0x77, 0x6e, 0x73, 0x79, 0x6e, 0x63, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x13, 0x5a, 0x11, 0x62, 0x61, 0x74, 0x74, 0x6c, 0x65, + 0x5f, 0x73, 0x72, 0x76, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/charts/smooth_melee_attack_spedup.gif b/charts/smooth_melee_attack_spedup_v088.gif similarity index 100% rename from charts/smooth_melee_attack_spedup.gif rename to charts/smooth_melee_attack_spedup_v088.gif diff --git a/dnmshared/resolv_helper.go b/dnmshared/resolv_helper.go index b534eb7..480360e 100644 --- a/dnmshared/resolv_helper.go +++ b/dnmshared/resolv_helper.go @@ -20,7 +20,7 @@ func ConvexPolygonStr(body *resolv.ConvexPolygon) string { func GenerateRectCollider(origX, origY, w, h, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object { cx, cy := WorldToPolygonColliderAnchorPos(origX, origY, w*0.5, h*0.5, spaceOffsetX, spaceOffsetY) - return GenerateRectColliderInCollisionSpace(cx, cy, w, h, tag) + return GenerateRectColliderInCollisionSpace(cx, cy, w, h, tag) } func GenerateRectColliderInCollisionSpace(cx, cy, w, h float64, tag string) *resolv.Object { diff --git a/dnmshared/tmx_parser.go b/dnmshared/tmx_parser.go index 7e9f81e..d46616d 100644 --- a/dnmshared/tmx_parser.go +++ b/dnmshared/tmx_parser.go @@ -7,6 +7,7 @@ import ( "encoding/base64" "encoding/xml" "errors" + "fmt" "go.uber.org/zap" "io/ioutil" "math" @@ -43,13 +44,13 @@ type TmxOrTsxPolyline struct { type TmxOrTsxObject struct { Id int `xml:"id,attr"` - Gid *int `xml:"gid,attr"` + Gid int `xml:"gid,attr"` X float64 `xml:"x,attr"` Y float64 `xml:"y,attr"` Properties *TmxOrTsxProperties `xml:"properties"` Polyline *TmxOrTsxPolyline `xml:"polyline"` - Width *float64 `xml:"width,attr"` - Height *float64 `xml:"height,attr"` + Width float64 `xml:"width,attr"` + Height float64 `xml:"height,attr"` } type TmxOrTsxObjectGroup struct { @@ -376,13 +377,37 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMap map[int]StrToP } for _, singleObjInTmxFile := range objGroup.Objects { - if nil == singleObjInTmxFile.Polyline { - continue - } if nil == singleObjInTmxFile.Properties.Property || "boundary_type" != singleObjInTmxFile.Properties.Property[0].Name || "barrier" != singleObjInTmxFile.Properties.Property[0].Value { continue } + if nil == singleObjInTmxFile.Polyline { + pts := make([]*Vec2D, 4) + s := make([]string, 0) + pts[0] = &Vec2D{ + X: float64(0), + Y: float64(0), + } + pts[1] = &Vec2D{ + X: float64(0), + Y: singleObjInTmxFile.Height, + } + pts[2] = &Vec2D{ + X: singleObjInTmxFile.Width, + Y: singleObjInTmxFile.Height, + } + pts[3] = &Vec2D{ + X: singleObjInTmxFile.Width, + Y: float64(0), + } + for _, pt := range pts { + s = append(s, fmt.Sprintf("%v,%v", pt.X, pt.Y)) + } + singleObjInTmxFile.Polyline = &TmxOrTsxPolyline{ + Points: strings.Join(s, " "), + } + } + thePolygon2DInWorld, err := tmxPolylineToPolygon2D(pTmxMapIns, singleObjInTmxFile, singleObjInTmxFile.Polyline) if nil != err { panic(err) diff --git a/frontend/assets/resources/pbfiles/room_downsync_frame.proto b/frontend/assets/resources/pbfiles/room_downsync_frame.proto index 65d5e06..26060e7 100644 --- a/frontend/assets/resources/pbfiles/room_downsync_frame.proto +++ b/frontend/assets/resources/pbfiles/room_downsync_frame.proto @@ -137,6 +137,12 @@ message BattleColliderInfo { int32 renderCacheSize = 26; map meleeSkillConfig = 27; // skillId -> skill + + double snapIntoPlatformOverlap = 28; + double snapIntoPlatformThreshold = 29; + int32 jumpingInitVelY = 30; + int32 gravityX = 31; + int32 gravityY = 32; } message RoomDownsyncFrame { diff --git a/frontend/assets/scenes/login.fire b/frontend/assets/scenes/login.fire index 5bc0d73..76a6bfa 100644 --- a/frontend/assets/scenes/login.fire +++ b/frontend/assets/scenes/login.fire @@ -440,7 +440,7 @@ "array": [ 0, 0, - 210.54381524704266, + 216.50635094610968, 0, 0, 0, diff --git a/frontend/assets/scenes/offline_map_1.fire b/frontend/assets/scenes/offline_map_1.fire index 1e5c272..98ab253 100644 --- a/frontend/assets/scenes/offline_map_1.fire +++ b/frontend/assets/scenes/offline_map_1.fire @@ -454,7 +454,7 @@ "array": [ 0, 0, - 217.365603642227, + 217.71545143883017, 0, 0, 0, diff --git a/frontend/assets/scripts/Map.js b/frontend/assets/scripts/Map.js index dcdb91f..8f38923 100644 --- a/frontend/assets/scripts/Map.js +++ b/frontend/assets/scripts/Map.js @@ -769,7 +769,7 @@ cc.Class({ newPlayerNode.setPosition(wx, wy); playerScriptIns.mapNode = self.node; const colliderWidth = playerDownsyncInfo.colliderRadius * 2, - colliderHeight = playerDownsyncInfo.colliderRadius * 3; + colliderHeight = playerDownsyncInfo.colliderRadius * 4; const [x0, y0] = self.virtualGridToPolygonColliderAnchorPos(vx, vy, colliderWidth, colliderHeight), pts = [[0, 0], [colliderWidth, 0], [colliderWidth, colliderHeight], [0, colliderHeight]]; diff --git a/frontend/assets/scripts/OfflineMap.js b/frontend/assets/scripts/OfflineMap.js index b754585..e54ba7c 100644 --- a/frontend/assets/scripts/OfflineMap.js +++ b/frontend/assets/scripts/OfflineMap.js @@ -591,38 +591,4 @@ cc.Class({ } } }, - - spawnPlayerNode(joinIndex, vx, vy, playerDownsyncInfo) { - const self = this; - const newPlayerNode = cc.instantiate(self.controlledCharacterPrefab) - const playerScriptIns = newPlayerNode.getComponent("ControlledCharacter"); - if (1 == joinIndex) { - playerScriptIns.setSpecies("SoldierWaterGhost"); - } else if (2 == joinIndex) { - playerScriptIns.setSpecies("SoldierFireGhost"); - } - - const [wx, wy] = self.virtualGridToWorldPos(vx, vy); - newPlayerNode.setPosition(wx, wy); - playerScriptIns.mapNode = self.node; - const colliderWidth = playerDownsyncInfo.colliderRadius * 2, - colliderHeight = playerDownsyncInfo.colliderRadius * 4; - const [x0, y0] = self.virtualGridToPolygonColliderAnchorPos(vx, vy, colliderWidth, colliderHeight), - pts = [[0, 0], [colliderWidth, 0], [colliderWidth, colliderHeight], [0, colliderHeight]]; - - const newPlayerCollider = self.collisionSys.createPolygon(x0, y0, pts); - const collisionPlayerIndex = self.collisionPlayerIndexPrefix + joinIndex; - newPlayerCollider.data = playerDownsyncInfo; - self.collisionSysMap.set(collisionPlayerIndex, newPlayerCollider); - - console.log(`Created new player collider: joinIndex=${joinIndex}, colliderRadius=${playerDownsyncInfo.colliderRadius}`); - - safelyAddChild(self.node, newPlayerNode); - setLocalZOrder(newPlayerNode, 5); - - newPlayerNode.active = true; - playerScriptIns.updateCharacterAnim(playerDownsyncInfo, null, true); - - return [newPlayerNode, playerScriptIns]; - }, }); diff --git a/frontend/assets/scripts/modules/room_downsync_frame_proto_bundle.forcemsg.js b/frontend/assets/scripts/modules/room_downsync_frame_proto_bundle.forcemsg.js index fa27db9..d58d1e3 100644 --- a/frontend/assets/scripts/modules/room_downsync_frame_proto_bundle.forcemsg.js +++ b/frontend/assets/scripts/modules/room_downsync_frame_proto_bundle.forcemsg.js @@ -4545,6 +4545,11 @@ $root.protos = (function() { * @property {number|null} [spAtkLookupFrames] BattleColliderInfo spAtkLookupFrames * @property {number|null} [renderCacheSize] BattleColliderInfo renderCacheSize * @property {Object.|null} [meleeSkillConfig] BattleColliderInfo meleeSkillConfig + * @property {number|null} [snapIntoPlatformOverlap] BattleColliderInfo snapIntoPlatformOverlap + * @property {number|null} [snapIntoPlatformThreshold] BattleColliderInfo snapIntoPlatformThreshold + * @property {number|null} [jumpingInitVelY] BattleColliderInfo jumpingInitVelY + * @property {number|null} [gravityX] BattleColliderInfo gravityX + * @property {number|null} [gravityY] BattleColliderInfo gravityY */ /** @@ -4773,6 +4778,46 @@ $root.protos = (function() { */ BattleColliderInfo.prototype.meleeSkillConfig = $util.emptyObject; + /** + * BattleColliderInfo snapIntoPlatformOverlap. + * @member {number} snapIntoPlatformOverlap + * @memberof protos.BattleColliderInfo + * @instance + */ + BattleColliderInfo.prototype.snapIntoPlatformOverlap = 0; + + /** + * BattleColliderInfo snapIntoPlatformThreshold. + * @member {number} snapIntoPlatformThreshold + * @memberof protos.BattleColliderInfo + * @instance + */ + BattleColliderInfo.prototype.snapIntoPlatformThreshold = 0; + + /** + * BattleColliderInfo jumpingInitVelY. + * @member {number} jumpingInitVelY + * @memberof protos.BattleColliderInfo + * @instance + */ + BattleColliderInfo.prototype.jumpingInitVelY = 0; + + /** + * BattleColliderInfo gravityX. + * @member {number} gravityX + * @memberof protos.BattleColliderInfo + * @instance + */ + BattleColliderInfo.prototype.gravityX = 0; + + /** + * BattleColliderInfo gravityY. + * @member {number} gravityY + * @memberof protos.BattleColliderInfo + * @instance + */ + BattleColliderInfo.prototype.gravityY = 0; + /** * Creates a new BattleColliderInfo instance using the specified properties. * @function create @@ -4858,6 +4903,16 @@ $root.protos = (function() { writer.uint32(/* id 27, wireType 2 =*/218).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); + if (message.snapIntoPlatformThreshold != null && Object.hasOwnProperty.call(message, "snapIntoPlatformThreshold")) + writer.uint32(/* id 29, wireType 1 =*/233).double(message.snapIntoPlatformThreshold); + if (message.jumpingInitVelY != null && Object.hasOwnProperty.call(message, "jumpingInitVelY")) + writer.uint32(/* id 30, wireType 0 =*/240).int32(message.jumpingInitVelY); + if (message.gravityX != null && Object.hasOwnProperty.call(message, "gravityX")) + writer.uint32(/* id 31, wireType 0 =*/248).int32(message.gravityX); + if (message.gravityY != null && Object.hasOwnProperty.call(message, "gravityY")) + writer.uint32(/* id 32, wireType 0 =*/256).int32(message.gravityY); return writer; }; @@ -5053,6 +5108,26 @@ $root.protos = (function() { message.meleeSkillConfig[key] = value; break; } + case 28: { + message.snapIntoPlatformOverlap = reader.double(); + break; + } + case 29: { + message.snapIntoPlatformThreshold = reader.double(); + break; + } + case 30: { + message.jumpingInitVelY = reader.int32(); + break; + } + case 31: { + message.gravityX = reader.int32(); + break; + } + case 32: { + message.gravityY = reader.int32(); + break; + } default: reader.skipType(tag & 7); break; @@ -5191,6 +5266,21 @@ $root.protos = (function() { } } } + if (message.snapIntoPlatformOverlap != null && message.hasOwnProperty("snapIntoPlatformOverlap")) + if (typeof message.snapIntoPlatformOverlap !== "number") + return "snapIntoPlatformOverlap: number expected"; + if (message.snapIntoPlatformThreshold != null && message.hasOwnProperty("snapIntoPlatformThreshold")) + if (typeof message.snapIntoPlatformThreshold !== "number") + return "snapIntoPlatformThreshold: number expected"; + if (message.jumpingInitVelY != null && message.hasOwnProperty("jumpingInitVelY")) + if (!$util.isInteger(message.jumpingInitVelY)) + return "jumpingInitVelY: integer expected"; + if (message.gravityX != null && message.hasOwnProperty("gravityX")) + if (!$util.isInteger(message.gravityX)) + return "gravityX: integer expected"; + if (message.gravityY != null && message.hasOwnProperty("gravityY")) + if (!$util.isInteger(message.gravityY)) + return "gravityY: integer expected"; return null; }; @@ -5296,6 +5386,16 @@ $root.protos = (function() { message.meleeSkillConfig[keys[i]] = $root.protos.MeleeBullet.fromObject(object.meleeSkillConfig[keys[i]]); } } + if (object.snapIntoPlatformOverlap != null) + message.snapIntoPlatformOverlap = Number(object.snapIntoPlatformOverlap); + if (object.snapIntoPlatformThreshold != null) + message.snapIntoPlatformThreshold = Number(object.snapIntoPlatformThreshold); + if (object.jumpingInitVelY != null) + message.jumpingInitVelY = object.jumpingInitVelY | 0; + if (object.gravityX != null) + message.gravityX = object.gravityX | 0; + if (object.gravityY != null) + message.gravityY = object.gravityY | 0; return message; }; @@ -5349,6 +5449,11 @@ $root.protos = (function() { object.virtualGridToWorldRatio = 0; object.spAtkLookupFrames = 0; object.renderCacheSize = 0; + object.snapIntoPlatformOverlap = 0; + object.snapIntoPlatformThreshold = 0; + object.jumpingInitVelY = 0; + object.gravityX = 0; + object.gravityY = 0; } if (message.stageName != null && message.hasOwnProperty("stageName")) object.stageName = message.stageName; @@ -5418,6 +5523,16 @@ $root.protos = (function() { for (var j = 0; j < keys2.length; ++j) object.meleeSkillConfig[keys2[j]] = $root.protos.MeleeBullet.toObject(message.meleeSkillConfig[keys2[j]], options); } + if (message.snapIntoPlatformOverlap != null && message.hasOwnProperty("snapIntoPlatformOverlap")) + object.snapIntoPlatformOverlap = options.json && !isFinite(message.snapIntoPlatformOverlap) ? String(message.snapIntoPlatformOverlap) : message.snapIntoPlatformOverlap; + if (message.snapIntoPlatformThreshold != null && message.hasOwnProperty("snapIntoPlatformThreshold")) + object.snapIntoPlatformThreshold = options.json && !isFinite(message.snapIntoPlatformThreshold) ? String(message.snapIntoPlatformThreshold) : message.snapIntoPlatformThreshold; + if (message.jumpingInitVelY != null && message.hasOwnProperty("jumpingInitVelY")) + object.jumpingInitVelY = message.jumpingInitVelY; + if (message.gravityX != null && message.hasOwnProperty("gravityX")) + object.gravityX = message.gravityX; + if (message.gravityY != null && message.hasOwnProperty("gravityY")) + object.gravityY = message.gravityY; return object; };