Compare commits

...

113 Commits

Author SHA1 Message Date
genxium
b79e2dc935 Enhanced UDP message callback handling. 2023-02-09 23:34:00 +08:00
genxium
7b0c807496 Drafted enhancement of UDP message callback. 2023-02-09 10:18:23 +08:00
genxium
5c611b626d Minor fix. 2023-02-08 19:28:40 +08:00
genxium
38149279bd Drafted hp handling. 2023-02-08 18:32:59 +08:00
genxium
a762c563d9 Updated skill sets and animations. 2023-02-07 11:31:59 +08:00
genxium
6a0d729dee Added more animation resources. 2023-02-06 12:02:44 +08:00
genxium
f10389bf55 Minor update. 2023-02-05 20:24:09 +08:00
genxium
6b3d1ed49a Enhanced UI handling upon battle started. 2023-02-05 18:44:37 +08:00
genxium
d25bb5ff10 Enhanced inertia handling. 2023-02-05 11:27:26 +08:00
genxium
d38d4b4ec9 Updated README. 2023-02-05 00:16:09 +08:00
genxium
03828db6ff Reverted input scale. 2023-02-04 21:41:58 +08:00
genxium
917fca2bcd Improved on wall dynamics. 2023-02-04 18:33:49 +08:00
genxium
680e4f1f59 Updated README. 2023-02-03 22:56:58 +08:00
genxium
f367609276 Fixes for rollback on UDP peer upsync. 2023-02-03 22:06:03 +08:00
genxium
70ae4a4c92 Fixed socket binding compatibility issue for Android and Windows. 2023-02-03 09:51:56 +08:00
genxium
6f561bea87 Fixed build for Android. 2023-02-03 00:21:07 +08:00
genxium
70a86c27b0 Enhancement for libuv thread safety. 2023-02-02 21:53:43 +08:00
genxium
b0f37d2237 Minor update. 2023-02-01 23:41:08 +08:00
genxium
09376b827d Reverted magic constants. 2023-02-01 23:27:27 +08:00
genxium
d560392c79 Minor fix. 2023-02-01 23:17:55 +08:00
genxium
c75f642011 Minor update again. 2023-02-01 22:55:27 +08:00
genxium
5cfcac6cf6 Minor update. 2023-02-01 21:44:33 +08:00
genxium
d37ebd4c33 Updated README. 2023-02-01 18:59:14 +08:00
genxium
1d138b17c3 Fixes for UDP p2p packets handling in frontend input buffer. 2023-02-01 17:43:15 +08:00
genxium
851678e2f3 Minor fix. 2023-02-01 13:09:17 +08:00
genxium
2fb6fd6bea Updated CameraTracker. 2023-01-31 23:11:46 +08:00
genxium
e3440a2a06 Fixes for UDP use in input prediction. 2023-01-31 22:39:21 +08:00
genxium
8de2d6e4e7 Enhancement for type#1 force-confirmation trigger. 2023-01-31 09:57:37 +08:00
genxium
ba2dd0b22e Added thread-safety comments for libuv codes. 2023-01-30 23:41:22 +08:00
genxium
754610d31b Updated documentation. 2023-01-30 09:56:19 +08:00
genxium
a35de9b83c Enhanced backend udp tunnel workflow. 2023-01-30 09:21:06 +08:00
genxium
2b6cb57050 Enabled backend udp tunnel forwarding. 2023-01-30 00:25:11 +08:00
genxium
677e76179c Minor fix. 2023-01-29 22:38:12 +08:00
genxium
c65c122f45 Added front-to-back UDP channel punching. 2023-01-29 18:20:48 +08:00
genxium
b5530b352b Updated pb files. 2023-01-29 13:10:19 +08:00
genxium
4e638fb2ec Preparing in battle udp tunnel on backend. 2023-01-29 12:42:48 +08:00
genxium
7c454130db Minor fix. 2023-01-28 23:50:32 +08:00
genxium
5863f88435 Minor update. 2023-01-28 12:55:22 +08:00
genxium
bbf07fe518 Fixed Android segfault on mysterious udp reception callback. 2023-01-28 10:52:58 +08:00
genxium
26660d75d2 Minor fix. 2023-01-28 00:13:30 +08:00
genxium
76cdbc8f1f Updated trouble shooting doc. 2023-01-28 00:10:10 +08:00
genxium
4097a8da75 Fixed libuv multithreading. 2023-01-27 22:51:34 +08:00
genxium
e7bf6ec16b Added basic input upsync via udp. 2023-01-26 21:34:29 +08:00
genxium
7ab983949c Fixes in udp_session type usage for cross-platform use. 2023-01-26 12:43:38 +08:00
genxium
2028f8277d Fixed Android building setup. 2023-01-26 00:08:46 +08:00
genxium
60bb74169e Fixed libuv resource deallocation. 2023-01-25 23:47:54 +08:00
genxium
8536521136 Integrated basic holepunching for multiplayer codebase. 2023-01-25 18:26:13 +08:00
genxium
5df545e168 Fixes for frontend hole punching compatibility. 2023-01-25 11:57:59 +08:00
genxium
6bc3feab58 Fixed part of Cpp to Js callback scopes. 2023-01-24 21:30:58 +08:00
genxium
e21e1b840f Drafted udp holepunching upsync pathway. 2023-01-24 12:00:49 +08:00
genxium
ef345e0e48 Fine tune for rollback params. 2023-01-24 10:08:34 +08:00
genxium
0168e2182e Further updates on win32 build templates. 2023-01-23 23:18:21 +08:00
genxium
58b06f6a10 Updated win32 build templates. 2023-01-23 12:22:34 +08:00
genxium
58e60a789f Preparation for native app build. 2023-01-22 23:05:32 +08:00
genxium
b5b43bb596 Minor update. 2023-01-22 14:32:32 +08:00
genxium
59767c1ed5 Added network doctor stats. 2023-01-22 11:39:27 +08:00
genxium
1c6ad5c8f8 Minor fix. 2023-01-21 23:03:55 +08:00
genxium
34e0893eb8 Added network doctor for frontend. 2023-01-21 22:53:41 +08:00
genxium
cc7524becd Updated README. 2023-01-21 11:59:01 +08:00
genxium
d06cb18a08 Fixed inertia on jumping. 2023-01-21 11:11:48 +08:00
genxium
00816fb636 Minor update. 2023-01-21 10:41:38 +08:00
genxium
ff24bea055 Fixed fireball trigger. 2023-01-21 10:40:13 +08:00
genxium
56d66a128a Minor updates. 2023-01-20 23:44:26 +08:00
genxium
2f097dfec5 Added turn-around and dashing actual triggers. 2023-01-20 23:22:02 +08:00
genxium
ff48b47ecc Updated documentation for the plan of UDP secondary session. 2023-01-20 20:49:26 +08:00
genxium
7a0127b17d Updated README. 2023-01-20 14:32:38 +08:00
genxium
59c8427c70 Enhanced turn-around performance. 2023-01-20 11:29:27 +08:00
genxium
c357ebad3b Updated README again. 2023-01-19 22:19:40 +08:00
genxium
b2e1f7c2a6 Updated README. 2023-01-19 10:45:48 +08:00
genxium
9a8c32197e Added TurnAroundFramesToRecover. 2023-01-19 09:20:52 +08:00
genxium
a82a238ce9 Added frontend log for inspection of "onPeerInputFrameUpsync". 2023-01-18 22:43:10 +08:00
genxium
5b76c5bbfb Minor fix. 2023-01-18 18:03:54 +08:00
genxium
b81c470135 Drafted peer inputFrameUpsync broadcasting mechanism. 2023-01-18 17:53:58 +08:00
genxium
48074d48af Misc fixes for UI alignments. 2023-01-18 12:22:12 +08:00
genxium
342efc623c Made frontend landscape. 2023-01-17 23:35:23 +08:00
genxium
b8e757064d Further enhanced frontend input processing and fixed frame data logging. 2023-01-17 17:38:18 +08:00
genxium
71b9e72592 Minor fix. 2023-01-17 15:16:31 +08:00
genxium
21b48b7c0d Updated frontend input generation. 2023-01-17 13:07:26 +08:00
genxium
fbfca965e6 Minor update. 2023-01-17 12:49:49 +08:00
genxium
b27b567c77 Fixed frontend action triggers. 2023-01-17 12:48:51 +08:00
genxium
e9119530f1 Updated README for UDP discussion. 2023-01-16 23:25:40 +08:00
genxium
e6a4295773 Updated charts in README. 2023-01-15 17:43:02 +08:00
Wing
aa14529bf8 Merge pull request #19 from genxium/explosion
Drafted bullet explosion data structure.
2023-01-15 17:23:52 +08:00
genxium
84af0d1572 Drafted bullet explosion data structure. 2023-01-15 17:21:34 +08:00
genxium
16fb23c376 Updated charts and refs in README. 2023-01-14 23:06:45 +08:00
genxium
d1f8a58154 Updated README. 2023-01-14 09:35:56 +08:00
genxium
89c31e8944 Updated README. 2023-01-13 15:13:27 +08:00
genxium
45380d170f Fixed fireball rollback sync. 2023-01-13 14:55:56 +08:00
genxium
dd9c03404e Fixed fireball rollback mechanism. 2023-01-13 12:10:06 +08:00
genxium
29e402ea71 Integrated onwall movements to multiplayer battle. 2023-01-12 18:09:02 +08:00
genxium
b1e3d6525c Fixes for wall jumping. 2023-01-12 16:09:20 +08:00
genxium
845282db50 Minor fix. 2023-01-12 12:55:57 +08:00
genxium
71a5a7b727 Drafted anti-air attack for Monk. 2023-01-11 22:24:31 +08:00
genxium
934a495d47 Updates for fireball bullet. 2023-01-11 18:42:57 +08:00
genxium
9725fb9df2 Minor updates. 2023-01-10 12:47:05 +08:00
Wing
7d922aab0b Merge pull request #18 from genxium/npc
Emergency fix for bullet lifecycle handling.
2023-01-10 12:40:35 +08:00
genxium
823624d95d Implemented basic fireball collision. 2023-01-10 12:37:38 +08:00
genxium
ab122a7bc8 Drafted new character as NPC. 2023-01-08 20:34:29 +08:00
genxium
5b9b3a0b55 Updated documentation. 2023-01-07 22:51:06 +08:00
genxium
24e980c17f Simplified backend input prediction. 2023-01-05 14:07:59 +08:00
genxium
ab6a04693d Enhanced backend input prediction alignment with the frontend counterpart. 2023-01-05 12:14:55 +08:00
genxium
bce26f4663 Minor fix. 2023-01-05 10:34:32 +08:00
Wing
938ca7e57d Merge pull request #17 from genxium/multihit
Added cancellable skills.
2023-01-05 10:23:28 +08:00
genxium
e2191f9d13 Misc fixes. 2023-01-05 10:20:01 +08:00
genxium
2d04363d69 Fixed frontend debug drawer. 2023-01-04 23:49:19 +08:00
genxium
80c6e05731 Initial attempt integrating online battle. 2023-01-02 23:35:56 +08:00
genxium
69581009ee Further simplified proto communication. 2023-01-02 20:42:23 +08:00
genxium
bd870e4059 Misc fixes. 2023-01-02 16:38:13 +08:00
genxium
915bbcae3d Fixes for KnifeGirl anim. 2023-01-02 12:23:15 +08:00
genxium
4c64c1984c Enhanced multihit config. 2023-01-02 00:08:54 +08:00
genxium
325dbfb79c A temp broken commit except for OfflineMap - drafted basic cancellable skills. 2023-01-01 20:18:35 +08:00
genxium
8b80117d3d A temp broken commit except for OfflineMap - refactoring character/skill/bullet config hierarchy. 2023-01-01 15:43:25 +08:00
genxium
c7fc377a2b A temp broken commit except for OfflineMap - refactoring jumping. 2022-12-31 23:28:09 +08:00
244 changed files with 43644 additions and 9575 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,5 @@
.vs
**/.vs
battle_srv/test_cases/test_cases
battle_srv/test_cases/tests
*.pid

View File

@@ -47,3 +47,32 @@ renderFrameId | toApplyInputFrameId
..., ..., ..., 368 | 90
369, 370, 371, 372 | 91
373, 374, 375, ... | 92
# Would using UDP instead of TCP yield better synchronization performance?
Yes, but with non-trivial efforts.
## Neat advantage using UDP
Let's check an actual use case. As soon as an inputFrame becomes all-confirmed, the server should downsync it to all active players -- and upon reception loss of the packet containing this "all-confirmed downsync inputFrame" to a certain player, the server MUST retransmit another packet containing the same inputFrame to that player.
To apply UDP on this use case, additional `ack & retransmission mechanism` would be required, which is a moderately difficult task -- don't just pick a 3rd party lib using TCP flow-control alike `sliding window mechanism`, e.g. [RUDP](https://www.geeksforgeeks.org/reliable-user-datagram-protocol-rudp/)! Here's why.
Assume that the server is downsyncing `sequence of packets[#1, #2, #3, #4, #5, #6, #7, #8, #9, #10]`, when using TCP we get the advantage that each active player is guaranteed to receive that same sequence in the same order -- however in a bad, lossy network when `packet#2` got lost several times for a certain player whose reception window size is just 5, it has to wait for the arrival of `packet#2` at `[_, #3, #4, #5, #6]`, thus unable to process `[#7, #8, #9, #10]` which could contain `unpredictable inputFrame` while `#2` being `correct prediction` for that player.
That's so neat but still an advantage for using UDP! Yet if the TCP flow-control alike `sliding window mechanism` is employed on UDP, such advantage'd be compromised.
To summarize, if UDP is used we need
- an `ack & retransmission mechanism` built on top of it to guarantee reception of critical packets for active players, and
- reception order is not necessary to be reserved (mimic [markConfirmationIfApplicable](https://github.com/genxium/DelayNoMore/blob/v0.9.14/battle_srv/models/room.go#L1085) to maintain `lastAllConfirmedInputFrameId`), but
- TCP flow-control alike `sliding window mechanism` should be avoided to gain advantage over TCP.
## Additional hassles to care about using UDP
When using UDP, it's also necessary to verify authorization of each incoming packet, e.g. by simple time limited symmetric key, due to being connectionless.
## Why not hybrid?
Instead of replacing all use of TCP by UDP, it's more reasonable to keep using TCP for login and the "all-confirmed downsync inputFrames" from server to players (and possibly "upsync inputFrames" from player to server, but tradeoff on that remains to be discussed), while using a `UDP secondary session` for broadcasting inputFrames of each individual player asap (either using p2p or not) just for **better prediction performance**!
## How do you actually implement the `UDP secondary session`?
It's not a global consensus, but in practice many UDP communications are platform specific due to their paired asynchronous I/O choices, e.g. epoll in Linux and kqueue in BSD-ish. Of course there're many 3rd party higher level encapsulated tools for cross-platform use but that introduces extra debugging when things go wrong.
Therefore, the following plan doesn't assume use of any specific 3rd party encapsulation of UDP communication.
![UDP_secondary_session](./charts/UDPEssentials.jpg)

7
MULTIHIT_ROADMAP.md Normal file
View File

@@ -0,0 +1,7 @@
Major goals
- Create several skills that can be chained by pressing "btnA" 3 times, while the 2nd skill cancels the last hit of 1st skill before the latters' FramesToRecover is over, same goes with 2nd->3rd transition.
- Note that each skill can contain "multihit".
Minor goals
- Split jumping anim into "once" part and "keep" part, depending on "character.framesElapsedInChState" we should play the corresponding part
- Add new "chState = STUNNED", which is applicable to both on ground and in air, while "inAir && STUNNED", "character.FramesToRecover" is regarded as infinite. If implemented, make the last hit of the aforementioned 3rd skill "pushback opponent to air".

View File

@@ -1,17 +1,22 @@
# Preface
This project is a demo for a websocket-based rollback netcode inspired by [GGPO](https://github.com/pond3r/ggpo/blob/master/doc/README.md).
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.5x for file size reduction, kindly note that animations are resumed from a partial progress)_
[Demo recorded over INTERNET (Phone-Wifi v.s. PC-Wifi UDP holepunched) using an input delay of 6 frames](https://pan.baidu.com/s/1UArwqDShLoPjYppjjqsTqQ?pwd=10wc), and it feels SMOOTH when playing!
![gif_demo](./charts/jump_sync_spedup.gif)
![Merged_cut_annotated_spedup](./charts/Merged_cut_annotated_spedup.gif)
Please also checkout [this demo video](https://pan.baidu.com/s/1Lmot9cb0pYylfUvC8G4fDg?pwd=ia97) 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.
As lots of feedbacks ask for a discussion on using UDP instead, I tried to summarize my personal opinion about it in [ConcerningEdgeCases](./ConcerningEdgeCases.md) -- **since v0.9.25, the project is actually equipped with UDP capabilities as follows**.
- When using the so called `native apps` on `Android` and `Windows` (I'm working casually hard to support `iOS` next), the frontends will try to use UDP hole-punching w/ the help of backend as a registry. If UDP hole-punching is working, the rollback is often less than `turn-around frames to recover` and thus not noticeable, being much better than using websocket alone. This video shows how the UDP holepunched p2p performs for [Phone-Wifi v.s. PC-Wifi (viewed by PC side)](https://pan.baidu.com/s/1K6704bJKlrSBTVqGcXhajA?pwd=l7ok).
- If UDP hole-punching is not working, e.g. for Symmetric NAT like in 4G/5G cellular network, the frontends will use backend as a UDP tunnel (or relay, whatever you like to call it). This video shows how the UDP tunnel performs for [Phone-4G v.s. PC-Wifi (viewed by PC side)](https://pan.baidu.com/s/1IZVa5wVgAdeH6D-xsZYFUw?pwd=dgkj).
- Browser vs `native app` is possible but in that case only websocket is used.
The video mainly shows the following features.
- The backend receives inputs from frontend peers and broadcasts back for synchronization.
- The game is recovered for a player upon reconnection.
- Both backend(Golang) and frontend(JavaScript) execute collision detection and handle collision contacts by the same algorithm. The backend dynamics is togglable by [Room.BackendDynamicsEnabled](https://github.com/genxium/DelayNoMore/blob/v0.5.2/battle_srv/models/room.go#L813), but **when turned off the game couldn't support recovery upon reconnection**.
# Notable Features
- Backend dynamics toggle via [Room.BackendDynamicsEnabled](https://github.com/genxium/DelayNoMore/blob/v0.9.14/battle_srv/models/room.go#L786)
- Recovery upon reconnection (only if backend dynamics is ON)
- Automatically correction for "slow ticker", especially "active slow ticker" which is well-known to be a headache for input synchronization
- Frame data logging toggle for both frontend & backend, useful for debugging out of sync entities when developing new features
_(how input delay roughly works)_
@@ -19,7 +24,10 @@ _(how input delay roughly works)_
_(how rollback-and-chase in this project roughly works)_
![server_clients](./charts/ServerClients.jpg)
![rollback_and_chase_intro](./charts/RollbackAndChase.jpg)
(By use of [GopherJs](https://github.com/gopherjs/gopherjs), the frontend codes for dynamics are now automatically generated)
![floating_point_accumulation_err](./charts/AvoidingFloatingPointAccumulationErr.jpg)
# 1. Building & running
@@ -27,7 +35,8 @@ _(how rollback-and-chase in this project roughly works)_
## 1.1 Tools to install
### Backend
- [Command Line Tools for Xcode](https://developer.apple.com/download/all/?q=command%20line%20tools) (on OSX) or [TDM-GCC](https://jmeubank.github.io/tdm-gcc/download/) (on Windows) (a `make` executable mandatory)
- [Golang1.18.6](https://golang.org/dl/) (brought down to 1.18 for GopherJs support, mandatory, in China please try a mirror site like [that of ustc](https://mirrors.ustc.edu.cn/golang/))
- [Golang1.18.6](https://golang.org/dl/) (brought down to 1.18 for _GopherJs_ support, mandatory, in China please try a mirror site like [that of ustc](https://mirrors.ustc.edu.cn/golang/))
- [GopherJs1.18.0-beta1](https://github.com/gopherjs/gopherjs/tree/v1.18.0-beta1) (optional, only for developemnt)
- [MySQL 5.7](https://dev.mysql.com/downloads/windows/installer/5.7.html) (mandatory, for OSX not all versions of 5.7 can be found thus 5.7.24 is recommended)
- [Redis 3.0.503 or above](https://redis.io/download/) (mandatory)
- [skeema](https://www.skeema.io/) (optional, only for convenient MySQL schema provisioning)
@@ -60,7 +69,7 @@ user@proj-root/battle_srv/configs> cp -r ./configs.template ./configs
user@proj-root/frontend/assets/plugin_scripts> cp ./conf.js.template ./conf.js
```
## 1.2 Actual building & running
## 1.3 Actual building & running
### Backend
```
### The following command runs mysql-server in foreground, it's almost NEVER run in such a way, please find a proper way to run it for yourself
@@ -89,3 +98,48 @@ ErrFatal {"err": "MISCONF Redis is configured to save RDB snapshots, but
```
Just restart your `redis-server` process.
### 2.2 Why not show "PING value" on frontend display?
The most important reason for not showing "PING value" is simple: in most games the "PING value" is collected by a dedicated kernel thread which doesn't interfere the UI thread or the primary networking thread. As this demo primarily runs on browser by far, I don't have this capability easily.
Moreover, in practice I found that to spot sync anomalies, the following tools are much more useful than the "PING VALUE".
- Detection of [prediction mismatch on the frontend](https://github.com/genxium/DelayNoMore/blob/v0.9.19/frontend/assets/scripts/Map.js#L842).
- Detection of [type#1 forceConfirmation on the backend](https://github.com/genxium/DelayNoMore/blob/v0.9.19/battle_srv/models/room.go#L1246).
- Detection of [type#2 forceConfirmation on the backend](https://github.com/genxium/DelayNoMore/blob/v0.9.19/battle_srv/models/room.go#L1259).
There's also some useful information displayed on the frontend when `true == Map.showNetworkDoctorInfo`.
![networkstats](./charts/networkstats.png)
### 2.3 WIN32 platform tool versioning
![visual_studio](./charts/VisualStudioSetup.png)
When building for native platforms, it's much more convenient to trigger the CocosCreator project forming frmo CLI, e.g.
```
shell> cd <proj-root>
shell> /path/to/CocosCreator.exe --path ./frontend --build "platform=win32;debug=true"
```
### 2.4 CococCreator native build reloading
CocosCreator doesn't have perfect file cache management during native project building, use "Developer Tools > Reload" to reset the IDE status upon mysterious errors.
![ccc_reload](./charts/NativeBuildReload.png)
Another issue is with the package name, see the screenshot below, kindly note that after successfully building with a blank package name, you can then re-fill the desired package name and build again!
![ccc_package_name](./charts/PackageNameIssueInCcc.png)
### 2.5 Checking UDP port binding result
__*nix__
```
netstat -anp | grep <your_port>
```
__Windows__
```
netstat -ano | grep <your_port>
```
### 2.6 Checking native code crash on non-rooted Android phone
```
DeveloperOs> adb bugreport ./logs.zip
# The file "logs.zip" will be automatically pulled to current folder of the DeveloperOS, copy "logs/FS/data/tomestones" out of the zip, then use the binary "$NDK_ROOT/ndk-stack" to analyze whichever tombstone you're interested in, for example, I often use the following
DeveloperOs> ${NDK_ROOT}/ndk-stack.cmd -sym \path\to\DelayNoMore\frontend\build\jsb-link\frameworks\runtime-src\proj.android-studio\app\build\intermediates\ndkBuild\debug\obj\local\arm64-v8a -dump \path\to\tombstones\tombstone_03
# The param "-sym \path\to\objs" tells "ndk-stack" to decode "tombstone_03" with symbols provided by all the files inside that "\path\to\objs".
```

View File

@@ -37,6 +37,8 @@ type mysqlConf struct {
type sioConf struct {
HostAndPort string `json:"hostAndPort"`
UdpHost string `json:"udpHost"`
UdpPort int `json:"udpPort"`
}
type botServerConf struct {

View File

@@ -1,3 +1,5 @@
{
"hostAndPort": "0.0.0.0:9992"
"hostAndPort": "0.0.0.0:9992",
"udpHost": "0.0.0.0",
"udpPort": 3000
}

View File

@@ -23,6 +23,8 @@ import (
"github.com/gin-gonic/gin"
"github.com/robfig/cron"
"go.uber.org/zap"
"net"
)
func main() {
@@ -34,7 +36,7 @@ func main() {
env_tools.MergeTestPlayerAccounts()
}
models.InitRoomHeapManager()
startScheduler()
// startScheduler()
router := gin.Default()
setRouter(router)
@@ -54,6 +56,7 @@ func main() {
}
Logger.Info("Listening and serving HTTP on", zap.Any("Conf.Sio.HostAndPort", Conf.Sio.HostAndPort))
}()
go startGrandUdpServer()
var gracefulStop = make(chan os.Signal)
signal.Notify(gracefulStop, syscall.SIGTERM)
signal.Notify(gracefulStop, syscall.SIGINT)
@@ -89,6 +92,7 @@ func setRouter(router *gin.Engine) {
router.StaticFS("/asset", http.Dir(filepath.Join(Conf.General.AppRoot, "asset")))
router.GET("/ping", f)
router.GET("/tsrht", ws.Serve)
router.GET("/tsrhtSecondary", ws.HandleSecondaryWsSessionForPlayer)
apiRouter := router.Group("/api")
{
@@ -113,3 +117,33 @@ func startScheduler() {
//c.AddFunc("*/1 * * * * *", FuncName)
c.Start()
}
func startGrandUdpServer() {
conn, err := net.ListenUDP("udp", &net.UDPAddr{
Port: Conf.Sio.UdpPort,
IP: net.ParseIP(Conf.Sio.UdpHost),
})
if err != nil {
panic(err)
}
defer func() {
conn.Close()
if r := recover(); r != nil {
Logger.Error("`GrandUdpServer`, recovery spot#1, recovered from: ", zap.Any("panic", r))
}
Logger.Info(fmt.Sprintf("The `GrandUdpServer` is stopped"))
}()
Logger.Info(fmt.Sprintf("`GrandUdpServer` started at %s", conn.LocalAddr().String()))
for {
message := make([]byte, 2046)
rlen, remote, err := conn.ReadFromUDP(message[:])
if err != nil {
panic(err)
}
Logger.Info(fmt.Sprintf("`GrandUdpServer` received: %d bytes from %s\n", rlen, remote))
ws.HandleUdpHolePunchingForPlayer(message[0:rlen], remote)
}
}

View File

@@ -10,67 +10,132 @@ func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame
return nil
}
ret := &pb.RoomDownsyncFrame{
Id: rdf.Id,
PlayersArr: make([]*pb.PlayerDownsync, len(rdf.PlayersArr), len(rdf.PlayersArr)),
MeleeBullets: make([]*pb.MeleeBullet, len(rdf.MeleeBullets), len(rdf.MeleeBullets)),
CountdownNanos: rdf.CountdownNanos,
BackendUnconfirmedMask: rdf.BackendUnconfirmedMask,
ShouldForceResync: rdf.ShouldForceResync,
PlayerOpPatternToSkillId: make(map[int32]int32),
Id: rdf.Id,
PlayersArr: make([]*pb.PlayerDownsync, len(rdf.PlayersArr), len(rdf.PlayersArr)),
BulletLocalIdCounter: rdf.BulletLocalIdCounter,
MeleeBullets: make([]*pb.MeleeBullet, len(rdf.MeleeBullets), len(rdf.MeleeBullets)),
FireballBullets: make([]*pb.FireballBullet, len(rdf.FireballBullets), len(rdf.FireballBullets)),
CountdownNanos: rdf.CountdownNanos,
BackendUnconfirmedMask: rdf.BackendUnconfirmedMask,
ShouldForceResync: rdf.ShouldForceResync,
}
for i, last := range rdf.PlayersArr {
pbPlayer := &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,
FramesToRecover: last.FramesToRecover,
Hp: last.Hp,
MaxHp: last.MaxHp,
Removed: last.Removed,
Id: last.Id,
VirtualGridX: last.VirtualGridX,
VirtualGridY: last.VirtualGridY,
DirX: last.DirX,
DirY: last.DirY,
VelX: last.VelX,
VelY: last.VelY,
FramesToRecover: last.FramesToRecover,
FramesInChState: last.FramesInChState,
ActiveSkillId: last.ActiveSkillId,
ActiveSkillHit: last.ActiveSkillHit,
FramesInvinsible: last.FramesInvinsible,
Speed: last.Speed,
BattleState: last.BattleState,
CharacterState: last.CharacterState,
InAir: last.InAir,
OnWall: last.OnWall,
OnWallNormX: last.OnWallNormX,
OnWallNormY: last.OnWallNormY,
CapturedByInertia: last.CapturedByInertia,
JoinIndex: last.JoinIndex,
BulletTeamId: last.BulletTeamId,
ChCollisionTeamId: last.ChCollisionTeamId,
Hp: last.Hp,
MaxHp: last.MaxHp,
RevivalVirtualGridX: last.RevivalVirtualGridX,
RevivalVirtualGridY: last.RevivalVirtualGridY,
ColliderRadius: last.ColliderRadius,
Score: last.Score,
Removed: last.Removed,
}
ret.PlayersArr[i] = pbPlayer
}
for i, last := range rdf.MeleeBullets {
pbBullet := &pb.MeleeBullet{
BattleLocalId: last.BattleLocalId,
StartupFrames: last.StartupFrames,
ActiveFrames: last.ActiveFrames,
RecoveryFrames: last.RecoveryFrames,
RecoveryFramesOnBlock: last.RecoveryFramesOnBlock,
RecoveryFramesOnHit: last.RecoveryFramesOnHit,
HitboxOffset: last.HitboxOffset,
HitStunFrames: last.HitStunFrames,
BlockStunFrames: last.BlockStunFrames,
Pushback: last.Pushback,
ReleaseTriggerType: last.ReleaseTriggerType,
Damage: last.Damage,
BulletLocalId: last.BattleAttr.BulletLocalId,
OriginatedRenderFrameId: last.BattleAttr.OriginatedRenderFrameId,
OffenderJoinIndex: last.BattleAttr.OffenderJoinIndex,
TeamId: last.BattleAttr.TeamId,
SelfMoveforwardX: last.SelfMoveforwardX,
SelfMoveforwardY: last.SelfMoveforwardY,
HitboxSizeX: last.HitboxSizeX,
HitboxSizeY: last.HitboxSizeY,
StartupFrames: last.Bullet.StartupFrames,
CancellableStFrame: last.Bullet.CancellableStFrame,
CancellableEdFrame: last.Bullet.CancellableEdFrame,
ActiveFrames: last.Bullet.ActiveFrames,
OffenderJoinIndex: last.OffenderJoinIndex,
OffenderPlayerId: last.OffenderPlayerId,
HitStunFrames: last.Bullet.HitStunFrames,
BlockStunFrames: last.Bullet.BlockStunFrames,
PushbackVelX: last.Bullet.PushbackVelX,
PushbackVelY: last.Bullet.PushbackVelY,
Damage: last.Bullet.Damage,
SelfLockVelX: last.Bullet.SelfLockVelX,
SelfLockVelY: last.Bullet.SelfLockVelY,
HitboxOffsetX: last.Bullet.HitboxOffsetX,
HitboxOffsetY: last.Bullet.HitboxOffsetY,
HitboxSizeX: last.Bullet.HitboxSizeX,
HitboxSizeY: last.Bullet.HitboxSizeY,
BlowUp: last.Bullet.BlowUp,
SpeciesId: last.Bullet.SpeciesId,
ExplosionFrames: last.Bullet.ExplosionFrames,
BlState: last.BlState,
FramesInBlState: last.FramesInBlState,
}
ret.MeleeBullets[i] = pbBullet
}
for i, last := range rdf.PlayerOpPatternToSkillId {
ret.PlayerOpPatternToSkillId[int32(i)] = int32(last)
for i, last := range rdf.FireballBullets {
pbBullet := &pb.FireballBullet{
BulletLocalId: last.BattleAttr.BulletLocalId,
OriginatedRenderFrameId: last.BattleAttr.OriginatedRenderFrameId,
OffenderJoinIndex: last.BattleAttr.OffenderJoinIndex,
TeamId: last.BattleAttr.TeamId,
StartupFrames: last.Bullet.StartupFrames,
CancellableStFrame: last.Bullet.CancellableStFrame,
CancellableEdFrame: last.Bullet.CancellableEdFrame,
ActiveFrames: last.Bullet.ActiveFrames,
HitStunFrames: last.Bullet.HitStunFrames,
BlockStunFrames: last.Bullet.BlockStunFrames,
PushbackVelX: last.Bullet.PushbackVelX,
PushbackVelY: last.Bullet.PushbackVelY,
Damage: last.Bullet.Damage,
SelfLockVelX: last.Bullet.SelfLockVelX,
SelfLockVelY: last.Bullet.SelfLockVelY,
HitboxOffsetX: last.Bullet.HitboxOffsetX,
HitboxOffsetY: last.Bullet.HitboxOffsetY,
HitboxSizeX: last.Bullet.HitboxSizeX,
HitboxSizeY: last.Bullet.HitboxSizeY,
BlowUp: last.Bullet.BlowUp,
SpeciesId: last.Bullet.SpeciesId,
ExplosionFrames: last.Bullet.ExplosionFrames,
BlState: last.BlState,
FramesInBlState: last.FramesInBlState,
VirtualGridX: last.VirtualGridX,
VirtualGridY: last.VirtualGridY,
DirX: last.DirX,
DirY: last.DirY,
VelX: last.VelX,
VelY: last.VelY,
Speed: last.Speed,
}
ret.FireballBullets[i] = pbBullet
}
return ret
@@ -84,22 +149,36 @@ func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) []*pb.Play
for _, last := range modelInstances {
pbPlayer := &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,
FramesToRecover: last.FramesToRecover,
Id: last.Id,
VirtualGridX: last.VirtualGridX,
VirtualGridY: last.VirtualGridY,
DirX: last.DirX,
DirY: last.DirY,
VelX: last.VelX,
VelY: last.VelY,
FramesToRecover: last.FramesToRecover,
FramesInChState: last.FramesInChState,
ActiveSkillId: last.ActiveSkillId,
ActiveSkillHit: last.ActiveSkillHit,
FramesInvinsible: last.FramesInvinsible,
Speed: last.Speed,
BattleState: last.BattleState,
CharacterState: last.CharacterState,
InAir: last.InAir,
OnWall: last.OnWall,
OnWallNormX: last.OnWallNormX,
OnWallNormY: last.OnWallNormY,
CapturedByInertia: last.CapturedByInertia,
JoinIndex: last.JoinIndex,
BulletTeamId: last.BulletTeamId,
ChCollisionTeamId: last.ChCollisionTeamId,
Hp: last.Hp,
MaxHp: last.MaxHp,
RevivalVirtualGridX: last.RevivalVirtualGridX,
RevivalVirtualGridY: last.RevivalVirtualGridY,
ColliderRadius: last.ColliderRadius,
Score: last.Score,
Removed: last.Removed,
}
if withMetaInfo {
pbPlayer.Name = last.Name
@@ -120,21 +199,36 @@ func toJsPlayers(modelInstances map[int32]*Player) []*battle.PlayerDownsync {
for _, last := range modelInstances {
toRet[last.JoinIndex-1] = &battle.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,
Id: last.Id,
VirtualGridX: last.VirtualGridX,
VirtualGridY: last.VirtualGridY,
DirX: last.DirX,
DirY: last.DirY,
VelX: last.VelX,
VelY: last.VelY,
FramesToRecover: last.FramesToRecover,
FramesInChState: last.FramesInChState,
ActiveSkillId: last.ActiveSkillId,
ActiveSkillHit: last.ActiveSkillHit,
FramesInvinsible: last.FramesInvinsible,
Speed: last.Speed,
BattleState: last.BattleState,
CharacterState: last.CharacterState,
JoinIndex: last.JoinIndex,
BulletTeamId: last.BulletTeamId,
ChCollisionTeamId: last.ChCollisionTeamId,
Hp: last.Hp,
MaxHp: last.MaxHp,
RevivalVirtualGridX: last.RevivalVirtualGridX,
RevivalVirtualGridY: last.RevivalVirtualGridY,
ColliderRadius: last.ColliderRadius,
InAir: last.InAir,
OnWall: last.OnWall,
OnWallNormX: last.OnWallNormX,
OnWallNormY: last.OnWallNormY,
CapturedByInertia: last.CapturedByInertia,
Score: last.Score,
Removed: last.Removed,
}
}

View File

@@ -8,6 +8,7 @@ import (
sq "github.com/Masterminds/squirrel"
"github.com/jmoiron/sqlx"
"go.uber.org/zap"
"net"
)
type PlayerBattleState struct {
@@ -46,9 +47,15 @@ type Player struct {
TutorialStage int `db:"tutorial_stage"`
// other in-battle info fields
LastSentInputFrameId int32
AckingFrameId int32
AckingInputFrameId int32
LastReceivedInputFrameId int32
LastUdpReceivedInputFrameId int32
LastSentInputFrameId int32
AckingFrameId int32
AckingInputFrameId int32
UdpAddr *PeerUdpAddr
BattleUdpTunnelAddr *net.UDPAddr // This addr is used by backend only, not visible to frontend
BattleUdpTunnelAuthKey int32
}
func ExistPlayerByName(name string) (bool, error) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,7 @@ import (
"github.com/golang/protobuf/proto"
"github.com/gorilla/websocket"
"go.uber.org/zap"
"net"
"net/http"
"strconv"
"sync/atomic"
@@ -46,6 +47,7 @@ func Serve(c *gin.Context) {
c.AbortWithStatus(http.StatusBadRequest)
return
}
boundRoomId := 0
expectedRoomId := 0
var err error
@@ -240,46 +242,40 @@ func Serve(c *gin.Context) {
// Construct "battleColliderInfo" to downsync
bciFrame := &pb.BattleColliderInfo{
BoundRoomId: pRoom.Id,
StageName: pRoom.StageName,
StageDiscreteW: pRoom.StageDiscreteW,
StageDiscreteH: pRoom.StageDiscreteH,
StageTileW: pRoom.StageTileW,
StageTileH: pRoom.StageTileH,
BoundRoomId: pRoom.Id,
StageName: pRoom.StageName,
IntervalToPing: int32(Constants.Ws.IntervalToPing),
WillKickIfInactiveFor: int32(Constants.Ws.WillKickIfInactiveFor),
BattleDurationNanos: pRoom.BattleDurationNanos,
IntervalToPing: int32(Constants.Ws.IntervalToPing),
WillKickIfInactiveFor: int32(Constants.Ws.WillKickIfInactiveFor),
BattleDurationNanos: pRoom.BattleDurationNanos,
ServerFps: pRoom.ServerFps,
InputDelayFrames: pRoom.InputDelayFrames,
InputScaleFrames: pRoom.InputScaleFrames,
NstDelayFrames: pRoom.NstDelayFrames,
InputFrameUpsyncDelayTolerance: pRoom.InputFrameUpsyncDelayTolerance,
MaxChasingRenderFramesPerUpdate: pRoom.MaxChasingRenderFramesPerUpdate,
PlayerBattleState: pThePlayer.BattleState, // For frontend to know whether it's rejoining
RollbackEstimatedDtMillis: pRoom.RollbackEstimatedDtMillis,
RollbackEstimatedDtNanos: pRoom.RollbackEstimatedDtNanos,
WorldToVirtualGridRatio: pRoom.WorldToVirtualGridRatio,
VirtualGridToWorldRatio: pRoom.VirtualGridToWorldRatio,
SpaceOffsetX: pRoom.SpaceOffsetX,
SpaceOffsetY: pRoom.SpaceOffsetY,
SpAtkLookupFrames: pRoom.SpAtkLookupFrames,
RenderCacheSize: pRoom.RenderCacheSize,
SnapIntoPlatformOverlap: pRoom.SnapIntoPlatformOverlap,
SnapIntoPlatformThreshold: pRoom.SnapIntoPlatformThreshold,
JumpingInitVelY: pRoom.JumpingInitVelY,
GravityX: pRoom.GravityX,
GravityY: pRoom.GravityY,
CollisionMinStep: pRoom.CollisionMinStep,
RenderCacheSize: pRoom.RenderCacheSize,
CollisionMinStep: pRoom.CollisionMinStep,
BoundRoomCapacity: int32(pRoom.Capacity),
BattleUdpTunnel: &pb.PeerUdpAddr{
Ip: pRoom.BattleUdpTunnelAddr.Ip,
Port: pRoom.BattleUdpTunnelAddr.Port,
AuthKey: pThePlayer.BattleUdpTunnelAuthKey,
},
FrameDataLoggingEnabled: pRoom.FrameDataLoggingEnabled,
}
resp := &pb.WsResp{
Ret: int32(Constants.RetCode.Ok),
EchoedMsgId: int32(0),
Act: models.DOWNSYNC_MSG_ACT_HB_REQ,
BciFrame: bciFrame,
Ret: int32(Constants.RetCode.Ok),
EchoedMsgId: int32(0),
Act: models.DOWNSYNC_MSG_ACT_HB_REQ,
BciFrame: bciFrame,
PeerJoinIndex: pThePlayer.JoinIndex,
}
Logger.Debug("Sending downsync HeartbeatRequirements:", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("resp", resp))
@@ -392,7 +388,7 @@ func Serve(c *gin.Context) {
startOrFeedHeartbeatWatchdog(conn)
case models.UPSYNC_MSG_ACT_PLAYER_CMD:
startOrFeedHeartbeatWatchdog(conn)
pRoom.OnBattleCmdReceived(pReq)
pRoom.OnBattleCmdReceived(pReq, false)
case models.UPSYNC_MSG_ACT_PLAYER_COLLIDER_ACK:
res := pRoom.OnPlayerBattleColliderAcked(int32(playerId))
if false == res {
@@ -409,3 +405,118 @@ func Serve(c *gin.Context) {
startOrFeedHeartbeatWatchdog(conn)
go receivingLoopAgainstPlayer()
}
func HandleSecondaryWsSessionForPlayer(c *gin.Context) {
token, ok := c.GetQuery("intAuthToken")
if !ok {
Logger.Warn("Secondary ws session req must have intAuthToken param!")
c.AbortWithStatus(http.StatusBadRequest)
return
}
boundRoomId := 0
var err error = nil
if boundRoomIdStr, hasBoundRoomId := c.GetQuery("boundRoomId"); hasBoundRoomId {
boundRoomId, err = strconv.Atoi(boundRoomIdStr)
if err != nil {
c.AbortWithStatus(http.StatusBadRequest)
return
}
} else {
Logger.Warn("Secondary ws session req must have boundRoomId param:", zap.Any("intAuthToken", token))
c.AbortWithStatus(http.StatusBadRequest)
return
}
var pRoom *models.Room = nil
// Deliberately querying playerId after querying room, because the former is against persistent storage and could be slow!
if tmpPRoom, existent := (*models.RoomMapManagerIns)[int32(boundRoomId)]; !existent {
Logger.Warn("Secondary ws session failed to get:\n", zap.Any("intAuthToken", token), zap.Any("forBoundRoomId", boundRoomId))
c.AbortWithStatus(http.StatusBadRequest)
} else {
pRoom = tmpPRoom
}
// TODO: Wrap the following 2 stmts by sql transaction!
playerId, err := models.GetPlayerIdByToken(token)
if err != nil || playerId == 0 {
// TODO: Abort with specific message.
Logger.Warn("Secondary ws session playerLogin record not found:", zap.Any("intAuthToken", token))
c.AbortWithStatus(http.StatusBadRequest)
return
}
Logger.Info("Secondary ws session playerLogin record has been found:", zap.Any("playerId", playerId), zap.Any("intAuthToken", token), zap.Any("boundRoomId", boundRoomId))
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
Logger.Error("Secondary ws session upgrade:", zap.Error(err), zap.Any("playerId", playerId))
c.AbortWithStatus(http.StatusBadRequest)
return
}
connHasBeenSignaledToClose := int32(0)
pConnHasBeenSignaledToClose := &connHasBeenSignaledToClose
signalToCloseConnOfThisPlayer := func(customRetCode int, customRetMsg string) {
if swapped := atomic.CompareAndSwapInt32(pConnHasBeenSignaledToClose, 0, 1); !swapped {
return
}
Logger.Warn("Secondary ws session signalToCloseConnOfThisPlayer:", zap.Any("playerId", playerId), zap.Any("customRetCode", customRetCode), zap.Any("customRetMsg", customRetMsg))
defer func() {
if r := recover(); r != nil {
Logger.Error("Secondary ws session recovered from: ", zap.Any("panic", r))
}
}()
closeMessage := websocket.FormatCloseMessage(customRetCode, customRetMsg)
err := conn.WriteControl(websocket.CloseMessage, closeMessage, time.Now().Add(time.Millisecond*(ConstVals.Ws.WillKickIfInactiveFor)))
if err != nil {
Logger.Error("Secondary ws session unable to send the CloseFrame control message to player(client-side):", zap.Any("playerId", playerId), zap.Error(err))
}
time.AfterFunc(3*time.Second, func() {
// To actually terminates the underlying TCP connection which might be in `CLOSE_WAIT` state if inspected by `netstat`.
conn.Close()
})
}
onReceivedCloseMessageFromClient := func(code int, text string) error {
Logger.Warn("Secondary ws session triggered `onReceivedCloseMessageFromClient`:", zap.Any("code", code), zap.Any("playerId", playerId), zap.Any("message", text))
signalToCloseConnOfThisPlayer(code, text)
return nil
}
conn.SetCloseHandler(onReceivedCloseMessageFromClient)
pRoom.SetSecondarySession(int32(playerId), conn, signalToCloseConnOfThisPlayer)
}
func HandleUdpHolePunchingForPlayer(message []byte, peerAddr *net.UDPAddr) {
pReq := new(pb.HolePunchUpsync)
if unmarshalErr := proto.Unmarshal(message, pReq); nil != unmarshalErr {
Logger.Error("`GrandUdpServer` failed to unmarshal", zap.Error(unmarshalErr))
return
}
token := pReq.IntAuthToken
boundRoomId := pReq.BoundRoomId
pRoom, existent := (*models.RoomMapManagerIns)[int32(boundRoomId)]
// Deliberately querying playerId after querying room, because the former is against persistent storage and could be slow!
if !existent {
Logger.Warn("`GrandUdpServer` failed to get:\n", zap.Any("intAuthToken", token), zap.Any("forBoundRoomId", boundRoomId))
return
}
// TODO: Wrap the following 2 stmts by sql transaction!
playerId, err := models.GetPlayerIdByToken(token)
if err != nil || playerId == 0 {
// TODO: Abort with specific message.
Logger.Warn("`GrandUdpServer` playerLogin record not found for:", zap.Any("intAuthToken", token))
return
}
Logger.Info("`GrandUdpServer` playerLogin record has been found:", zap.Any("playerId", playerId), zap.Any("intAuthToken", token), zap.Any("boundRoomId", boundRoomId), zap.Any("peerAddr", peerAddr))
pRoom.UpdatePeerUdpAddrList(int32(playerId), peerAddr, pReq)
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

View File

@@ -14,3 +14,15 @@ ffmpeg -vsync vfr -i input.gif output%d.png
```
The `-vsync vfr` tells ffmpeg to disrespect the original delays set within the GIF file, otherwise many duplicate frame will be extracted by the default 60FPS.
More complicated transparent padding example (used when alignment in image source is much more preferred than aligning in codes)
```
ffmpeg -vsync vfr -i LayDown1.gif -vf "scale=iw:188:force_original_aspect_ratio=decrease,pad=iw:188:0:(oh-ih):color=#00000000,format=rgba" pngs/LayDown1_%d.png
```
The command above uses same input-output width, but pads the output height with a top transparent section such that the output height is fixed to 188px.
Similarly to crop a gif into pngs.
```
ffmpeg -vsync vfr -i Idle1.gif -vf "crop=70:ih:(iw-ow-10):0" pngs/Idle1_%d.png
```

BIN
charts/ServerClients.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
charts/UDPEssentials.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 MiB

BIN
charts/networkstats.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

View File

@@ -0,0 +1 @@
This module is no longer useful, as we can now use GopherJs+OfflineMap to visualize experimental game dynamics.

View File

@@ -4,8 +4,10 @@ go 1.18
require (
resolv v0.0.0
jsexport v0.0.0
)
replace (
resolv => ../resolv_tailored
jsexport => ../jsexport
)

View File

@@ -1,66 +0,0 @@
function NetworkDoctor(serverFps, clientUpsyncFps) {
this.serverFps = serverFps;
this.clientUpsyncFps = clientUpsyncFps;
this.millisPerServerFrame = parseInt(1000 / this.serverFps);
this._tooLongSinceLastFrameDiffReceivedThreshold = (this.millisPerServerFrame << 6);
this.setupFps = function(fps) {
this.serverFps = this.clientUpsyncFps = fps;
this.millisPerServerFrame = parseInt(1000 / this.serverFps);
this._tooLongSinceLastFrameDiffReceivedThreshold = (this.millisPerServerFrame << 6);
}
this._lastFrameDiffRecvTime = null;
this._tooLongSinceLastFrameDiffReceived = function() {
if (undefined === this._lastFrameDiffRecvTime || null === this._lastFrameDiffRecvTime) return false;
return (this._tooLongSinceLastFrameDiffReceivedThreshold <= (Date.now() - this._lastFrameDiffRecvTime));
};
this._consecutiveALittleLongFrameDiffReceivedIntervalCount = 0;
this._consecutiveALittleLongFrameDiffReceivedIntervalCountThreshold = 120;
this.onNewFrameDiffReceived = function(frameDiff) {
var now = Date.now();
if (undefined !== this._lastFrameDiffRecvTime && null !== this._lastFrameDiffRecvTime) {
var intervalFromLastFrameDiff = (now - this._lastFrameDiffRecvTime);
if ((this.millisPerServerFrame << 5) < intervalFromLastFrameDiff) {
++this._consecutiveALittleLongFrameDiffReceivedIntervalCount;
console.log('Medium delay, intervalFromLastFrameDiff is', intervalFromLastFrameDiff);
} else {
this._consecutiveALittleLongFrameDiffReceivedIntervalCount = 0;
}
}
this._lastFrameDiffRecvTime = now;
};
this._networkComplaintPrefix = "\nNetwork is not good >_<\n";
this.generateNetworkComplaint = function(excludeTypeConstantALittleLongFrameDiffReceivedInterval, excludeTypeTooLongSinceLastFrameDiffReceived) {
if (this.hasBattleStopped) return null;
var shouldComplain = false;
var ret = this._networkComplaintPrefix;
if (true != excludeTypeConstantALittleLongFrameDiffReceivedInterval && this._consecutiveALittleLongFrameDiffReceivedIntervalCountThreshold <= this._consecutiveALittleLongFrameDiffReceivedIntervalCount) {
this._consecutiveALittleLongFrameDiffReceivedIntervalCount = 0;
ret += "\nConstantly having a little long recv interval.\n";
shouldComplain = true;
}
if (true != excludeTypeTooLongSinceLastFrameDiffReceived && this._tooLongSinceLastFrameDiffReceived()) {
ret += "\nToo long since last received frameDiff.\n";
shouldComplain = true;
}
return (shouldComplain ? ret : null);
};
this.hasBattleStopped = false;
this.onBattleStopped = function() {
this.hasBattleStopped = true;
};
this.isClientSessionConnected = function() {
if (!window.game) return false;
if (!window.game.clientSession) return false;
return window.game.clientSession.connected;
};
}
window.NetworkDoctor = NetworkDoctor;

View File

@@ -198,3 +198,6 @@ window.getOrCreateAnimationClipForGid = function(gid, tiledMapInfo, tilesElListU
animationClip: animClip,
};
};
// Node.js, this is a workaround to avoid accessing the non-existent "TextDecoder class" from "jsexport.js".
window.fs = function() {};

View File

@@ -0,0 +1,7 @@
{
"ver": "1.0.1",
"uuid": "c7c2ac6e-f1ea-4233-b6a4-aa5b96b61e17",
"isSubpackage": false,
"subpackageName": "",
"subMetas": {}
}

View File

@@ -0,0 +1,55 @@
{
"__type__": "cc.AnimationClip",
"_name": "Fireball1Explosion",
"_objFlags": 0,
"_native": "",
"_duration": 0.5,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "f4ad4f9f-4890-450b-9334-68fe6b903893"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "c6a5994f-251d-4191-a550-dfef979bab59"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "417e58d9-e364-47f7-9364-f31ad3452adc"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "8b566f26-b34d-4da6-bdaa-078358a5b685"
}
},
{
"frame": 0.31666666666666665,
"value": {
"__uuid__": "6ec5f75d-307e-4292-b667-cbbb5a52c2f6"
}
},
{
"frame": 0.48333333333333334,
"value": {
"__uuid__": "d89977f1-d927-4a08-9591-9feb1daf68c8"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "7941215a-2b8c-4798-954b-4f1b16d5f6f5",
"subMetas": {}
}

View File

@@ -0,0 +1,85 @@
{
"__type__": "cc.AnimationClip",
"_name": "Fireball2Explosion",
"_objFlags": 0,
"_native": "",
"_duration": 0.5,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "a1979f05-3ecc-4d70-9ea9-7822e35602c3"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "850884ca-2e6a-4d04-94d9-fd929ac33942"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "88b9c254-1fd8-451f-902e-4a43a7ef5d51"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "566342a3-cfde-44c9-afbe-7d9469653ccb"
}
},
{
"frame": 0.18333333333333332,
"value": {
"__uuid__": "d1620a98-de62-4069-8910-122f361d22a4"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "2e9ed070-e592-4e77-8fa1-c5250deb006b"
}
},
{
"frame": 0.2833333333333333,
"value": {
"__uuid__": "a3e8357d-39da-42e8-b26b-f5ae7a68aed7"
}
},
{
"frame": 0.3333333333333333,
"value": {
"__uuid__": "3f3cb45c-732d-4bea-89b4-5495fb0d2c37"
}
},
{
"frame": 0.38333333333333336,
"value": {
"__uuid__": "d7aeb01a-4e04-4037-a2c4-ba72f45f69f3"
}
},
{
"frame": 0.43333333333333335,
"value": {
"__uuid__": "fe4a97a0-1207-4b81-a541-c2da0bf0a6f3"
}
},
{
"frame": 0.48333333333333334,
"value": {
"__uuid__": "97014ab9-8bdd-4b71-9f61-0639327f9159"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "14b92f5c-af81-416a-a162-e5822d20fe68",
"subMetas": {}
}

View File

@@ -0,0 +1,79 @@
{
"__type__": "cc.AnimationClip",
"_name": "Fireball3Explosion",
"_objFlags": 0,
"_native": "",
"_duration": 0.5,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "0e003318-f8c2-40f7-b144-140b5ca1e46a"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "9c2b0cc2-9a52-4052-b796-cd6c6bd940d4"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "76fe0c09-d2d6-432d-bacb-20d297eb4966"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "0735a7ff-0e50-472a-b0f9-8e2cc97be7e7"
}
},
{
"frame": 0.2833333333333333,
"value": {
"__uuid__": "993199a8-54a9-40d1-8d2f-12bf16af934c"
}
},
{
"frame": 0.35,
"value": {
"__uuid__": "5d8d9ffc-b4d6-4518-9946-953929ec055c"
}
},
{
"frame": 0.38333333333333336,
"value": {
"__uuid__": "6501ae08-b0ff-43ad-b5c5-cb6dc67f989d"
}
},
{
"frame": 0.4166666666666667,
"value": {
"__uuid__": "616cfa00-1dba-4a71-8141-36774933b6a9"
}
},
{
"frame": 0.45,
"value": {
"__uuid__": "4b296e86-2e96-4276-b6de-6a6b22530344"
}
},
{
"frame": 0.48333333333333334,
"value": {
"__uuid__": "f9cc8e37-c9c2-4f20-9d7e-4533c4e859fe"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "0dbb90ed-a08a-448c-b06e-4831260e9213",
"subMetas": {}
}

View File

@@ -0,0 +1,79 @@
{
"__type__": "cc.AnimationClip",
"_name": "MeleeExplosion1",
"_objFlags": 0,
"_native": "",
"_duration": 0.16666666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "ab4866e8-ce52-4bc1-be19-b03687acf0d6"
}
},
{
"frame": 0.016666666666666666,
"value": {
"__uuid__": "67cc8a51-0ebe-49db-a941-7aabc5655ecf"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "367592d0-3566-4b6a-8707-01d6a8dbe34a"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "cc336b1e-b5d8-4a89-96fc-7ada0e232389"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "a457cc63-08bd-4cfa-b84a-7287d0343ecf"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "89697d35-cde3-4392-a231-db91d4ede29b"
}
},
{
"frame": 0.1,
"value": {
"__uuid__": "3815bf7a-0a48-40e0-b791-0a0be9ec0da6"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "20e691ee-a0c0-4710-8981-8dee1911e819"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "94e678c5-0780-4f2b-bf3b-86c6c0a75c23"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "af4f9c62-4c7e-43a4-b9b3-dd3effbbbafb"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "954a2924-89df-4df4-93fc-36d2b22e7619",
"subMetas": {}
}

View File

@@ -0,0 +1,79 @@
{
"__type__": "cc.AnimationClip",
"_name": "MeleeExplosion2",
"_objFlags": 0,
"_native": "",
"_duration": 0.26666666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "89e54317-7835-4d4c-9c04-579da8b33c54"
}
},
{
"frame": 0.016666666666666666,
"value": {
"__uuid__": "2a186e00-a0c5-4c8a-b0ab-c84d56dcee7c"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "083168e3-6ccc-4c5b-a800-2554bffc67d4"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "d4b12ec9-6f04-493c-91e5-22b1a212262a"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "13038788-b0f9-4714-960b-c98619a0d0ce"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "94c21ed7-94a2-47a4-9537-fe5d9c51d7b0"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "d5340298-923c-4bd7-9fd7-7a2e029a2b44"
}
},
{
"frame": 0.21666666666666667,
"value": {
"__uuid__": "c4b145c0-0145-4e09-8559-9ef508d95be8"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "79398d4d-305e-4987-b199-d9d9649cf490"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "c032eb65-fdf3-41e6-b868-d95df34168df"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "5bd304eb-c8ba-426f-a9ab-5698ac62de85",
"subMetas": {}
}

View File

@@ -0,0 +1,79 @@
{
"__type__": "cc.AnimationClip",
"_name": "MeleeExplosion3",
"_objFlags": 0,
"_native": "",
"_duration": 0.26666666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "20d9ce6b-d9ab-4402-8c59-770ad0adf570"
}
},
{
"frame": 0.016666666666666666,
"value": {
"__uuid__": "0654601f-6788-4a2c-aed4-8dfbe1c5fdd0"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "0913e11a-c796-4b58-94cf-f70b3869deff"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "d6b58622-2cc3-4ee6-a34f-1a18deb73700"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "b83c6261-b86f-4323-ad11-7375cac02a2b"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "b458c047-b7b5-4476-996e-d4c1ca85ef9c"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "3971256a-8120-448e-8adf-de8d67dedfd3"
}
},
{
"frame": 0.18333333333333332,
"value": {
"__uuid__": "0e548d92-36c8-4795-b3dc-2bc2cfcd7170"
}
},
{
"frame": 0.21666666666666667,
"value": {
"__uuid__": "25f94245-87b0-4954-abab-c817c80fed37"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "20d9ce6b-d9ab-4402-8c59-770ad0adf570"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "5054633c-a588-4506-b4ac-eef29b1d8511",
"subMetas": {}
}

View File

@@ -0,0 +1,476 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>frames</key>
<dict>
<key>Explosion1_1.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{0,506},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_10.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{0,577},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_2.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{67,506},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_3.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{67,577},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_4.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{134,506},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_5.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{134,577},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_6.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{355,503},{71,67}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion1_7.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{426,503},{71,67}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion1_8.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{355,570},{71,67}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion1_9.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{71,67}</string>
<key>spriteSourceSize</key>
<string>{71,67}</string>
<key>textureRect</key>
<string>{{422,570},{71,67}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion2_1.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{462,0},{88,45}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion2_10.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{462,88},{88,45}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion2_2.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{462,176},{88,45}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion2_3.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{462,264},{88,45}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion2_4.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{0,304},{88,45}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion2_5.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{88,304},{88,45}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion2_6.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{176,304},{88,45}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion2_7.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{264,304},{88,45}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion2_8.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{352,304},{88,45}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion2_9.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{88,45}</string>
<key>spriteSourceSize</key>
<string>{88,45}</string>
<key>textureRect</key>
<string>{{456,352},{88,45}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion3_1.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{0,0},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_10.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{154,0},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_2.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{308,0},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_3.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{0,152},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_4.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{154,152},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_5.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{308,152},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_6.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{0,352},{154,152}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion3_7.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{152,349},{154,152}}</string>
<key>textureRotated</key>
<true/>
</dict>
<key>Explosion3_8.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{201,503},{154,152}}</string>
<key>textureRotated</key>
<false/>
</dict>
<key>Explosion3_9.png</key>
<dict>
<key>aliases</key>
<array/>
<key>spriteOffset</key>
<string>{0,0}</string>
<key>spriteSize</key>
<string>{154,152}</string>
<key>spriteSourceSize</key>
<string>{154,152}</string>
<key>textureRect</key>
<string>{{304,349},{154,152}}</string>
<key>textureRotated</key>
<true/>
</dict>
</dict>
<key>metadata</key>
<dict>
<key>format</key>
<integer>3</integer>
<key>pixelFormat</key>
<string>RGBA8888</string>
<key>premultiplyAlpha</key>
<false/>
<key>realTextureFileName</key>
<string>MeleeExplosions.png</string>
<key>size</key>
<string>{507,655}</string>
<key>smartupdate</key>
<string>$TexturePacker:SmartUpdate:6c1498ee6f30bdad4abeb6a9f6af8367:4c81e1a1720f2ad3535ac93f1b42991f:d9b184ec81b83b14db5cf31d298727df$</string>
<key>textureFileName</key>
<string>MeleeExplosions.png</string>
</dict>
</dict>
</plist>

View File

@@ -0,0 +1,672 @@
{
"ver": "1.2.4",
"uuid": "1c4c1dcb-54af-485b-9119-abd6d6d84526",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"size": {
"width": 507,
"height": 655
},
"type": "Texture Packer",
"subMetas": {
"Explosion1_1.png": {
"ver": "1.0.4",
"uuid": "ab4866e8-ce52-4bc1-be19-b03687acf0d6",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 506,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_10.png": {
"ver": "1.0.4",
"uuid": "af4f9c62-4c7e-43a4-b9b3-dd3effbbbafb",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 577,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_2.png": {
"ver": "1.0.4",
"uuid": "67cc8a51-0ebe-49db-a941-7aabc5655ecf",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 67,
"trimY": 506,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_3.png": {
"ver": "1.0.4",
"uuid": "367592d0-3566-4b6a-8707-01d6a8dbe34a",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 67,
"trimY": 577,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_4.png": {
"ver": "1.0.4",
"uuid": "cc336b1e-b5d8-4a89-96fc-7ada0e232389",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 134,
"trimY": 506,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_5.png": {
"ver": "1.0.4",
"uuid": "a457cc63-08bd-4cfa-b84a-7287d0343ecf",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 134,
"trimY": 577,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_6.png": {
"ver": "1.0.4",
"uuid": "89697d35-cde3-4392-a231-db91d4ede29b",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 355,
"trimY": 503,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_7.png": {
"ver": "1.0.4",
"uuid": "3815bf7a-0a48-40e0-b791-0a0be9ec0da6",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 426,
"trimY": 503,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_8.png": {
"ver": "1.0.4",
"uuid": "20e691ee-a0c0-4710-8981-8dee1911e819",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 355,
"trimY": 570,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion1_9.png": {
"ver": "1.0.4",
"uuid": "94e678c5-0780-4f2b-bf3b-86c6c0a75c23",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 422,
"trimY": 570,
"width": 71,
"height": 67,
"rawWidth": 71,
"rawHeight": 67,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_1.png": {
"ver": "1.0.4",
"uuid": "89e54317-7835-4d4c-9c04-579da8b33c54",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 462,
"trimY": 0,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_10.png": {
"ver": "1.0.4",
"uuid": "c032eb65-fdf3-41e6-b868-d95df34168df",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 462,
"trimY": 88,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_2.png": {
"ver": "1.0.4",
"uuid": "2a186e00-a0c5-4c8a-b0ab-c84d56dcee7c",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 462,
"trimY": 176,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_3.png": {
"ver": "1.0.4",
"uuid": "083168e3-6ccc-4c5b-a800-2554bffc67d4",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 462,
"trimY": 264,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_4.png": {
"ver": "1.0.4",
"uuid": "d4b12ec9-6f04-493c-91e5-22b1a212262a",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 304,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_5.png": {
"ver": "1.0.4",
"uuid": "13038788-b0f9-4714-960b-c98619a0d0ce",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 88,
"trimY": 304,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_6.png": {
"ver": "1.0.4",
"uuid": "94c21ed7-94a2-47a4-9537-fe5d9c51d7b0",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 176,
"trimY": 304,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_7.png": {
"ver": "1.0.4",
"uuid": "d5340298-923c-4bd7-9fd7-7a2e029a2b44",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 264,
"trimY": 304,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_8.png": {
"ver": "1.0.4",
"uuid": "c4b145c0-0145-4e09-8559-9ef508d95be8",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 352,
"trimY": 304,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion2_9.png": {
"ver": "1.0.4",
"uuid": "79398d4d-305e-4987-b199-d9d9649cf490",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 456,
"trimY": 352,
"width": 88,
"height": 45,
"rawWidth": 88,
"rawHeight": 45,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_1.png": {
"ver": "1.0.4",
"uuid": "84e28787-c6cb-435b-8f59-20d9afe6bf3a",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_10.png": {
"ver": "1.0.4",
"uuid": "20d9ce6b-d9ab-4402-8c59-770ad0adf570",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 154,
"trimY": 0,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_2.png": {
"ver": "1.0.4",
"uuid": "0654601f-6788-4a2c-aed4-8dfbe1c5fdd0",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 308,
"trimY": 0,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_3.png": {
"ver": "1.0.4",
"uuid": "0913e11a-c796-4b58-94cf-f70b3869deff",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 152,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_4.png": {
"ver": "1.0.4",
"uuid": "d6b58622-2cc3-4ee6-a34f-1a18deb73700",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 154,
"trimY": 152,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_5.png": {
"ver": "1.0.4",
"uuid": "b83c6261-b86f-4323-ad11-7375cac02a2b",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 308,
"trimY": 152,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_6.png": {
"ver": "1.0.4",
"uuid": "b458c047-b7b5-4476-996e-d4c1ca85ef9c",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 352,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_7.png": {
"ver": "1.0.4",
"uuid": "3971256a-8120-448e-8adf-de8d67dedfd3",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 152,
"trimY": 349,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_8.png": {
"ver": "1.0.4",
"uuid": "0e548d92-36c8-4795-b3dc-2bc2cfcd7170",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 201,
"trimY": 503,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
},
"Explosion3_9.png": {
"ver": "1.0.4",
"uuid": "25f94245-87b0-4954-abab-c817c80fed37",
"rawTextureUuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"trimType": "auto",
"trimThreshold": 1,
"rotated": true,
"offsetX": 0,
"offsetY": 0,
"trimX": 304,
"trimY": 349,
"width": 154,
"height": 152,
"rawWidth": 154,
"rawHeight": 152,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"spriteType": "normal",
"subMetas": {}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,12 @@
{
"ver": "2.3.3",
"uuid": "b11569aa-2e43-4084-a3e5-42eec243c4eb",
"type": "raw",
"wrapMode": "clamp",
"filterMode": "bilinear",
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"platformSettings": {},
"subMetas": {}
}

View File

@@ -0,0 +1,7 @@
{
"ver": "1.0.1",
"uuid": "b07a911d-2d61-486d-9edc-1b3ba53c9911",
"isSubpackage": false,
"subpackageName": "",
"subMetas": {}
}

View File

@@ -0,0 +1,145 @@
{
"__type__": "cc.AnimationClip",
"_name": "Fireball1",
"_objFlags": 0,
"_native": "",
"_duration": 0.35,
"sample": 60,
"speed": 1,
"wrapMode": 2,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "dbe67025-9878-4e13-8f3d-81e04734810a"
}
},
{
"frame": 0.016666666666666666,
"value": {
"__uuid__": "e92702d5-d5fd-49e6-ab6b-2296b43fa6d6"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "e1a89340-0b92-4e6b-93f2-e983302d70ce"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "b0bb4a7a-4ae3-48fc-9913-3b6d1d36c56f"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "b44d585b-8e18-4767-b263-ed3a53cd3250"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "a87a9ea8-2d84-4a3b-83e3-a4d7b8ac96b8"
}
},
{
"frame": 0.1,
"value": {
"__uuid__": "a1604f9d-c0ea-4f92-b09b-3608245bda8e"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "4372818f-1e44-4180-a0ce-4a34cee4fc5b"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "dbe67025-9878-4e13-8f3d-81e04734810a"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "5d867617-7f50-4fa8-804d-ce28c47ea407"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "824c9bee-42b7-4a94-86f8-6356f11aee16"
}
},
{
"frame": 0.18333333333333332,
"value": {
"__uuid__": "6389164e-93bb-4d4d-9740-5e2d5cdb1029"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "d184a083-6043-4ca6-bd14-8db1b6be1d2e"
}
},
{
"frame": 0.21666666666666667,
"value": {
"__uuid__": "361b1722-e362-46e5-939e-e2d1666df374"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "662fbe4f-a1f4-46f7-83e4-eafd021432da"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "5e509118-a44b-4e7f-9686-c6bb0b30f0b0"
}
},
{
"frame": 0.26666666666666666,
"value": {
"__uuid__": "bc1110c7-4423-4c43-965c-0cb3dd8e31ff"
}
},
{
"frame": 0.2833333333333333,
"value": {
"__uuid__": "33cc8d11-1568-47a7-b4f1-cef4888302e5"
}
},
{
"frame": 0.3,
"value": {
"__uuid__": "83bb5dd3-510c-4fce-b393-840f14efb8cd"
}
},
{
"frame": 0.31666666666666665,
"value": {
"__uuid__": "1db706f5-366a-421c-843f-a4bb016f80ec"
}
},
{
"frame": 0.3333333333333333,
"value": {
"__uuid__": "41a4f35a-01c0-4a22-b5cc-7bfe25ed4501"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "ba12416b-eec3-4260-8402-7fc25b125624",
"subMetas": {}
}

View File

@@ -0,0 +1,97 @@
{
"__type__": "cc.AnimationClip",
"_name": "Fireball2",
"_objFlags": 0,
"_native": "",
"_duration": 0.21666666666666667,
"sample": 60,
"speed": 1,
"wrapMode": 2,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "db4c7e6f-9bee-4e7a-8628-d41b8bcaff42"
}
},
{
"frame": 0.016666666666666666,
"value": {
"__uuid__": "42796576-72b3-49c2-8c5a-ea946fbe1525"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "0aa5a52f-a92a-4a4a-b49b-aee2b5a3eb55"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "0a7b5e41-acdc-4af3-beff-0a42aca9f91a"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "de0b22b7-65ca-455f-bcd1-2ddd6cc114e2"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "e9ce1383-9e3d-4d44-9f80-ab5fa2224138"
}
},
{
"frame": 0.1,
"value": {
"__uuid__": "5b22df7e-414b-44a3-989f-640c5b9417b9"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "f459615c-70a4-421b-b649-a28460332364"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "c2723b9d-fbd8-4524-a0dd-b110451e4e32"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "4286b3d1-fea2-41fd-8829-7635f546def4"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "4e0d6419-62df-4382-893e-dd7cc47f7770"
}
},
{
"frame": 0.18333333333333332,
"value": {
"__uuid__": "f0cd9259-b323-4fba-ad8b-02d5e56c2cd4"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "0193b66d-06bb-49f9-b2f5-51fff8b16015"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "d2c65ac4-a5b3-411e-8d2d-18d3980649d7",
"subMetas": {}
}

View File

@@ -0,0 +1,73 @@
{
"__type__": "cc.AnimationClip",
"_name": "Fireball3",
"_objFlags": 0,
"_native": "",
"_duration": 0.5666666666666667,
"sample": 60,
"speed": 1,
"wrapMode": 2,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "6af65d40-470c-47de-8b3d-f53c3923bf90"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "ebf64819-79a5-4366-bf70-08f3b1c6114c"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "e03d879b-5227-4c11-a4b9-0a426967d28a"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "a1aa0c83-4a34-43ae-9a8f-56189808df68"
}
},
{
"frame": 0.26666666666666666,
"value": {
"__uuid__": "3cc28dd0-2518-4162-a39d-4e4b19f9d60b"
}
},
{
"frame": 0.35,
"value": {
"__uuid__": "1b41f500-c55b-4cbf-a040-287b6cc0e958"
}
},
{
"frame": 0.43333333333333335,
"value": {
"__uuid__": "cfa24c51-0ad4-4e3b-b571-c5500002d6e9"
}
},
{
"frame": 0.5,
"value": {
"__uuid__": "d4a46a6a-401c-4694-a192-0a7b3ce6f603"
}
},
{
"frame": 0.55,
"value": {
"__uuid__": "c88c5293-9f21-4a1a-a6b6-649e403dc7a2"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "6aef5812-d16c-4da1-96a3-a38ac227c823",
"subMetas": {}
}

View File

@@ -0,0 +1,7 @@
{
"ver": "1.0.1",
"uuid": "15043c55-01a9-408c-b985-910c5de144c7",
"isSubpackage": false,
"subpackageName": "",
"subMetas": {}
}

View File

@@ -0,0 +1,91 @@
{
"__type__": "cc.AnimationClip",
"_name": "Atk1",
"_objFlags": 0,
"_native": "",
"_duration": 0.6,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "6b2a1a09-8236-4972-8aee-1781b6547d4e"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "5b269b2e-0800-4bf5-b5db-055b78cf318d"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "e184f831-3f90-47cb-8ca5-ad9446ba0398"
}
},
{
"frame": 0.18333333333333332,
"value": {
"__uuid__": "f260f82b-10cf-49af-b46c-cd8dc7a3503f"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "09f43e75-0986-4b8f-907b-e5a5a73b7c54"
}
},
{
"frame": 0.2833333333333333,
"value": {
"__uuid__": "d7432402-fcbd-4e2e-b2c1-33364f31948b"
}
},
{
"frame": 0.3333333333333333,
"value": {
"__uuid__": "8acf1c5a-6910-47d6-aa18-1e6f07546d7a"
}
},
{
"frame": 0.38333333333333336,
"value": {
"__uuid__": "76120dbd-6390-4706-9580-dcec9687e83e"
}
},
{
"frame": 0.43333333333333335,
"value": {
"__uuid__": "f9a7a04a-2369-4946-8313-c2da896da51e"
}
},
{
"frame": 0.48333333333333334,
"value": {
"__uuid__": "c8fb14e2-745e-4a2b-b235-d43195052652"
}
},
{
"frame": 0.5333333333333333,
"value": {
"__uuid__": "1f23e0e5-830c-4d07-8f80-cbb98a2a1954"
}
},
{
"frame": 0.5833333333333334,
"value": {
"__uuid__": "4c512398-4290-4fdf-bb21-2b0062a9071b"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "829b17c6-9365-4e97-b14f-fa266bd5ecbe",
"subMetas": {}
}

View File

@@ -0,0 +1,73 @@
{
"__type__": "cc.AnimationClip",
"_name": "Atk2",
"_objFlags": 0,
"_native": "",
"_duration": 1.0166666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "60f9f7d4-5cf7-4098-9455-0f6a74963fc6"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "dd9a00aa-ddbc-4b01-a7cb-3c43c3a655b6"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "e80d3a01-5048-42b7-a280-cb6aa01602c2"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "d899088c-be62-47b4-9ebf-0a89a2261565"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "5b1e5aa7-fd82-47ae-a5b2-6d4983d848ed"
}
},
{
"frame": 0.18333333333333332,
"value": {
"__uuid__": "c2945988-b4bb-4583-a5ef-2fa02b23a347"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "070ea1e3-9c07-4735-8b94-515ef70216ad"
}
},
{
"frame": 0.2833333333333333,
"value": {
"__uuid__": "3b8bc5c0-26df-4218-b7dc-134a36080a35"
}
},
{
"frame": 1,
"value": {
"__uuid__": "3898259f-a3b0-490d-b260-f86ab5109dfe"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "52b8e47d-715c-4c12-a2c9-6f553e14dc42",
"subMetas": {}
}

View File

@@ -0,0 +1,79 @@
{
"__type__": "cc.AnimationClip",
"_name": "Atk3",
"_objFlags": 0,
"_native": "",
"_duration": 1.0166666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "51ab185b-2271-48b5-a897-af79721d566c"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "c29fd95d-7467-4138-9e01-6421af63dd68"
}
},
{
"frame": 0.1,
"value": {
"__uuid__": "3285b5eb-c6be-4cb9-ac60-c506645fee4b"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "13fd4a87-71f4-4b69-a5b3-413d564c35e6"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "7189e229-00d6-427a-8ea1-d05fbd97824f"
}
},
{
"frame": 0.45,
"value": {
"__uuid__": "d9ccfe33-3db7-4b3a-807c-adb2121fb7c7"
}
},
{
"frame": 0.6833333333333333,
"value": {
"__uuid__": "a51cbc29-0826-46f7-a38b-8b0f996fbace"
}
},
{
"frame": 0.8833333333333333,
"value": {
"__uuid__": "7e9f3a24-6abc-4b49-a5c5-a0c100865ffc"
}
},
{
"frame": 0.95,
"value": {
"__uuid__": "ecbaeb43-1118-483a-91c9-ff1ff01b7b33"
}
},
{
"frame": 1,
"value": {
"__uuid__": "58afa365-a916-4ec6-aab3-1c87f5332b12"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "9b500cb0-8048-4715-81db-cc975c914225",
"subMetas": {}
}

View File

@@ -0,0 +1,73 @@
{
"__type__": "cc.AnimationClip",
"_name": "Atk4",
"_objFlags": 0,
"_native": "",
"_duration": 1.0166666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "da597a30-22da-4053-b4ee-1cfa27980a75"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "b3604b4c-426f-4843-bb76-f09a9687950d"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "24b51487-6c91-42d9-bd12-afbbf70f2e4b"
}
},
{
"frame": 0.2833333333333333,
"value": {
"__uuid__": "c318ad71-7a5e-43b0-8098-b7a34a6e6fbe"
}
},
{
"frame": 0.38333333333333336,
"value": {
"__uuid__": "85d6d8d7-81cf-4369-a501-6ad72d70f5a2"
}
},
{
"frame": 0.5,
"value": {
"__uuid__": "42b76eaf-db36-4835-9072-893337c83425"
}
},
{
"frame": 0.6,
"value": {
"__uuid__": "152f23a1-f70f-4db6-bb28-68625aef930f"
}
},
{
"frame": 0.8833333333333333,
"value": {
"__uuid__": "9c907eb5-84ab-4fa9-9404-9085f29706cc"
}
},
{
"frame": 1,
"value": {
"__uuid__": "74f0ffc8-cc25-4fcf-a6d8-bf093daba9ca"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "2aef91f9-ef47-4bb4-bf43-5441723aa639",
"subMetas": {}
}

View File

@@ -0,0 +1,43 @@
{
"__type__": "cc.AnimationClip",
"_name": "Atked1",
"_objFlags": 0,
"_native": "",
"_duration": 0.26666666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "9b90ae89-7fbe-4bb6-ab15-fc08462f54c5"
}
},
{
"frame": 0.1,
"value": {
"__uuid__": "aeb3553a-6de4-4197-9f06-d7cc3fa7c4cf"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "07650461-a7c0-4638-92fc-fa436752c045"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "ca22d473-83aa-4146-b732-89d0246a2968"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "2a50c853-000b-46f3-ae59-1dfb793de814",
"subMetas": {}
}

View File

@@ -0,0 +1,43 @@
{
"__type__": "cc.AnimationClip",
"_name": "BlownUp1",
"_objFlags": 0,
"_native": "",
"_duration": 0.4166666666666667,
"sample": 60,
"speed": 1,
"wrapMode": 2,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "0ea84f61-4a2f-4ca2-a0b8-b580e027c142"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "a3a31fcd-a162-456a-9c26-1f32413f87f3"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "da4ee0a0-ba66-455c-99d3-9c803a3d0f17"
}
},
{
"frame": 0.4,
"value": {
"__uuid__": "4c058d60-e727-4438-b058-6e51969df458"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "0892a3ea-9da1-4157-825b-0c8ef1c73eeb",
"subMetas": {}
}

View File

@@ -0,0 +1,61 @@
{
"__type__": "cc.AnimationClip",
"_name": "Dashing",
"_objFlags": 0,
"_native": "",
"_duration": 0.35,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "cf396dac-50c9-4389-90c0-55f49fd3276d"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "b9e4b5d5-c296-48c8-aa60-d22db0e5a632"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "e456c710-69f5-4dcc-9f5d-dd486a9198a1"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "ec6df76f-0004-4216-9b83-449487fe0cda"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "26032d0f-845c-4b96-89a6-d88113ed7827"
}
},
{
"frame": 0.2833333333333333,
"value": {
"__uuid__": "e3e0169c-3c56-4206-a20e-35e4d0471873"
}
},
{
"frame": 0.3333333333333333,
"value": {
"__uuid__": "80b98036-c5de-492b-b0e8-f1703f3a7d20"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "38b2c892-347b-4009-93f8-65b2ab1614f0",
"subMetas": {}
}

View File

@@ -0,0 +1,103 @@
{
"__type__": "cc.AnimationClip",
"_name": "Dying",
"_objFlags": 0,
"_native": "",
"_duration": 0.5333333333333333,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "700f93f9-ef84-4cb2-b759-f39ceac1c1d1"
}
},
{
"frame": 0.016666666666666666,
"value": {
"__uuid__": "5b4ea047-594e-4d0b-8e08-e24117bf1e67"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "a822576c-d2eb-4c17-8969-03dd1da5a93e"
}
},
{
"frame": 0.1,
"value": {
"__uuid__": "85e92afc-4359-4a8d-bdfa-958a6134cd6a"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "88d6e560-1b65-4d78-949c-cbc0e67d33cc"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "9ac16319-c1af-41d1-910b-99cbfd6230b2"
}
},
{
"frame": 0.23333333333333334,
"value": {
"__uuid__": "2a6b168a-458f-4d19-a985-9b00cc6e37e8"
}
},
{
"frame": 0.26666666666666666,
"value": {
"__uuid__": "f8482295-dc0d-4265-be56-0b0a9f6f6b9b"
}
},
{
"frame": 0.31666666666666665,
"value": {
"__uuid__": "0d4a314c-119a-46b9-8dce-dbaacf2523e5"
}
},
{
"frame": 0.36666666666666664,
"value": {
"__uuid__": "18d4ff6c-6b57-461b-8588-03521fafc9d1"
}
},
{
"frame": 0.4,
"value": {
"__uuid__": "f25280f2-442a-4ad7-914e-0f96cbf108f5"
}
},
{
"frame": 0.45,
"value": {
"__uuid__": "ccccb669-d44d-4a5c-89a1-9aba9476ce12"
}
},
{
"frame": 0.48333333333333334,
"value": {
"__uuid__": "4a45c23d-7bc8-4c5e-b761-ac1100b12a09"
}
},
{
"frame": 0.5166666666666667,
"value": {
"__uuid__": "1c4359c5-b303-403d-82ad-8d5e6ae6ec99"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "ac90c9b8-3b06-4866-89ce-2c953a9d5a9a",
"subMetas": {}
}

View File

@@ -0,0 +1,61 @@
{
"__type__": "cc.AnimationClip",
"_name": "GetUp1",
"_objFlags": 0,
"_native": "",
"_duration": 0.5166666666666667,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "3f26b0a4-db13-4a14-b885-5a812073eccf"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "23eb42d6-52a2-458d-98a3-2f692dd79398"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "7bd4428c-44f9-4ff8-8d00-d3448a27a0c4"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "57640cd8-17eb-4279-a118-1ea40174da3c"
}
},
{
"frame": 0.35,
"value": {
"__uuid__": "56a2c954-6d04-433c-8ae4-f1bc7a0e9469"
}
},
{
"frame": 0.43333333333333335,
"value": {
"__uuid__": "b4dc81a3-eb90-4722-9296-5158f004fd4c"
}
},
{
"frame": 0.5,
"value": {
"__uuid__": "c156fa2c-0c4e-4413-80c1-accf8fea4779"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "7d69868f-d474-4d86-a262-01f1cdd49021",
"subMetas": {}
}

View File

@@ -0,0 +1,109 @@
{
"__type__": "cc.AnimationClip",
"_name": "Idle1",
"_objFlags": 0,
"_native": "",
"_duration": 2.0166666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 2,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "51ede1f1-5e65-4b69-8fbc-5b7df2a7c90f"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "b0f1ecf7-be41-46a8-bccb-92ee53b4ef88"
}
},
{
"frame": 0.21666666666666667,
"value": {
"__uuid__": "944adaee-5e11-4c55-9573-1d529f21ed4b"
}
},
{
"frame": 0.31666666666666665,
"value": {
"__uuid__": "ede36130-8312-46a2-abe5-ba102bc97822"
}
},
{
"frame": 0.45,
"value": {
"__uuid__": "32dbb977-301c-4fbd-a19c-14a5ce0e2f5b"
}
},
{
"frame": 0.6,
"value": {
"__uuid__": "581c7ab1-451d-46b0-9eeb-24cf3b898924"
}
},
{
"frame": 0.7666666666666667,
"value": {
"__uuid__": "27005132-eda8-4c3f-9f4a-3a6004245e9f"
}
},
{
"frame": 0.9166666666666666,
"value": {
"__uuid__": "2b339657-aa80-4ab6-a4dd-83e9c12b6a54"
}
},
{
"frame": 1.0666666666666667,
"value": {
"__uuid__": "08e25a99-158d-4159-8152-6c9047fe9d54"
}
},
{
"frame": 1.2166666666666666,
"value": {
"__uuid__": "ab739541-39b5-4758-9b93-6681d6038730"
}
},
{
"frame": 1.3833333333333333,
"value": {
"__uuid__": "9ecbf97e-34bc-4c5e-b9e8-4d885a02e0d3"
}
},
{
"frame": 1.5333333333333334,
"value": {
"__uuid__": "e7d9a7c9-47ec-4335-97c9-19ed6ee3d9ce"
}
},
{
"frame": 1.7,
"value": {
"__uuid__": "cf258753-3900-4de4-a0bb-09158500fd9a"
}
},
{
"frame": 1.85,
"value": {
"__uuid__": "be7bedfe-7054-4092-89fc-ca397460f140"
}
},
{
"frame": 2,
"value": {
"__uuid__": "b1b467dd-1757-4ff1-9909-3449f74463d8"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "5afe50e0-d03f-4d48-a7c0-a350c36e14d4",
"subMetas": {}
}

View File

@@ -0,0 +1,55 @@
{
"__type__": "cc.AnimationClip",
"_name": "InAirAtk1",
"_objFlags": 0,
"_native": "",
"_duration": 0.38333333333333336,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "e6a3099f-b4c3-425f-a66b-9b992ae1c7b0"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "cade5a52-282e-47e5-aca9-5abb4f6afd14"
}
},
{
"frame": 0.1,
"value": {
"__uuid__": "96b0b028-3045-4a04-bf9c-c957f8c9e9ab"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "567f6bb7-c764-4c1d-bfec-f5c0c9812192"
}
},
{
"frame": 0.31666666666666665,
"value": {
"__uuid__": "5d0c32b4-52ce-4157-9b91-dd400a7ed07a"
}
},
{
"frame": 0.36666666666666664,
"value": {
"__uuid__": "fcef9c9b-dc71-459c-a541-9273b6e3923a"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "0e7468cc-b90d-4f68-91ce-0be126b406dd",
"subMetas": {}
}

View File

@@ -0,0 +1,31 @@
{
"__type__": "cc.AnimationClip",
"_name": "InAirAtked1",
"_objFlags": 0,
"_native": "",
"_duration": 0.08333333333333333,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "01e8b938-03cb-4519-a417-384c31131a27"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "d7970a18-f3af-44c6-b216-ee55b9a1b32c"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "c86debde-118b-46b8-b483-f5ccec337315",
"subMetas": {}
}

View File

@@ -0,0 +1,79 @@
{
"__type__": "cc.AnimationClip",
"_name": "InAirIdle1ByJump",
"_objFlags": 0,
"_native": "",
"_duration": 0.4666666666666667,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "6ff7b4e6-80ec-4673-b47b-e0bba7567c3c"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "4ff35932-9869-4c78-9f75-b304eee46647"
}
},
{
"frame": 0.1,
"value": {
"__uuid__": "6b1355c5-a750-4e37-9018-de1b84238f6c"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "01193448-adb0-4364-94f3-ca810897f397"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "f4f0cd5d-835b-44c3-8cc9-2651dd00cd37"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "4c32b2d6-346f-4d6e-a92e-6678e4c4b1ad"
}
},
{
"frame": 0.3,
"value": {
"__uuid__": "30ef09b2-366a-4946-b556-2c0fac359c0b"
}
},
{
"frame": 0.35,
"value": {
"__uuid__": "6ab33993-124f-429e-ba4c-b0f6824ea6c7"
}
},
{
"frame": 0.4,
"value": {
"__uuid__": "e0612a37-a743-40fe-83ff-f189971f1992"
}
},
{
"frame": 0.45,
"value": {
"__uuid__": "6ff230eb-44e8-4ca9-97d0-1b059aa1e21b"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "c4ddf3ea-2292-4511-a320-5486934ac361",
"subMetas": {}
}

View File

@@ -0,0 +1,25 @@
{
"__type__": "cc.AnimationClip",
"_name": "InAirIdle1NoJump",
"_objFlags": 0,
"_native": "",
"_duration": 0.016666666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 2,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "6ff230eb-44e8-4ca9-97d0-1b059aa1e21b"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "bc461a02-4d1a-46a4-9f3c-7370adc6c1c8",
"subMetas": {}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

View File

@@ -0,0 +1,12 @@
{
"ver": "2.3.3",
"uuid": "385b0a2b-765c-43fc-9243-977baccfd37a",
"type": "raw",
"wrapMode": "clamp",
"filterMode": "bilinear",
"premultiplyAlpha": false,
"genMipmaps": false,
"packable": true,
"platformSettings": {},
"subMetas": {}
}

View File

@@ -0,0 +1,31 @@
{
"__type__": "cc.AnimationClip",
"_name": "LayDown1",
"_objFlags": 0,
"_native": "",
"_duration": 0.06666666666666667,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "4e8a4f3c-5406-4700-9230-b2abc29a1093"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "1ae5e6f6-ba82-485d-b3c7-59fd16ece3d5"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "0a6478a6-f4cc-47cb-a1c6-761cf9141eb2",
"subMetas": {}
}

View File

@@ -0,0 +1,37 @@
{
"__type__": "cc.AnimationClip",
"_name": "OnWall",
"_objFlags": 0,
"_native": "",
"_duration": 0.26666666666666666,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "c18886db-8116-4602-84f2-51652a90269a"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "0d81cbf0-dff8-4672-99b3-2ec8055c6931"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "a183e740-3c2d-4890-8430-39a00f55f446"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "411f964a-4dd8-424c-b2e2-d92b10474ce2",
"subMetas": {}
}

View File

@@ -0,0 +1,43 @@
{
"__type__": "cc.AnimationClip",
"_name": "TurnAround1",
"_objFlags": 0,
"_native": "",
"_duration": 0.15,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "28ee1f29-e538-4d36-bb5c-275f9e3b392b"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "211a73bb-31d7-4e6c-901e-f6939d9214e0"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "048c41dc-fc00-4bc4-8041-6003e7c2b6e4"
}
},
{
"frame": 0.13333333333333333,
"value": {
"__uuid__": "9435195e-4560-495e-b1ae-083c0c87e8a0"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "e906322d-a08b-4477-a2e9-98acd42fa034",
"subMetas": {}
}

View File

@@ -0,0 +1,97 @@
{
"__type__": "cc.AnimationClip",
"_name": "Walking",
"_objFlags": 0,
"_native": "",
"_duration": 0.6333333333333333,
"sample": 60,
"speed": 1.2,
"wrapMode": 2,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "9435195e-4560-495e-b1ae-083c0c87e8a0"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "ec048360-7a17-4f22-ba52-eb86ec1acae8"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "82bb81e3-667c-4280-8710-211f4904ef2f"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "c3b14ecc-a6d9-4cb3-8637-ca7b407a0f5c"
}
},
{
"frame": 0.21666666666666667,
"value": {
"__uuid__": "f958fb7f-ef5a-4918-81f3-564004572f45"
}
},
{
"frame": 0.26666666666666666,
"value": {
"__uuid__": "8a0ecf92-db26-4206-9a80-20e749055def"
}
},
{
"frame": 0.31666666666666665,
"value": {
"__uuid__": "942f2e02-a700-4fbf-877e-08c93e4d4010"
}
},
{
"frame": 0.36666666666666664,
"value": {
"__uuid__": "30546064-1a11-499e-8523-a82c83951c73"
}
},
{
"frame": 0.4166666666666667,
"value": {
"__uuid__": "515bb75f-7a1f-4500-8aa9-c895915ce19f"
}
},
{
"frame": 0.4666666666666667,
"value": {
"__uuid__": "9100da6b-7582-4afb-9698-3d67d3b2012d"
}
},
{
"frame": 0.5166666666666667,
"value": {
"__uuid__": "1257f72d-0cb3-4750-ae70-13c2d8eb2269"
}
},
{
"frame": 0.5666666666666667,
"value": {
"__uuid__": "1d34b6db-27ba-4e26-864d-0f00d501765e"
}
},
{
"frame": 0.6166666666666667,
"value": {
"__uuid__": "c317a75a-52c0-4c38-9300-a064cbf4efb3"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "f7f60d3f-32c0-4b56-901e-6eec9f73fa83",
"subMetas": {}
}

View File

@@ -0,0 +1,7 @@
{
"ver": "1.0.1",
"uuid": "e0e9bbc6-e22a-4277-b674-1308432d9734",
"isSubpackage": false,
"subpackageName": "",
"subMetas": {}
}

View File

@@ -0,0 +1,61 @@
{
"__type__": "cc.AnimationClip",
"_name": "Atk1",
"_objFlags": 0,
"_native": "",
"_duration": 0.5,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "c7107ebe-c5c1-4ba6-8ef4-6eb768f7faf9"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "e0e20918-ff59-43bc-aeaf-035087934092"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "5896a135-36da-4fa9-9257-a9042ba4b546"
}
},
{
"frame": 0.26666666666666666,
"value": {
"__uuid__": "4a16667a-f3b3-405c-8565-d65a4281cfc8"
}
},
{
"frame": 0.35,
"value": {
"__uuid__": "5ad9858c-52aa-4742-be68-d680210e0d0a"
}
},
{
"frame": 0.43333333333333335,
"value": {
"__uuid__": "e54dbc94-3eeb-450a-9206-655e960771d2"
}
},
{
"frame": 0.48333333333333334,
"value": {
"__uuid__": "f79260b7-7702-4f15-8f12-eb19f018aff1"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "d044ab74-be6a-49a2-85ab-eba41922c2cd",
"subMetas": {}
}

View File

@@ -0,0 +1,103 @@
{
"__type__": "cc.AnimationClip",
"_name": "Atk2",
"_objFlags": 0,
"_native": "",
"_duration": 0.6166666666666667,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "549e581f-5121-4cbb-96e9-b3b8b5b0f227"
}
},
{
"frame": 0.06666666666666667,
"value": {
"__uuid__": "0355243d-755f-497b-b1ff-4ec105f4efe7"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "22386328-484b-441e-9675-6553ede6118c"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "1ed0eb22-5a20-405f-a15e-8a66348bd025"
}
},
{
"frame": 0.18333333333333332,
"value": {
"__uuid__": "6e12225f-2300-4e0e-bcf6-00049bfbc48f"
}
},
{
"frame": 0.21666666666666667,
"value": {
"__uuid__": "08e1ec2a-500f-4a16-a19d-383de218cc14"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "024b3ae9-7d24-4057-83d7-4b58f8651ce0"
}
},
{
"frame": 0.3,
"value": {
"__uuid__": "57f241ae-ce40-49ed-bf63-71d016e41e2f"
}
},
{
"frame": 0.35,
"value": {
"__uuid__": "d2685f61-3365-4c14-9fb1-d7b2311871c4"
}
},
{
"frame": 0.4,
"value": {
"__uuid__": "59587d34-25af-42bd-ba0c-747c5f5fa697"
}
},
{
"frame": 0.45,
"value": {
"__uuid__": "3bceacb5-309a-41e0-bdad-26e85bcf859a"
}
},
{
"frame": 0.5,
"value": {
"__uuid__": "57f6da9e-f131-4fab-9a3d-f2e894d203aa"
}
},
{
"frame": 0.55,
"value": {
"__uuid__": "c35454f3-535b-4aec-b408-b8174a74556a"
}
},
{
"frame": 0.6,
"value": {
"__uuid__": "24f5b898-42dc-4f67-b6fc-946cdb5e369f"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "2cab337d-df23-476d-8a98-b5f115a52d04",
"subMetas": {}
}

View File

@@ -0,0 +1,91 @@
{
"__type__": "cc.AnimationClip",
"_name": "Atk3",
"_objFlags": 0,
"_native": "",
"_duration": 0.5333333333333333,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "d97f6a5f-8e63-40d7-bd14-9dc71e15e5db"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "196bcbf9-e89f-4b26-b736-73e2fa787e50"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "3229e023-e63d-4a4e-af72-2b1409ea43c5"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "e2d6e8b8-b468-4edb-b8c3-860bd85ebeae"
}
},
{
"frame": 0.16666666666666666,
"value": {
"__uuid__": "318745eb-06b1-4e7f-88d1-e23e02d99e67"
}
},
{
"frame": 0.21666666666666667,
"value": {
"__uuid__": "bba6f088-0e1f-4a12-9872-41670be1152a"
}
},
{
"frame": 0.26666666666666666,
"value": {
"__uuid__": "2c5de5b2-9009-48fa-bef4-ae34cc94f876"
}
},
{
"frame": 0.31666666666666665,
"value": {
"__uuid__": "6f27b252-6eaf-4b4b-9c5a-46ba899e4845"
}
},
{
"frame": 0.36666666666666664,
"value": {
"__uuid__": "4ebd5c60-efa6-4950-a4c8-74a7a8517333"
}
},
{
"frame": 0.4166666666666667,
"value": {
"__uuid__": "a207290f-4556-4adb-8a11-e1d5ba342550"
}
},
{
"frame": 0.4666666666666667,
"value": {
"__uuid__": "e9d442d2-981d-437d-87c0-085162017de7"
}
},
{
"frame": 0.5166666666666667,
"value": {
"__uuid__": "9b4d5c8c-5ec0-4fd7-a45e-6b0bc8ff9119"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "504dd9c8-7850-44e8-a944-bbdb2260b18a",
"subMetas": {}
}

View File

@@ -0,0 +1,115 @@
{
"__type__": "cc.AnimationClip",
"_name": "Atk4",
"_objFlags": 0,
"_native": "",
"_duration": 0.6833333333333333,
"sample": 60,
"speed": 1,
"wrapMode": 1,
"curveData": {
"comps": {
"cc.Sprite": {
"spriteFrame": [
{
"frame": 0,
"value": {
"__uuid__": "a4f724de-140f-472a-be83-731520d3da38"
}
},
{
"frame": 0.03333333333333333,
"value": {
"__uuid__": "3594a12d-5b5c-4dc6-8138-1b48eacf0798"
}
},
{
"frame": 0.05,
"value": {
"__uuid__": "cdef413d-f009-45d3-aeb6-423652fc366d"
}
},
{
"frame": 0.08333333333333333,
"value": {
"__uuid__": "688682c4-ea77-4d2c-b1e4-079f5880d3cd"
}
},
{
"frame": 0.11666666666666667,
"value": {
"__uuid__": "ca9f0a44-9977-4b24-8243-ac5536f14bc8"
}
},
{
"frame": 0.15,
"value": {
"__uuid__": "6b4dbc7c-a872-40d6-be0e-4d1a96eddd44"
}
},
{
"frame": 0.2,
"value": {
"__uuid__": "b43c8a38-1d55-4d6b-b6a1-fc888a9e53b5"
}
},
{
"frame": 0.25,
"value": {
"__uuid__": "0eb3d73a-a724-46f3-b1f1-56d315150320"
}
},
{
"frame": 0.3,
"value": {
"__uuid__": "ddac83f4-f0bf-460e-9a83-cc75c69ef024"
}
},
{
"frame": 0.35,
"value": {
"__uuid__": "8e673fdc-2cc8-435c-8a0d-38dcfc7b8600"
}
},
{
"frame": 0.4,
"value": {
"__uuid__": "7a345895-6501-4388-88f6-984992a3799b"
}
},
{
"frame": 0.4666666666666667,
"value": {
"__uuid__": "99b4e340-52ca-4f3e-a86f-ca385ff8797a"
}
},
{
"frame": 0.5166666666666667,
"value": {
"__uuid__": "554d0862-0d1c-4f61-8d47-03362cd9eb1d"
}
},
{
"frame": 0.5666666666666667,
"value": {
"__uuid__": "cd15a283-cf0d-48d4-9162-2d72202baf82"
}
},
{
"frame": 0.6166666666666667,
"value": {
"__uuid__": "b2bb7fdf-2532-408f-a3d1-fe8bf0e34f61"
}
},
{
"frame": 0.6666666666666666,
"value": {
"__uuid__": "435c0195-a5c3-4a8f-9d44-e6f026649b70"
}
}
]
}
}
},
"events": []
}

View File

@@ -0,0 +1,5 @@
{
"ver": "2.1.0",
"uuid": "7e0a1e98-ee5a-446f-bec2-7d72b6916503",
"subMetas": {}
}

Some files were not shown because too many files have changed in this diff Show More