Compare commits
308 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
7e89d703ba | ||
|
dc1e6d3e09 | ||
|
28e5c18f00 | ||
|
a241912e7a | ||
|
c582071f4f | ||
|
59d6300880 | ||
|
6713feded1 | ||
|
da1204dc63 | ||
|
ea14ced958 | ||
|
b9beee549f | ||
|
04d8013cbb | ||
|
6b503ec95d | ||
|
71f2a1ecdf | ||
|
de9f3c9090 | ||
|
96e355eab3 | ||
|
16e1d8a913 | ||
|
04b033be7e | ||
|
7fd96b335a | ||
|
8cd5f1d475 | ||
|
21806a3754 | ||
|
e213fdfb04 | ||
|
b9827f8430 | ||
|
91d16b1cc4 | ||
|
b19868920a | ||
|
be5200663c | ||
|
7b878ff947 | ||
|
c78c480f99 | ||
|
b50874f5c4 | ||
|
f1db2972fd | ||
|
16c27b0ce0 | ||
|
a44535cad2 | ||
|
8b5a96e825 | ||
|
618531f5c6 | ||
|
8345d55e76 | ||
|
a48e2f3cc0 | ||
|
83419a6f23 | ||
|
b19549b0a8 | ||
|
60866674b5 | ||
|
a4941c1273 | ||
|
2b304eaa75 | ||
|
c6b98855af | ||
|
4e0928cb1b | ||
|
fb42533f55 | ||
|
9dff989e02 | ||
|
5b7f35b874 | ||
|
2d179d0cdf | ||
|
f4b303eb91 | ||
|
5d92b339f6 | ||
|
642adff919 | ||
|
62c51b1838 | ||
|
2751569e0c | ||
|
d623916b3c | ||
|
efd070a11b | ||
|
d111de0a7a | ||
|
c2fa251e69 | ||
|
de16e8e8de | ||
|
365177a3af | ||
|
b79e2dc935 | ||
|
7b0c807496 | ||
|
5c611b626d | ||
|
38149279bd | ||
|
a762c563d9 | ||
|
6a0d729dee | ||
|
f10389bf55 | ||
|
6b3d1ed49a | ||
|
d25bb5ff10 | ||
|
d38d4b4ec9 | ||
|
03828db6ff | ||
|
917fca2bcd | ||
|
680e4f1f59 | ||
|
f367609276 | ||
|
70ae4a4c92 | ||
|
6f561bea87 | ||
|
70a86c27b0 | ||
|
b0f37d2237 | ||
|
09376b827d | ||
|
d560392c79 | ||
|
c75f642011 | ||
|
5cfcac6cf6 | ||
|
d37ebd4c33 | ||
|
1d138b17c3 | ||
|
851678e2f3 | ||
|
2fb6fd6bea | ||
|
e3440a2a06 | ||
|
8de2d6e4e7 | ||
|
ba2dd0b22e | ||
|
754610d31b | ||
|
a35de9b83c | ||
|
2b6cb57050 | ||
|
677e76179c | ||
|
c65c122f45 | ||
|
b5530b352b | ||
|
4e638fb2ec | ||
|
7c454130db | ||
|
5863f88435 | ||
|
bbf07fe518 | ||
|
26660d75d2 | ||
|
76cdbc8f1f | ||
|
4097a8da75 | ||
|
e7bf6ec16b | ||
|
7ab983949c | ||
|
2028f8277d | ||
|
60bb74169e | ||
|
8536521136 | ||
|
5df545e168 | ||
|
6bc3feab58 | ||
|
e21e1b840f | ||
|
ef345e0e48 | ||
|
0168e2182e | ||
|
58b06f6a10 | ||
|
58e60a789f | ||
|
b5b43bb596 | ||
|
59767c1ed5 | ||
|
1c6ad5c8f8 | ||
|
34e0893eb8 | ||
|
cc7524becd | ||
|
d06cb18a08 | ||
|
00816fb636 | ||
|
ff24bea055 | ||
|
56d66a128a | ||
|
2f097dfec5 | ||
|
ff48b47ecc | ||
|
7a0127b17d | ||
|
59c8427c70 | ||
|
c357ebad3b | ||
|
b2e1f7c2a6 | ||
|
9a8c32197e | ||
|
a82a238ce9 | ||
|
5b76c5bbfb | ||
|
b81c470135 | ||
|
48074d48af | ||
|
342efc623c | ||
|
b8e757064d | ||
|
71b9e72592 | ||
|
21b48b7c0d | ||
|
fbfca965e6 | ||
|
b27b567c77 | ||
|
e9119530f1 | ||
|
e6a4295773 | ||
|
aa14529bf8 | ||
|
84af0d1572 | ||
|
16fb23c376 | ||
|
d1f8a58154 | ||
|
89c31e8944 | ||
|
45380d170f | ||
|
dd9c03404e | ||
|
29e402ea71 | ||
|
b1e3d6525c | ||
|
845282db50 | ||
|
71a5a7b727 | ||
|
934a495d47 | ||
|
9725fb9df2 | ||
|
7d922aab0b | ||
|
823624d95d | ||
|
ab122a7bc8 | ||
|
5b9b3a0b55 | ||
|
24e980c17f | ||
|
ab6a04693d | ||
|
bce26f4663 | ||
|
938ca7e57d | ||
|
e2191f9d13 | ||
|
2d04363d69 | ||
|
80c6e05731 | ||
|
69581009ee | ||
|
bd870e4059 | ||
|
915bbcae3d | ||
|
4c64c1984c | ||
|
325dbfb79c | ||
|
8b80117d3d | ||
|
c7fc377a2b | ||
|
b34fa79aeb | ||
|
b466f1196d | ||
|
ec8760c24b | ||
|
d773b57299 | ||
|
69f0ddc171 | ||
|
11d001465d | ||
|
f4868197b6 | ||
|
c017aaa7ed | ||
|
335e11e925 | ||
|
bb6055f48c | ||
|
ac5217611d | ||
|
0b0de0beb3 | ||
|
bc8eab8115 | ||
|
a85c6f9ad8 | ||
|
8139a00939 | ||
|
9ffcc6fbd8 | ||
|
013c1ea312 | ||
|
72782735d3 | ||
|
cb571f56e8 | ||
|
8a9d449d83 | ||
|
df5c9fda30 | ||
|
9d03794e49 | ||
|
69e6baf8e7 | ||
|
faee73ae50 | ||
|
14bb6fa1ea | ||
|
3c15e21652 | ||
|
727e66787f | ||
|
9eb6ad26ef | ||
|
847607f3e6 | ||
|
8d2665ebd7 | ||
|
1694287083 | ||
|
e63ce2c484 | ||
|
a28c9a31f9 | ||
|
3b186c7f75 | ||
|
34c4a24b64 | ||
|
4e7c3060fe | ||
|
2928cbbe3c | ||
|
850eee20a8 | ||
|
5eec7fcfe7 | ||
|
4e42c0770c | ||
|
8647c1a859 | ||
|
a41c68fb13 | ||
|
c5b26d716e | ||
|
1e0959c4cf | ||
|
3e54670a1b | ||
|
b41b86bbd3 | ||
|
db2bc0e3cd | ||
|
eedcf5c4dc | ||
|
c171ebc211 | ||
|
5a463239bb | ||
|
5c06cfdbac | ||
|
7985a242fd | ||
|
bef1df48aa | ||
|
8d989d543a | ||
|
849ce34fe5 | ||
|
195a400dc2 | ||
|
66dfcaa0f5 | ||
|
9917a62526 | ||
|
62e50f8b6c | ||
|
dc66be1599 | ||
|
858eba5243 | ||
|
d113cffc7d | ||
|
6af9a14be5 | ||
|
e3fe773634 | ||
|
17cac19c62 | ||
|
26bdd41285 | ||
|
6bf70463fa | ||
|
e3d844abad | ||
|
0373665382 | ||
|
3b0db64792 | ||
|
dd8b731ade | ||
|
c4489e0912 | ||
|
348c889e14 | ||
|
c6473db561 | ||
|
e165d49cb1 | ||
|
26370dce61 | ||
|
f3a12b2aa9 | ||
|
1f5802ee14 | ||
|
080a384ade | ||
|
9469b27348 | ||
|
ca5ba83b07 | ||
|
b1f0cf2c57 | ||
|
1b43e6d760 | ||
|
e0fb21f3fb | ||
|
9bce561441 | ||
|
52be2a6a79 | ||
|
fa491b357d | ||
|
695eacaabc | ||
|
0324b584a5 | ||
|
70e552f5f0 | ||
|
c58e690a47 | ||
|
1593965950 | ||
|
2a1105efa4 | ||
|
04de4666d5 | ||
|
2290c57c1c | ||
|
24d5ad9dc8 | ||
|
fdc296531a | ||
|
becc56f672 | ||
|
58c18ab7ae | ||
|
024d527f3d | ||
|
9b29edaaa1 | ||
|
360f2fc22b | ||
|
2dbc529978 | ||
|
d21f59cafa | ||
|
335fef66ef | ||
|
52480ab29f | ||
|
971f6461ab | ||
|
061aa449c9 | ||
|
78dd9ecd85 | ||
|
d4226137b6 | ||
|
e432026fec | ||
|
3e7718ed04 | ||
|
b78dd54431 | ||
|
22fb72afbc | ||
|
7b9172c27b | ||
|
7e12853a73 | ||
|
95dcc2ef17 | ||
|
63164569b1 | ||
|
8a4efd023b | ||
|
b031fc1c61 | ||
|
4369729d9c | ||
|
2d080ad134 | ||
|
bd9beec5e5 | ||
|
89a54211e1 | ||
|
a4ebde3e07 | ||
|
41967b11f7 | ||
|
98daeff408 | ||
|
320e98361e | ||
|
15a062af10 | ||
|
3f4e49656a | ||
|
f97ce22cef | ||
|
901b189c5a | ||
|
e5ed8124e8 | ||
|
885443c2b1 | ||
|
aa795fcee5 | ||
|
cb3c19a339 | ||
|
d3d3629618 | ||
|
f37f4337de |
4
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
.vs
|
||||
**/.vs
|
||||
battle_srv/test_cases/test_cases
|
||||
battle_srv/test_cases/tests
|
||||
*.pid
|
||||
@@ -132,3 +134,5 @@ gradle/*
|
||||
*.project
|
||||
|
||||
*~
|
||||
jsexport/jsexport.js*
|
||||
battle_srv/room_*.txt
|
||||
|
@@ -1,15 +1,21 @@
|
||||
# Potential avalanche from local lag
|
||||
# What to be concerned for internet syncing
|
||||
1. Server received too late (solution: force confirmation)
|
||||
2. Client received too late (solution: prediction and frame chasing, big impact on user experience because the graphics will be inconsistent if mismatches occur too often)
|
||||
|
||||
# Potential avalanche from `ACTIVE SLOW TICKER`
|
||||
Under the current "input delay" algorithm, the lag of a single player would cause all the other players to receive outdated commands, e.g. when at a certain moment
|
||||
- player#1: renderFrameId = 100, significantly lagged due to local CPU overheated
|
||||
- player#1: renderFrameId = 100, **still active in battle but significantly lagged** due to local CPU overheated
|
||||
- player#2: renderFrameId = 240
|
||||
- player#3: renderFrameId = 239
|
||||
- player#4: renderFrameId = 242
|
||||
|
||||
players #2, #3 #4 would receive "outdated(in their subjective feelings) but all-confirmed commands" from then on, thus forced to rollback and chase many frames - the lag due to "large range of frame-chasing" would then further deteriorate the situation - like an avalanche.
|
||||
|
||||
In a "no-server & p2p" setup, I couldn't think of a proper way to cope with such edge case. Solely on the frontend we could only mitigate the impact to players #2, #3, #4, e.g. a potential lag due to "large range of frame-chasing" is proactively avoided in `<proj-root>/frontend/assets/scripts/Map.js, function update(dt)`.
|
||||
**BE CAUTIOUS, THIS `ACTIVE SLOW TICKER` SITUATION HAPPENS QUITE OFTEN FOR REAL DEVICES** where different operating systems and temporary CPU overheat cause different lags for different player in a same battle! If not properly handled, slow tickers would be `inputing in the "history" of other players`, resulting in too frequent prediction mismatch and thus inconsistent graphics for other players!
|
||||
|
||||
However in a "server as authority" setup, the server could force confirming an inputFrame without player#1's upsync, and notify player#1 to apply a "roomDownsyncFrame" as well as drop all its outdated local inputFrames.
|
||||
In a "no-server & p2p" setup, I couldn't think of a proper way to cope with such edge case. Solely on the frontend we could only mitigate the impact to players #2, #3, #4, e.g. a potential lag due to "large range of frame-chasing" is proactively avoided in `<proj-root>/frontend/assets/scripts/Map.js, function update(dt)`.
|
||||
|
||||
To be fair, **a "p2p" setup can reduce round-trip to single-trip**, but w/o a point of authority in such case player#1 needs a way to recognize the slowness (e.g. check the received peer inputs) and ticks faster for a while to catch up; in contrast in a "server as authority" setup, the server could force confirming an inputFrame without player#1's upsync, and notify player#1 to apply a "roomDownsyncFrame" as well as drop all its outdated local inputFrames.
|
||||
|
||||
# Start up frames
|
||||
renderFrameId | generatedInputFrameId | toApplyInputFrameId
|
||||
@@ -41,3 +47,46 @@ 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.
|
||||

|
||||
|
||||
# Would using WebRTC for all frontends be a `UDP for all` solution?
|
||||
Theoretically yes.
|
||||
|
||||
## Plan to integrate WebRTC
|
||||
The actual integration of WebRTC to enable `browser v.s. native app w/ WebRTC` requires detailed planning :)
|
||||
|
||||
In my current implementation, there's only 1 backend process and it's responsible for all of the following things. The plan for integrating/migrating each item is written respectively.
|
||||
- TURN for UDP tunneling/relay
|
||||
- Some minor modification to [Room.PlayerSecondaryDownsyncSessionDict](https://github.com/genxium/DelayNoMore/blob/365177a3af6033f1cd629a4a4d59beb4557cc311/battle_srv/models/room.go#L126) should be enough to yield a WebRTC API friendly TURN. It's interesting that [though UDP based in transport layer, a WebRTC session is stateful and more similar to WebSocket in terms of API](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API).
|
||||
- STUN for UDP holepunching
|
||||
- Some minor modification to [Player.UdpAddr](https://github.com/genxium/DelayNoMore/blob/365177a3af6033f1cd629a4a4d59beb4557cc311/battle_srv/models/player.go#L56) should be enough to yield a WebRTC API friendly STUN.
|
||||
- reconnection recovery
|
||||
- Not sure whether or not I should separate this feature from STUN and TURN, but if I were to do so, [both `Room.RenderFrameBuffer` and `Room.InputsBuffer`](https://github.com/genxium/DelayNoMore/blob/365177a3af6033f1cd629a4a4d59beb4557cc311/battle_srv/models/room.go) should be moved to a shared fast I/O storage (e.g. using Redis) to achieve the same level of `High Availability` in design as STUN and TURN.
|
||||
|
7
MULTIHIT_ROADMAP.md
Normal 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".
|
118
README.md
@@ -1,6 +1,32 @@
|
||||
Please refer to [DelayNoMoreUnity](https://github.com/genxium/DelayNoMoreUnity) for a Unity rebuild with .net backend.
|
||||
|
||||
# Preface
|
||||
|
||||
This project is a demo for a websocket-based input synchronization method inspired by [GGPO](https://www.ggpo.net/).
|
||||
This project is a demo for a websocket-based rollback netcode inspired by [GGPO](https://github.com/pond3r/ggpo/blob/master/doc/README.md).
|
||||
|
||||
[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!
|
||||
|
||||

|
||||
|
||||
(battle between 2 celluar 4G users using Android phones, [original video here](https://pan.baidu.com/s/1m50d-VZxEGT3IgeZtww49g?pwd=eqx1))
|
||||
|
||||

|
||||
|
||||
**Since v1.0.13, smoothness in worst cases (e.g. turn-around on ground, in air and after dashing) is drastically improved due to update of prediction approach. The gifs and corresponding screenrecordings above are not updated because there's no big difference when network is good -- however, `input delay` is now set to `4 frames` -- while `input delay = 6 frames` was used in the screenrecordings -- and smoothness is even better now (well there's [a new screenrecording for PcWifi vs Android4g here](https://pan.baidu.com/s/1iNrQ2l_wqbWkURMIfyG88w?pwd=fe2f)).** Key changes are listed below.
|
||||
- [change#1](https://github.com/genxium/DelayNoMore/blob/c582071f4f2e3dd7e83d65562c7c99981252c358/jsexport/battle/battle.go#L647)
|
||||
- [change#2](https://github.com/genxium/DelayNoMore/blob/c582071f4f2e3dd7e83d65562c7c99981252c358/frontend/assets/scripts/Map.js#L1446)
|
||||
|
||||
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 (merged view@v0.9.34, excellent synchronization)](https://pan.baidu.com/s/1yeIrN5TSf6_av_8-N3vdVg?pwd=7tzw).
|
||||
- Browser vs `native app` is possible but in that case only websocket is used. For WebRTC integration plan please see [ConcerningEdgeCases](./ConcerningEdgeCases.md). You might also be interested in visiting [netplayjs](https://github.com/rameshvarun/netplayjs) to see how others use WebRTC for browser game synchronization as well.
|
||||
|
||||
|
||||
# Notable Features
|
||||
- Backend dynamics toggle via [Room.BackendDynamicsEnabled](https://github.com/genxium/DelayNoMore/blob/c582071f4f2e3dd7e83d65562c7c99981252c358/battle_srv/models/room.go#L147)
|
||||
- Recovery upon reconnection (only if backend dynamics is ON)
|
||||
- Automatic 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)_
|
||||
|
||||
@@ -8,25 +34,19 @@ _(how input delay roughly works)_
|
||||
|
||||
_(how rollback-and-chase in this project roughly works)_
|
||||
|
||||

|
||||

|
||||
|
||||
_(in game screenshot)_
|
||||
|
||||

|
||||
|
||||
Please checkout [this demo video](https://pan.baidu.com/s/123LlWcT9X-wbcYybqYnvmA?pwd=qrlw) to see whether the source codes are doing what you expect for synchronization.
|
||||
|
||||
The video mainly shows the following features.
|
||||
- The backend receives inputs from frontend peers and [by a GGPO-alike manner](https://github.com/pond3r/ggpo/blob/master/doc/README.md) 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 can be toggled off 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**.
|
||||
(By use of [GopherJs](https://github.com/gopherjs/gopherjs), the frontend codes for dynamics are now automatically generated)
|
||||

|
||||
|
||||
# 1. Building & running
|
||||
|
||||
## 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.19.1](https://golang.org/dl/) (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)
|
||||
@@ -59,7 +79,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
|
||||
@@ -78,7 +98,14 @@ The easy way is to try out 2 players with test accounts on a same machine.
|
||||
- Open one browser instance, visit _http://localhost:7456?expectedRoomId=1_, input `add`on the username box and click to request a captcha, this is a test account so a captcha would be returned by the backend and filled automatically (as shown in the figure below), then click and click to proceed to a matching scene.
|
||||
- Open another browser instance, visit _http://localhost:7456?expectedRoomId=1_, input `bdd`on the username box and click to request a captcha, this is another test account so a captcha would be returned by the backend and filled automatically, then click and click to proceed, when matched a `battle`(but no competition rule yet) would start.
|
||||
- Try out the onscreen virtual joysticks to move the cars and see if their movements are in-sync.
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 2 Troubleshooting
|
||||
|
||||
@@ -88,3 +115,66 @@ 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/c582071f4f2e3dd7e83d65562c7c99981252c358/frontend/assets/scripts/Map.js#L968).
|
||||
- Detection of [type#1 forceConfirmation on the backend](https://github.com/genxium/DelayNoMore/blob/c582071f4f2e3dd7e83d65562c7c99981252c358/battle_srv/models/room.go#L1315).
|
||||
- Detection of [type#2 forceConfirmation on the backend](https://github.com/genxium/DelayNoMore/blob/c582071f4f2e3dd7e83d65562c7c99981252c358/battle_srv/models/room.go#L1328).
|
||||
|
||||
There's also some useful information displayed on the frontend when `true == Map.showNetworkDoctorInfo`.
|
||||

|
||||
|
||||
### 2.3 WIN32 platform tool versioning
|
||||

|
||||
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"
|
||||
shell> cd ./frontend/build/jsb-link/frameworks/runtime-src/proj.win32 && MSBUILD DelayNoMore.vcxproj -property:Configuration=Debug
|
||||
```
|
||||
or
|
||||
```
|
||||
shell> cd <proj-root>
|
||||
shell> /path/to/CocosCreator.exe --path ./frontend --build "platform=win32;debug=false"
|
||||
shell> cd ./frontend/build/jsb-link/frameworks/runtime-src/proj.win32 && MSBUILD DelayNoMore.vcxproj -property:Configuration=Release
|
||||
```
|
||||
|
||||
for release.
|
||||
|
||||
If `MSBUILD` command is not yet added to `PATH`, Use `Get-Command MSBUILD` in `Developer Command Prompt for VS 2017/2019` to see where the command should come from and add it to `PATH`.
|
||||
|
||||
Similarly for Android release build
|
||||
```
|
||||
shell> cd <proj-root>
|
||||
shell> /path/to/CocosCreator.exe --path ./frontend --build "platform=android;debug=false"
|
||||
shell> cd ./frontend/build/jsb-link/frameworks/runtime-src/proj.android-studio && ./gradlew assembleRelease
|
||||
```
|
||||
|
||||
### 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.
|
||||

|
||||
|
||||
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!
|
||||

|
||||
|
||||
### 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".
|
||||
```
|
||||
|
@@ -1,10 +1,27 @@
|
||||
PROJECTNAME=server.exe
|
||||
ROOT_DIR=.
|
||||
#GOPROXY=https://mirrors.aliyun.com/goproxy
|
||||
GOPROXY=https://goproxy.io
|
||||
all: help
|
||||
|
||||
# To install `gojson` executable
|
||||
# ```
|
||||
# go install github.com/ChimeraCoder/gojson/gojson@latest
|
||||
# ```
|
||||
#
|
||||
# OS detection reference https://stackoverflow.com/a/12099167
|
||||
gen-constants:
|
||||
gojson -pkg common -name constants -input common/constants.json -o common/constants_struct.go
|
||||
ifeq ($(OS),Windows_NT)
|
||||
sed -i 's/int64/int/g' common/constants_struct.go
|
||||
else
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
sed -i '' -e 's/int64/int/g' common/constants_struct.go
|
||||
else
|
||||
sed -i 's/int64/int/g' common/constants_struct.go
|
||||
endif
|
||||
endif
|
||||
|
||||
run-test: build
|
||||
ServerEnv=TEST ./$(PROJECTNAME)
|
||||
@@ -13,13 +30,13 @@ run-test-and-hotreload:
|
||||
ServerEnv=TEST CompileDaemon -log-prefix=false -build="go build" -command="./$(PROJECTNAME)"
|
||||
|
||||
build:
|
||||
go build -o $(ROOT_DIR)/$(PROJECTNAME)
|
||||
GOPROXY=$(GOPROXY) go build -o $(ROOT_DIR)/$(PROJECTNAME)
|
||||
|
||||
run-prod: build-prod
|
||||
./$(PROJECTNAME)
|
||||
|
||||
build-prod:
|
||||
go build -ldflags "-s -w -X main.VERSION=$(shell git rev-parse --short HEAD)-$(shell date "+%Y%m%d-%H:%M:%S")" -o $(ROOT_DIR)/$(PROJECTNAME)
|
||||
GOPROXY=$(GOPROXY) go build -ldflags "-s -w -X main.VERSION=$(shell git rev-parse --short HEAD)-$(shell date "+%Y%m%d-%H:%M:%S")" -o $(ROOT_DIR)/$(PROJECTNAME)
|
||||
|
||||
.PHONY: help
|
||||
|
||||
|
@@ -1,6 +1,12 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"battle_srv/api"
|
||||
. "battle_srv/common"
|
||||
"battle_srv/common/utils"
|
||||
"battle_srv/models"
|
||||
. "battle_srv/protos"
|
||||
"battle_srv/storage"
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
@@ -10,11 +16,6 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"server/api"
|
||||
. "server/common"
|
||||
"server/common/utils"
|
||||
"server/models"
|
||||
"server/storage"
|
||||
"strconv"
|
||||
|
||||
. "dnmshared"
|
||||
@@ -79,49 +80,40 @@ func (p *playerController) SMSCaptchaGet(c *gin.Context) {
|
||||
c.Set(api.RET, Constants.RetCode.UnknownError)
|
||||
return
|
||||
}
|
||||
// Redis剩余时长校验
|
||||
if ttl >= ConstVals.Player.CaptchaMaxTTL {
|
||||
Logger.Info("There's an existing SmsCaptcha record in Redis-server: ", zap.String("key", redisKey), zap.Duration("ttl", ttl))
|
||||
c.Set(api.RET, Constants.RetCode.SmsCaptchaRequestedTooFrequently)
|
||||
return
|
||||
}
|
||||
Logger.Info("A new SmsCaptcha record is needed for: ", zap.String("key", redisKey))
|
||||
pass := false
|
||||
var succRet int
|
||||
if Conf.General.ServerEnv == SERVER_ENV_TEST {
|
||||
// 测试环境,优先从数据库校验`player.name`,不通过再走机器人magic name校验
|
||||
player, err := models.GetPlayerByName(req.Num)
|
||||
if nil == err && nil != player {
|
||||
pass = true
|
||||
succRet = Constants.RetCode.IsTestAcc
|
||||
Logger.Info("A new SmsCaptcha record is needed for: ", zap.String("key", redisKey), zap.Any("player", player))
|
||||
}
|
||||
}
|
||||
|
||||
if !pass {
|
||||
// 机器人magic name校验,不通过再走手机号校验
|
||||
player, err := models.GetPlayerByName(req.Num)
|
||||
if nil == err && nil != player {
|
||||
pass = true
|
||||
succRet = Constants.RetCode.IsBotAcc
|
||||
}
|
||||
}
|
||||
|
||||
if !pass {
|
||||
if RE_PHONE_NUM.MatchString(req.Num) {
|
||||
succRet = Constants.RetCode.Ok
|
||||
pass = true
|
||||
}
|
||||
// Hardecoded 只验证国内手机号格式
|
||||
if req.CountryCode == "86" {
|
||||
if RE_CHINA_PHONE_NUM.MatchString(req.Num) {
|
||||
succRet = Constants.RetCode.Ok
|
||||
pass = true
|
||||
} else {
|
||||
succRet = Constants.RetCode.InvalidRequestParam
|
||||
pass = false
|
||||
/*
|
||||
// Real phonenum is not supported yet!
|
||||
if !pass {
|
||||
if RE_PHONE_NUM.MatchString(req.Num) {
|
||||
succRet = Constants.RetCode.Ok
|
||||
pass = true
|
||||
}
|
||||
if req.CountryCode == "86" {
|
||||
if RE_CHINA_PHONE_NUM.MatchString(req.Num) {
|
||||
succRet = Constants.RetCode.Ok
|
||||
pass = true
|
||||
} else {
|
||||
succRet = Constants.RetCode.InvalidRequestParam
|
||||
pass = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
if !pass {
|
||||
c.Set(api.RET, Constants.RetCode.InvalidRequestParam)
|
||||
return
|
||||
@@ -133,7 +125,6 @@ func (p *playerController) SMSCaptchaGet(c *gin.Context) {
|
||||
}{Ret: succRet}
|
||||
var captcha string
|
||||
if ttl >= 0 {
|
||||
// 已有未过期的旧验证码记录,续验证码有效期。
|
||||
storage.RedisManagerIns.Expire(redisKey, ConstVals.Player.CaptchaExpire)
|
||||
captcha = storage.RedisManagerIns.Get(redisKey).Val()
|
||||
if ttl >= ConstVals.Player.CaptchaExpire/4 {
|
||||
@@ -147,7 +138,6 @@ func (p *playerController) SMSCaptchaGet(c *gin.Context) {
|
||||
}
|
||||
Logger.Info("Extended ttl of existing SMSCaptcha record in Redis:", zap.String("key", redisKey), zap.String("captcha", captcha))
|
||||
} else {
|
||||
// 校验通过,进行验证码生成处理
|
||||
captcha = strconv.Itoa(utils.Rand.Number(1000, 9999))
|
||||
if succRet == Constants.RetCode.Ok {
|
||||
getSmsCaptchaRespErrorCode := sendSMSViaVendor(req.Num, req.CountryCode, captcha)
|
||||
@@ -234,7 +224,6 @@ func (p *playerController) WechatLogin(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
//baseInfo ResAccessToken 获取用户授权access_token的返回结果
|
||||
baseInfo, err := utils.WechatIns.GetOauth2Basic(req.Authcode)
|
||||
|
||||
if err != nil {
|
||||
@@ -250,7 +239,6 @@ func (p *playerController) WechatLogin(c *gin.Context) {
|
||||
c.Set(api.RET, Constants.RetCode.WechatServerError)
|
||||
return
|
||||
}
|
||||
//fserver不会返回openId
|
||||
userInfo.OpenID = baseInfo.OpenID
|
||||
|
||||
player, err := p.maybeCreatePlayerWechatAuthBinding(userInfo)
|
||||
@@ -316,7 +304,6 @@ func (p *playerController) WechatGameLogin(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
//baseInfo ResAccessToken 获取用户授权access_token的返回结果
|
||||
baseInfo, err := utils.WechatGameIns.GetOauth2Basic(req.Authcode)
|
||||
|
||||
if err != nil {
|
||||
@@ -337,7 +324,6 @@ func (p *playerController) WechatGameLogin(c *gin.Context) {
|
||||
c.Set(api.RET, Constants.RetCode.WechatServerError)
|
||||
return
|
||||
}
|
||||
//fserver不会返回openId
|
||||
userInfo.OpenID = baseInfo.OpenID
|
||||
|
||||
player, err := p.maybeCreatePlayerWechatGameAuthBinding(userInfo)
|
||||
@@ -395,7 +381,6 @@ func (p *playerController) IntAuthTokenLogin(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
//kobako: 从player获取display name等
|
||||
player, err := models.GetPlayerById(playerLogin.PlayerID)
|
||||
if err != nil {
|
||||
Logger.Error("Get player by id in IntAuthTokenLogin function error: ", zap.Error(err))
|
||||
@@ -479,7 +464,6 @@ func (p *playerController) TokenAuth(c *gin.Context) {
|
||||
c.Abort()
|
||||
}
|
||||
|
||||
// 以下是内部私有函数
|
||||
func (p *playerController) maybeCreateNewPlayer(req smsCaptchaReq) (*models.Player, error) {
|
||||
extAuthID := req.extAuthID()
|
||||
if Conf.General.ServerEnv == SERVER_ENV_TEST {
|
||||
@@ -492,16 +476,6 @@ func (p *playerController) maybeCreateNewPlayer(req smsCaptchaReq) (*models.Play
|
||||
Logger.Info("Got a test env player:", zap.Any("phonenum", req.Num), zap.Any("playerId", player.Id))
|
||||
return player, nil
|
||||
}
|
||||
} else { //正式环境检查是否为bot用户
|
||||
botPlayer, err := models.GetPlayerByName(req.Num)
|
||||
if err != nil {
|
||||
Logger.Error("Seeking bot player error:", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
if botPlayer != nil {
|
||||
Logger.Info("Got a bot player:", zap.Any("phonenum", req.Num), zap.Any("playerId", botPlayer.Id))
|
||||
return botPlayer, nil
|
||||
}
|
||||
}
|
||||
|
||||
bind, err := models.GetPlayerAuthBinding(Constants.AuthChannel.Sms, extAuthID)
|
||||
@@ -537,29 +511,31 @@ func (p *playerController) maybeCreatePlayerWechatAuthBinding(userInfo utils.Use
|
||||
return nil, err
|
||||
}
|
||||
if player != nil {
|
||||
{ //更新玩家姓名及头像
|
||||
updateInfo := models.Player{
|
||||
updateInfo := models.Player{
|
||||
PlayerDownsync: PlayerDownsync{
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
DisplayName: userInfo.Nickname,
|
||||
}
|
||||
tx := storage.MySQLManagerIns.MustBegin()
|
||||
defer tx.Rollback()
|
||||
ok, err := models.Update(tx, player.Id, &updateInfo)
|
||||
if err != nil && ok != true {
|
||||
return nil, err
|
||||
} else {
|
||||
tx.Commit()
|
||||
}
|
||||
},
|
||||
}
|
||||
tx := storage.MySQLManagerIns.MustBegin()
|
||||
defer tx.Rollback()
|
||||
ok, err := models.Update(tx, player.Id, &updateInfo)
|
||||
if err != nil && ok != true {
|
||||
return nil, err
|
||||
} else {
|
||||
tx.Commit()
|
||||
}
|
||||
return player, nil
|
||||
}
|
||||
}
|
||||
now := utils.UnixtimeMilli()
|
||||
player := models.Player{
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
DisplayName: userInfo.Nickname,
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
PlayerDownsync: PlayerDownsync{
|
||||
DisplayName: userInfo.Nickname,
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
},
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
return p.createNewPlayer(player, userInfo.OpenID, int(Constants.AuthChannel.Wechat))
|
||||
}
|
||||
@@ -575,29 +551,31 @@ func (p *playerController) maybeCreatePlayerWechatGameAuthBinding(userInfo utils
|
||||
return nil, err
|
||||
}
|
||||
if player != nil {
|
||||
{ //更新玩家姓名及头像
|
||||
updateInfo := models.Player{
|
||||
updateInfo := models.Player{
|
||||
PlayerDownsync: PlayerDownsync{
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
DisplayName: userInfo.Nickname,
|
||||
}
|
||||
tx := storage.MySQLManagerIns.MustBegin()
|
||||
defer tx.Rollback()
|
||||
ok, err := models.Update(tx, player.Id, &updateInfo)
|
||||
if err != nil && ok != true {
|
||||
return nil, err
|
||||
} else {
|
||||
tx.Commit()
|
||||
}
|
||||
},
|
||||
}
|
||||
tx := storage.MySQLManagerIns.MustBegin()
|
||||
defer tx.Rollback()
|
||||
ok, err := models.Update(tx, player.Id, &updateInfo)
|
||||
if err != nil && ok != true {
|
||||
return nil, err
|
||||
} else {
|
||||
tx.Commit()
|
||||
}
|
||||
return player, nil
|
||||
}
|
||||
}
|
||||
now := utils.UnixtimeMilli()
|
||||
player := models.Player{
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
DisplayName: userInfo.Nickname,
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
PlayerDownsync: PlayerDownsync{
|
||||
DisplayName: userInfo.Nickname,
|
||||
Avatar: userInfo.HeadImgURL,
|
||||
},
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
return p.createNewPlayer(player, userInfo.OpenID, int(Constants.AuthChannel.WechatGame))
|
||||
}
|
||||
@@ -672,15 +650,13 @@ func sendSMSViaVendor(mobile string, nationcode string, captchaCode string) int
|
||||
Nationcode: nationcode,
|
||||
}
|
||||
var captchaExpireMin string
|
||||
//短信有效期hardcode
|
||||
if Conf.General.ServerEnv == SERVER_ENV_TEST {
|
||||
//测试环境下有效期为20秒 先hardcode了
|
||||
captchaExpireMin = "0.5"
|
||||
captchaExpireMin = "0.5" // Hardcoded
|
||||
} else {
|
||||
captchaExpireMin = strconv.Itoa(int(ConstVals.Player.CaptchaExpire) / 60000000000)
|
||||
}
|
||||
params := [2]string{captchaCode, captchaExpireMin}
|
||||
appkey := "41a5142feff0b38ade02ea12deee9741" // TODO: Should read from config file!
|
||||
appkey := "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" // TODO: Should read from config file!
|
||||
rand := strconv.Itoa(utils.Rand.Number(1000, 9999))
|
||||
now := utils.UnixtimeSec()
|
||||
|
||||
@@ -694,7 +670,7 @@ func sendSMSViaVendor(mobile string, nationcode string, captchaCode string) int
|
||||
Extend: "",
|
||||
Params: ¶ms,
|
||||
Sig: sig,
|
||||
Sign: "洛克互娱",
|
||||
Sign: "YYYYYYYYYYYYYYYYY",
|
||||
Tel: tel,
|
||||
Time: now,
|
||||
Tpl_id: 207399,
|
||||
@@ -705,7 +681,7 @@ func sendSMSViaVendor(mobile string, nationcode string, captchaCode string) int
|
||||
Logger.Info("json marshal", zap.Any("err:", err))
|
||||
return -1
|
||||
}
|
||||
resp, err := http.Post("https://yun.tim.qq.com/v5/tlssmssvr/sendsms?sdkappid=1400150185&random="+rand,
|
||||
resp, err := http.Post("https://yun.tim.qq.com/v5/tlssmssvr/sendsms?sdkappid=uuuuuuuuuuuuuuuuuuuuuuuu&random="+rand,
|
||||
"application/json",
|
||||
req)
|
||||
if err != nil {
|
||||
|
@@ -74,7 +74,7 @@ func Test_SMSCaptchaGet_illegalPhone(t *testing.T) {
|
||||
|
||||
func Test_SMSCaptchaGet_testAcc(t *testing.T) {
|
||||
player, err := getTestPlayer()
|
||||
if err == nil && player != nil {
|
||||
if nil == err && nil != player {
|
||||
resp := mustDoSmsCaptchaGetReq(fakeSMSCaptchReq(player.Name), t)
|
||||
if resp.Ret != Constants.RetCode.IsTestAcc {
|
||||
t.Fail()
|
||||
|
0
battle_srv/check_daemon.sh
Normal file → Executable 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 {
|
||||
|
@@ -1,28 +1,29 @@
|
||||
{
|
||||
"RET_CODE": {
|
||||
"__comment__":"基础",
|
||||
"OK": 9000,
|
||||
"UNKNOWN_ERROR": 9001,
|
||||
"INVALID_REQUEST_PARAM": 9002,
|
||||
"IS_TEST_ACC": 9003,
|
||||
"MYSQL_ERROR": 9004,
|
||||
"NONEXISTENT_ACT": 9005,
|
||||
"LACK_OF_DIAMOND": 9006,
|
||||
"LACK_OF_GOLD": 9007,
|
||||
"LACK_OF_ENERGY": 9008,
|
||||
"NONEXISTENT_ACT_HANDLER": 9009,
|
||||
"LOCALLY_NO_AVAILABLE_ROOM": 9010,
|
||||
"LOCALLY_NO_SPECIFIED_ROOM": 9011,
|
||||
"PLAYER_NOT_ADDABLE_TO_ROOM": 9012,
|
||||
"PLAYER_NOT_READDABLE_TO_ROOM": 9013,
|
||||
"PLAYER_NOT_FOUND": 9014,
|
||||
"PLAYER_CHEATING": 9015,
|
||||
"WECHAT_SERVER_ERROR": 9016,
|
||||
"IS_BOT_ACC": 9017,
|
||||
"__comment__": "Websocket",
|
||||
"OK": 3000,
|
||||
"UNKNOWN_ERROR": 3001,
|
||||
"INVALID_REQUEST_PARAM": 3002,
|
||||
"IS_TEST_ACC": 3003,
|
||||
"MYSQL_ERROR": 3004,
|
||||
"NONEXISTENT_ACT": 3005,
|
||||
"LACK_OF_DIAMOND": 3006,
|
||||
"LACK_OF_GOLD": 3007,
|
||||
"LACK_OF_ENERGY": 3008,
|
||||
"NONEXISTENT_ACT_HANDLER": 3009,
|
||||
"LOCALLY_NO_AVAILABLE_ROOM": 3010,
|
||||
"LOCALLY_NO_SPECIFIED_ROOM": 3011,
|
||||
"PLAYER_NOT_ADDABLE_TO_ROOM": 3012,
|
||||
"PLAYER_NOT_READDABLE_TO_ROOM": 3013,
|
||||
"PLAYER_NOT_FOUND": 3014,
|
||||
"PLAYER_CHEATING": 3015,
|
||||
"WECHAT_SERVER_ERROR": 3016,
|
||||
"IS_BOT_ACC": 3017,
|
||||
"ACTIVE_WATCHDOG": 3018,
|
||||
"BATTLE_STOPPED": 3019,
|
||||
"CLIENT_MISMATCHED_RENDER_FRAME": 3020,
|
||||
|
||||
"__comment__":"SMS",
|
||||
"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY": 5001,
|
||||
"SMS_CAPTCHA_NOT_MATCH": 5002,
|
||||
"__comment__": "OTHERS",
|
||||
"INVALID_TOKEN": 2001,
|
||||
|
||||
"DUPLICATED": 2002,
|
||||
@@ -39,12 +40,15 @@
|
||||
"FAILED_TO_DELETE": 2015,
|
||||
"FAILED_TO_CREATE": 2016,
|
||||
"INCORRECT_PHONE_NUMBER": 2018,
|
||||
"INSUFFICIENT_MEM_TO_ALLOCATE_CONNECTION": 3001,
|
||||
"PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY": 4000,
|
||||
"TRADE_CREATION_TOO_FREQUENTLY": 4002,
|
||||
"MAP_NOT_UNLOCKED": 4003,
|
||||
"INSUFFICIENT_MEM_TO_ALLOCATE_CONNECTION": 2019,
|
||||
"PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY": 2020,
|
||||
"TRADE_CREATION_TOO_FREQUENTLY": 2021,
|
||||
"MAP_NOT_UNLOCKED": 2022,
|
||||
"GET_SMS_CAPTCHA_RESP_ERROR_CODE": 2023,
|
||||
"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY": 2024,
|
||||
"SMS_CAPTCHA_NOT_MATCH": 2025,
|
||||
"SAME_PLAYER_ALREADY_IN_SAME_ROOM": 2026,
|
||||
|
||||
"GET_SMS_CAPTCHA_RESP_ERROR_CODE": 5003,
|
||||
"NOT_IMPLEMENTED_YET": 65535
|
||||
},
|
||||
"AUTH_CHANNEL": {
|
||||
@@ -62,6 +66,6 @@
|
||||
},
|
||||
"WS": {
|
||||
"INTERVAL_TO_PING": 2000,
|
||||
"WILL_KICK_IF_INACTIVE_FOR": 6000
|
||||
"WILL_KICK_IF_INACTIVE_FOR": 4000
|
||||
}
|
||||
}
|
||||
|
@@ -15,10 +15,14 @@ type constants struct {
|
||||
SmsValidResendPeriodSeconds int `json:"SMS_VALID_RESEND_PERIOD_SECONDS"`
|
||||
} `json:"PLAYER"`
|
||||
RetCode struct {
|
||||
ActiveWatchdog int `json:"ACTIVE_WATCHDOG"`
|
||||
BattleStopped int `json:"BATTLE_STOPPED"`
|
||||
ClientMismatchedRenderFrame int `json:"CLIENT_MISMATCHED_RENDER_FRAME"`
|
||||
Duplicated int `json:"DUPLICATED"`
|
||||
FailedToCreate int `json:"FAILED_TO_CREATE"`
|
||||
FailedToDelete int `json:"FAILED_TO_DELETE"`
|
||||
FailedToUpdate int `json:"FAILED_TO_UPDATE"`
|
||||
GetSmsCaptchaRespErrorCode int `json:"GET_SMS_CAPTCHA_RESP_ERROR_CODE"`
|
||||
IncorrectCaptcha int `json:"INCORRECT_CAPTCHA"`
|
||||
IncorrectHandle int `json:"INCORRECT_HANDLE"`
|
||||
IncorrectPassword int `json:"INCORRECT_PASSWORD"`
|
||||
@@ -28,27 +32,27 @@ type constants struct {
|
||||
InvalidEmailLiteral int `json:"INVALID_EMAIL_LITERAL"`
|
||||
InvalidRequestParam int `json:"INVALID_REQUEST_PARAM"`
|
||||
InvalidToken int `json:"INVALID_TOKEN"`
|
||||
IsTestAcc int `json:"IS_TEST_ACC"`
|
||||
IsBotAcc int `json:"IS_BOT_ACC"`
|
||||
IsTestAcc int `json:"IS_TEST_ACC"`
|
||||
LackOfDiamond int `json:"LACK_OF_DIAMOND"`
|
||||
LackOfEnergy int `json:"LACK_OF_ENERGY"`
|
||||
LackOfGold int `json:"LACK_OF_GOLD"`
|
||||
LocallyNoAvailableRoom int `json:"LOCALLY_NO_AVAILABLE_ROOM"`
|
||||
LocallyNoSpecifiedRoom int `json:"LOCALLY_NO_SPECIFIED_ROOM"`
|
||||
MapNotUnlocked int `json:"MAP_NOT_UNLOCKED"`
|
||||
MysqlError int `json:"MYSQL_ERROR"`
|
||||
GetSmsCaptchaRespErrorCode int `json:"GET_SMS_CAPTCHA_RESP_ERROR_CODE"`
|
||||
NewHandleConflict int `json:"NEW_HANDLE_CONFLICT"`
|
||||
NonexistentAct int `json:"NONEXISTENT_ACT"`
|
||||
NonexistentActHandler int `json:"NONEXISTENT_ACT_HANDLER"`
|
||||
LocallyNoAvailableRoom int `json:"LOCALLY_NO_AVAILABLE_ROOM"`
|
||||
LocallyNoSpecifiedRoom int `json:"LOCALLY_NO_SPECIFIED_ROOM"`
|
||||
PlayerNotAddableToRoom int `json:"PLAYER_NOT_ADDABLE_TO_ROOM"`
|
||||
PlayerNotReAddableToRoom int `json:"PLAYER_NOT_READDABLE_TO_ROOM"`
|
||||
PlayerNotFound int `json:"PLAYER_NOT_FOUND"`
|
||||
PlayerCheating int `json:"PLAYER_CHEATING"`
|
||||
NotImplementedYet int `json:"NOT_IMPLEMENTED_YET"`
|
||||
NoAssociatedEmail int `json:"NO_ASSOCIATED_EMAIL"`
|
||||
Ok int `json:"OK"`
|
||||
PasswordResetCodeGenerationPerEmailTooFrequently int `json:"PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY"`
|
||||
PlayerCheating int `json:"PLAYER_CHEATING"`
|
||||
PlayerNotAddableToRoom int `json:"PLAYER_NOT_ADDABLE_TO_ROOM"`
|
||||
PlayerNotFound int `json:"PLAYER_NOT_FOUND"`
|
||||
PlayerNotReaddableToRoom int `json:"PLAYER_NOT_READDABLE_TO_ROOM"`
|
||||
SamePlayerAlreadyInSameRoom int `json:"SAME_PLAYER_ALREADY_IN_SAME_ROOM"`
|
||||
SendEmailTimeout int `json:"SEND_EMAIL_TIMEOUT"`
|
||||
SmsCaptchaNotMatch int `json:"SMS_CAPTCHA_NOT_MATCH"`
|
||||
SmsCaptchaRequestedTooFrequently int `json:"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY"`
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
. "battle_srv/common"
|
||||
. "battle_srv/configs"
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
. "dnmshared"
|
||||
@@ -11,8 +13,6 @@ import (
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
. "server/common"
|
||||
. "server/configs"
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
@@ -250,10 +250,6 @@ func (w *wechat) getTicketFromServer() (ticket resTicket, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
//jsAPITicketCacheKey := fmt.Sprintf("jsapi_ticket_%s", w.config.AppID)
|
||||
//expires := ticket.ExpiresIn - 1500
|
||||
//set
|
||||
//err = js.Cache.Set(jsAPITicketCacheKey, ticket.Ticket, time.Duration(expires)*time.Second)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -276,9 +272,6 @@ func (w *wechat) getAccessTokenFromServer() (accessToken string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
//accessTokenCacheKey := fmt.Sprintf("access_token_%s", w.config.AppID)
|
||||
//expires := r.ExpiresIn - 1500
|
||||
//set to redis err = ctx.Cache.Set(accessTokenCacheKey, r.AccessToken, time.Duration(expires)*time.Second)
|
||||
accessToken = r.AccessToken
|
||||
return
|
||||
}
|
||||
|
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"hostAndPort": "0.0.0.0:9992"
|
||||
"hostAndPort": "0.0.0.0:9992",
|
||||
"udpHost": "0.0.0.0",
|
||||
"udpPort": 3000
|
||||
}
|
||||
|
@@ -1,15 +1,16 @@
|
||||
package env_tools
|
||||
|
||||
import (
|
||||
. "battle_srv/common"
|
||||
"battle_srv/common/utils"
|
||||
"battle_srv/models"
|
||||
. "battle_srv/protos"
|
||||
"battle_srv/storage"
|
||||
. "dnmshared"
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"go.uber.org/zap"
|
||||
. "server/common"
|
||||
"server/common/utils"
|
||||
"server/models"
|
||||
"server/storage"
|
||||
)
|
||||
|
||||
func LoadPreConf() {
|
||||
@@ -71,7 +72,6 @@ func createMysqlData(rows *sqlx.Rows, v string) {
|
||||
}
|
||||
}
|
||||
|
||||
// 加上tableName参数, 用于pre_conf_data.sqlite里bot_player表的复用 --kobako
|
||||
func maybeCreateNewPlayerFromBotTable(db *sqlx.DB, tableName string) {
|
||||
var ls []*dbBotPlayer
|
||||
err := db.Select(&ls, "SELECT name, magic_phone_country_code, magic_phone_num, display_name FROM "+tableName)
|
||||
@@ -88,7 +88,6 @@ func maybeCreateNewPlayerFromBotTable(db *sqlx.DB, tableName string) {
|
||||
panic(err)
|
||||
}
|
||||
query = storage.MySQLManagerIns.Rebind(query)
|
||||
// existNames := make([]string, len(ls), len(ls))
|
||||
var existPlayers []*models.Player
|
||||
err = storage.MySQLManagerIns.Select(&existPlayers, query, args...)
|
||||
if nil != err {
|
||||
@@ -99,13 +98,11 @@ func maybeCreateNewPlayerFromBotTable(db *sqlx.DB, tableName string) {
|
||||
var flag bool
|
||||
for _, v := range existPlayers {
|
||||
if botPlayer.Name == v.Name {
|
||||
// 已有数据,合并处理
|
||||
flag = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !flag {
|
||||
// 找不到,新增
|
||||
Logger.Debug("create", zap.Any(tableName, botPlayer))
|
||||
err := createNewBotPlayer(botPlayer)
|
||||
if err != nil {
|
||||
@@ -120,11 +117,14 @@ func createNewBotPlayer(p *dbBotPlayer) error {
|
||||
defer tx.Rollback()
|
||||
now := utils.UnixtimeMilli()
|
||||
player := models.Player{
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Name: p.Name,
|
||||
DisplayName: p.DisplayName,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
PlayerDownsync: PlayerDownsync{
|
||||
Name: p.Name,
|
||||
DisplayName: p.DisplayName,
|
||||
},
|
||||
}
|
||||
|
||||
err := player.Insert(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -1,11 +1,12 @@
|
||||
package env_tools
|
||||
|
||||
import (
|
||||
. "battle_srv/common"
|
||||
"battle_srv/common/utils"
|
||||
"battle_srv/models"
|
||||
. "battle_srv/protos"
|
||||
"battle_srv/storage"
|
||||
. "dnmshared"
|
||||
. "server/common"
|
||||
"server/common/utils"
|
||||
"server/models"
|
||||
"server/storage"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
@@ -75,9 +76,11 @@ func createNewPlayer(p *dbTestPlayer) error {
|
||||
defer tx.Rollback()
|
||||
now := utils.UnixtimeMilli()
|
||||
player := models.Player{
|
||||
PlayerDownsync: PlayerDownsync{
|
||||
Name: p.Name,
|
||||
},
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Name: p.Name,
|
||||
}
|
||||
err := player.Insert(tx)
|
||||
if err != nil {
|
||||
|
@@ -1,8 +1,9 @@
|
||||
module server
|
||||
module battle_srv
|
||||
|
||||
go 1.19
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
dnmshared v0.0.0
|
||||
github.com/Masterminds/squirrel v0.0.0-20180815162352-8a7e65843414
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/gin-contrib/cors v0.0.0-20180514151808-6f0a820f94be
|
||||
@@ -16,16 +17,15 @@ require (
|
||||
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e
|
||||
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967
|
||||
github.com/solarlune/resolv v0.5.1
|
||||
github.com/thoas/go-funk v0.0.0-20180716193722-1060394a7713
|
||||
go.uber.org/zap v1.9.1
|
||||
google.golang.org/protobuf v1.28.1
|
||||
|
||||
dnmshared v0.0.0
|
||||
jsexport v0.0.0
|
||||
resolv v0.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ChimeraCoder/gojson v1.0.0 // indirect
|
||||
github.com/ChimeraCoder/gojson v1.1.0 // indirect
|
||||
github.com/fatih/color v1.7.0 // indirect
|
||||
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect
|
||||
github.com/githubnemo/CompileDaemon v1.0.0 // indirect
|
||||
@@ -43,9 +43,11 @@ require (
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 // indirect
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
dnmshared => ../dnmshared
|
||||
jsexport => ../jsexport
|
||||
resolv => ../resolv_tailored
|
||||
)
|
||||
|
@@ -2,6 +2,8 @@ github.com/ByteArena/box2d v1.0.2 h1:f7f9KEQWhCs1n516DMLzi5w6u0MeeE78Mes4fWMcj9k
|
||||
github.com/ByteArena/box2d v1.0.2/go.mod h1:LzEuxY9iCz+tskfWCY3o0ywYBRafDDugdSj+/YGI6sE=
|
||||
github.com/ChimeraCoder/gojson v1.0.0 h1:gAYKGTV+xfQ4+l/4C/nazPbiQDUidG0G3ukAJnE7LNE=
|
||||
github.com/ChimeraCoder/gojson v1.0.0/go.mod h1:nYbTQlu6hv8PETM15J927yM0zGj3njIldp72UT1MqSw=
|
||||
github.com/ChimeraCoder/gojson v1.1.0 h1:/6S8djl/jColpJGTYniA3xrqJWuKeyEozzPtpr5L4Pw=
|
||||
github.com/ChimeraCoder/gojson v1.1.0/go.mod h1:nYbTQlu6hv8PETM15J927yM0zGj3njIldp72UT1MqSw=
|
||||
github.com/Masterminds/squirrel v0.0.0-20180815162352-8a7e65843414 h1:VHdYPA0V0YgL97gdjHevN6IVPRX+fOoNMqcYvUAzwNU=
|
||||
github.com/Masterminds/squirrel v0.0.0-20180815162352-8a7e65843414/go.mod h1:xnKTFzjGUiZtiOagBsfnvomW+nJg2usB1ZpordQWqNM=
|
||||
github.com/Pallinder/go-randomdata v0.0.0-20180616180521-15df0648130a h1:0OnS8GR4uI3nau+f/juCZlAq+zCrsHXRJlENrUQ4eU8=
|
||||
@@ -92,3 +94,5 @@ gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2G
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
@@ -1,19 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"battle_srv/api"
|
||||
"battle_srv/api/v1"
|
||||
. "battle_srv/common"
|
||||
"battle_srv/env_tools"
|
||||
"battle_srv/models"
|
||||
"battle_srv/storage"
|
||||
"battle_srv/ws"
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"server/api"
|
||||
"server/api/v1"
|
||||
. "server/common"
|
||||
"server/env_tools"
|
||||
"server/models"
|
||||
"server/storage"
|
||||
"server/ws"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -23,9 +23,18 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/robfig/cron"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"net"
|
||||
// _ "net/http/pprof"
|
||||
)
|
||||
|
||||
func main() {
|
||||
/*
|
||||
// Only used for profiling
|
||||
go func() {
|
||||
http.ListenAndServe("0.0.0.0:6060", nil)
|
||||
}()
|
||||
*/
|
||||
MustParseConfig()
|
||||
MustParseConstants()
|
||||
storage.Init()
|
||||
@@ -34,7 +43,7 @@ func main() {
|
||||
env_tools.MergeTestPlayerAccounts()
|
||||
}
|
||||
models.InitRoomHeapManager()
|
||||
startScheduler()
|
||||
// startScheduler()
|
||||
router := gin.Default()
|
||||
setRouter(router)
|
||||
|
||||
@@ -54,6 +63,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 +99,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 +124,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)
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
. "dnmshared"
|
||||
)
|
||||
|
||||
type Barrier struct {
|
||||
Boundary *Polygon2D
|
||||
}
|
@@ -1,85 +1,234 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
. "dnmshared"
|
||||
pb "server/pb_output"
|
||||
pb "battle_srv/protos"
|
||||
"jsexport/battle"
|
||||
)
|
||||
|
||||
func toPbVec2D(modelInstance *Vec2D) *pb.Vec2D {
|
||||
toRet := &pb.Vec2D{
|
||||
X: modelInstance.X,
|
||||
Y: modelInstance.Y,
|
||||
func toPbRoomDownsyncFrame(rdf *battle.RoomDownsyncFrame) *pb.RoomDownsyncFrame {
|
||||
if nil == rdf {
|
||||
return nil
|
||||
}
|
||||
return toRet
|
||||
ret := &pb.RoomDownsyncFrame{
|
||||
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,
|
||||
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{
|
||||
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,
|
||||
}
|
||||
ret.MeleeBullets[i] = pbBullet
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func toPbPolygon2D(modelInstance *Polygon2D) *pb.Polygon2D {
|
||||
toRet := &pb.Polygon2D{
|
||||
Anchor: toPbVec2D(modelInstance.Anchor),
|
||||
Points: make([]*pb.Vec2D, len(modelInstance.Points)),
|
||||
}
|
||||
for index, p := range modelInstance.Points {
|
||||
toRet.Points[index] = toPbVec2D(p)
|
||||
}
|
||||
return toRet
|
||||
}
|
||||
|
||||
func toPbVec2DList(modelInstance *Vec2DList) *pb.Vec2DList {
|
||||
toRet := &pb.Vec2DList{
|
||||
Vec2DList: make([]*pb.Vec2D, len(*modelInstance)),
|
||||
}
|
||||
for k, v := range *modelInstance {
|
||||
toRet.Vec2DList[k] = toPbVec2D(v)
|
||||
}
|
||||
return toRet
|
||||
}
|
||||
|
||||
func ToPbVec2DListMap(modelInstances map[string]*Vec2DList) map[string]*pb.Vec2DList {
|
||||
toRet := make(map[string]*pb.Vec2DList, len(modelInstances))
|
||||
for k, v := range modelInstances {
|
||||
toRet[k] = toPbVec2DList(v)
|
||||
}
|
||||
return toRet
|
||||
}
|
||||
|
||||
func toPbPolygon2DList(modelInstance *Polygon2DList) *pb.Polygon2DList {
|
||||
toRet := &pb.Polygon2DList{
|
||||
Polygon2DList: make([]*pb.Polygon2D, len(*modelInstance)),
|
||||
}
|
||||
for k, v := range *modelInstance {
|
||||
toRet.Polygon2DList[k] = toPbPolygon2D(v)
|
||||
}
|
||||
return toRet
|
||||
}
|
||||
|
||||
func ToPbPolygon2DListMap(modelInstances map[string]*Polygon2DList) map[string]*pb.Polygon2DList {
|
||||
toRet := make(map[string]*pb.Polygon2DList, len(modelInstances))
|
||||
for k, v := range modelInstances {
|
||||
toRet[k] = toPbPolygon2DList(v)
|
||||
}
|
||||
return toRet
|
||||
}
|
||||
|
||||
func toPbPlayers(modelInstances map[int32]*Player) map[int32]*pb.Player {
|
||||
toRet := make(map[int32]*pb.Player, 0)
|
||||
func toPbPlayers(modelInstances map[int32]*Player, withMetaInfo bool) []*pb.PlayerDownsync {
|
||||
toRet := make([]*pb.PlayerDownsync, len(modelInstances), len(modelInstances))
|
||||
if nil == modelInstances {
|
||||
return toRet
|
||||
}
|
||||
|
||||
for k, last := range modelInstances {
|
||||
toRet[k] = &pb.Player{
|
||||
Id: last.Id,
|
||||
X: last.X,
|
||||
Y: last.Y,
|
||||
Dir: &pb.Direction{
|
||||
Dx: last.Dir.Dx,
|
||||
Dy: last.Dir.Dy,
|
||||
},
|
||||
Speed: last.Speed,
|
||||
BattleState: last.BattleState,
|
||||
Score: last.Score,
|
||||
Removed: last.Removed,
|
||||
JoinIndex: last.JoinIndex,
|
||||
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,
|
||||
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
|
||||
pbPlayer.DisplayName = last.DisplayName
|
||||
pbPlayer.Avatar = last.Avatar
|
||||
}
|
||||
toRet[last.JoinIndex-1] = pbPlayer
|
||||
}
|
||||
|
||||
return toRet
|
||||
}
|
||||
|
||||
func toJsPlayers(modelInstances map[int32]*Player) []*battle.PlayerDownsync {
|
||||
toRet := make([]*battle.PlayerDownsync, len(modelInstances), len(modelInstances))
|
||||
if nil == modelInstances {
|
||||
return toRet
|
||||
}
|
||||
|
||||
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,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,16 +1,20 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
. "battle_srv/protos"
|
||||
"battle_srv/storage"
|
||||
. "dnmshared"
|
||||
"fmt"
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"go.uber.org/zap"
|
||||
"net"
|
||||
)
|
||||
|
||||
type PlayerBattleState struct {
|
||||
ADDED_PENDING_BATTLE_COLLIDER_ACK int32
|
||||
READDED_PENDING_BATTLE_COLLIDER_ACK int32
|
||||
READDED_BATTLE_COLLIDER_ACKED int32
|
||||
ACTIVE int32
|
||||
DISCONNECTED int32
|
||||
LOST int32
|
||||
@@ -24,39 +28,33 @@ func InitPlayerBattleStateIns() {
|
||||
PlayerBattleStateIns = PlayerBattleState{
|
||||
ADDED_PENDING_BATTLE_COLLIDER_ACK: 0,
|
||||
READDED_PENDING_BATTLE_COLLIDER_ACK: 1,
|
||||
ACTIVE: 2,
|
||||
DISCONNECTED: 3,
|
||||
LOST: 4,
|
||||
EXPELLED_DURING_GAME: 5,
|
||||
EXPELLED_IN_DISMISSAL: 6,
|
||||
READDED_BATTLE_COLLIDER_ACKED: 2,
|
||||
ACTIVE: 3,
|
||||
DISCONNECTED: 4,
|
||||
LOST: 5,
|
||||
EXPELLED_DURING_GAME: 6,
|
||||
EXPELLED_IN_DISMISSAL: 7,
|
||||
}
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
Id int32 `json:"id,omitempty" db:"id"`
|
||||
X float64 `json:"x,omitempty"`
|
||||
Y float64 `json:"y,omitempty"`
|
||||
Dir *Direction `json:"dir,omitempty"`
|
||||
Speed float64 `json:"speed,omitempty"`
|
||||
BattleState int32 `json:"battleState,omitempty"`
|
||||
LastMoveGmtMillis int32 `json:"lastMoveGmtMillis,omitempty"`
|
||||
Score int32 `json:"score,omitempty"`
|
||||
Removed bool `json:"removed,omitempty"`
|
||||
JoinIndex int32
|
||||
PlayerDownsync
|
||||
|
||||
Name string `json:"name,omitempty" db:"name"`
|
||||
DisplayName string `json:"displayName,omitempty" db:"display_name"`
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
// DB only fields
|
||||
CreatedAt int64 `db:"created_at"`
|
||||
UpdatedAt int64 `db:"updated_at"`
|
||||
DeletedAt NullInt64 `db:"deleted_at"`
|
||||
TutorialStage int `db:"tutorial_stage"`
|
||||
|
||||
FrozenAtGmtMillis int64 `json:"-" db:"-"`
|
||||
AddSpeedAtGmtMillis int64 `json:"-" db:"-"`
|
||||
CreatedAt int64 `json:"-" db:"created_at"`
|
||||
UpdatedAt int64 `json:"-" db:"updated_at"`
|
||||
DeletedAt NullInt64 `json:"-" db:"deleted_at"`
|
||||
TutorialStage int `json:"-" db:"tutorial_stage"`
|
||||
AckingFrameId int32 `json:"ackingFrameId"`
|
||||
AckingInputFrameId int32 `json:"-"`
|
||||
LastSentInputFrameId int32 `json:"-"`
|
||||
// other in-battle info fields
|
||||
LastConsecutiveRecvInputFrameId 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) {
|
||||
@@ -72,16 +70,50 @@ func GetPlayerById(id int) (*Player, error) {
|
||||
}
|
||||
|
||||
func getPlayer(cond sq.Eq) (*Player, error) {
|
||||
var p Player
|
||||
err := getObj("player", cond, &p)
|
||||
if err == sql.ErrNoRows {
|
||||
p := Player{}
|
||||
pd := PlayerDownsync{}
|
||||
query, args, err := sq.Select("*").From("player").Where(cond).Limit(1).ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rows, err := storage.MySQLManagerIns.Queryx(query, args...)
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
cols, err := rows.Columns()
|
||||
if nil != err {
|
||||
panic(err)
|
||||
}
|
||||
cnt := 0
|
||||
for rows.Next() {
|
||||
// TODO: Do it more elegantly, but by now I don't have time to learn reflection of Golang
|
||||
vals := rowValues(rows, cols)
|
||||
for i, col := range cols {
|
||||
val := *vals[i].(*interface{})
|
||||
if "id" == col {
|
||||
pd.Id = int32(val.(int64))
|
||||
}
|
||||
if "name" == col {
|
||||
switch v := val.(type) {
|
||||
case []byte:
|
||||
pd.Name = string(v)
|
||||
default:
|
||||
pd.Name = fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
if "created_at" == col {
|
||||
p.CreatedAt = int64(val.(int64))
|
||||
}
|
||||
}
|
||||
Logger.Debug("Queried player from db", zap.Any("cond", cond), zap.Any("p", p), zap.Any("pd", pd), zap.Any("cols", cols), zap.Any("rowValues", vals))
|
||||
cnt++
|
||||
}
|
||||
if 0 < cnt {
|
||||
p.PlayerDownsync = pd
|
||||
return &p, nil
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
p.Dir = &Direction{
|
||||
Dx: 0,
|
||||
Dy: 0,
|
||||
}
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func (p *Player) Insert(tx *sqlx.Tx) error {
|
||||
@@ -111,8 +143,6 @@ func Update(tx *sqlx.Tx, id int32, p *Player) (bool, error) {
|
||||
}
|
||||
result, err := tx.Exec(query, args...)
|
||||
if err != nil {
|
||||
fmt.Println("ERRRRRRR: ")
|
||||
fmt.Println(err)
|
||||
return false, err
|
||||
}
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
|
@@ -1,15 +1,26 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"battle_srv/storage"
|
||||
"database/sql"
|
||||
. "dnmshared"
|
||||
"server/storage"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func rowValues(rows *sqlx.Rows, cols []string) []interface{} {
|
||||
results := make([]interface{}, len(cols))
|
||||
for i := range results {
|
||||
results[i] = new(interface{})
|
||||
}
|
||||
if err := rows.Scan(results[:]...); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
func exist(t string, cond sq.Eq) (bool, error) {
|
||||
c, err := getCount(t, cond)
|
||||
if err != nil {
|
||||
|
@@ -1,10 +1,10 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
. "battle_srv/common"
|
||||
"battle_srv/common/utils"
|
||||
"battle_srv/storage"
|
||||
"database/sql"
|
||||
. "server/common"
|
||||
"server/common/utils"
|
||||
"server/storage"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
)
|
||||
|
@@ -1,11 +1,11 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
. "battle_srv/common"
|
||||
"battle_srv/common/utils"
|
||||
"database/sql"
|
||||
. "dnmshared"
|
||||
"errors"
|
||||
. "server/common"
|
||||
"server/common/utils"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
@@ -1,73 +0,0 @@
|
||||
package models
|
||||
|
||||
type RingBuffer struct {
|
||||
Ed int32 // write index, open index
|
||||
St int32 // read index, closed index
|
||||
EdFrameId int32
|
||||
StFrameId int32
|
||||
N int32
|
||||
Cnt int32 // the count of valid elements in the buffer, used mainly to distinguish what "st == ed" means for "Pop" and "Get" methods
|
||||
Eles []interface{}
|
||||
}
|
||||
|
||||
func NewRingBuffer(n int32) *RingBuffer {
|
||||
return &RingBuffer{
|
||||
Ed: 0,
|
||||
St: 0,
|
||||
N: n,
|
||||
Cnt: 0,
|
||||
Eles: make([]interface{}, n),
|
||||
}
|
||||
}
|
||||
|
||||
func (rb *RingBuffer) Put(pItem interface{}) {
|
||||
rb.Eles[rb.Ed] = pItem
|
||||
rb.EdFrameId++
|
||||
rb.Cnt++
|
||||
rb.Ed++
|
||||
if rb.Ed >= rb.N {
|
||||
rb.Ed -= rb.N // Deliberately not using "%" operator for performance concern
|
||||
}
|
||||
}
|
||||
|
||||
func (rb *RingBuffer) Pop() interface{} {
|
||||
if 0 == rb.Cnt {
|
||||
return nil
|
||||
}
|
||||
pItem := rb.Eles[rb.St]
|
||||
rb.StFrameId++
|
||||
rb.Cnt--
|
||||
rb.St++
|
||||
if rb.St >= rb.N {
|
||||
rb.St -= rb.N
|
||||
}
|
||||
return pItem
|
||||
}
|
||||
|
||||
func (rb *RingBuffer) GetByOffset(offsetFromSt int32) interface{} {
|
||||
if 0 == rb.Cnt {
|
||||
return nil
|
||||
}
|
||||
arrIdx := rb.St + offsetFromSt
|
||||
if rb.St < rb.Ed {
|
||||
// case#1: 0...st...ed...N-1
|
||||
if rb.St <= arrIdx && arrIdx < rb.Ed {
|
||||
return rb.Eles[arrIdx]
|
||||
}
|
||||
} else {
|
||||
// if rb.St >= rb.Ed
|
||||
// case#2: 0...ed...st...N-1
|
||||
if arrIdx >= rb.N {
|
||||
arrIdx -= rb.N
|
||||
}
|
||||
if arrIdx >= rb.St || arrIdx < rb.Ed {
|
||||
return rb.Eles[arrIdx]
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rb *RingBuffer) GetByFrameId(frameId int32) interface{} {
|
||||
return rb.GetByOffset(frameId - rb.StFrameId)
|
||||
}
|
@@ -5,6 +5,7 @@ import (
|
||||
. "dnmshared"
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@@ -21,11 +22,13 @@ var (
|
||||
|
||||
func (pPq *RoomHeap) PrintInOrder() {
|
||||
pq := *pPq
|
||||
fmt.Printf("The RoomHeap instance now contains:\n")
|
||||
s := make([]string, 0)
|
||||
s = append(s, fmt.Sprintf("The RoomHeap instance now contains:"))
|
||||
for i := 0; i < len(pq); i++ {
|
||||
fmt.Printf("{index: %d, roomID: %d, score: %.2f} ", i, pq[i].Id, pq[i].Score)
|
||||
s = append(s, fmt.Sprintf("{index: %d, roomID: %d, score: %.2f} ", i, pq[i].Id, pq[i].Score))
|
||||
}
|
||||
fmt.Printf("\n")
|
||||
|
||||
Logger.Debug(strings.Join(s, "\n"))
|
||||
}
|
||||
|
||||
func (pq RoomHeap) Len() int { return len(pq) }
|
||||
|
27
battle_srv/models/watchdog.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Watchdog struct {
|
||||
interval time.Duration
|
||||
timer *time.Timer
|
||||
}
|
||||
|
||||
func NewWatchdog(interval time.Duration, callback func()) *Watchdog {
|
||||
w := Watchdog{
|
||||
interval: interval,
|
||||
timer: time.AfterFunc(interval, callback),
|
||||
}
|
||||
return &w
|
||||
}
|
||||
|
||||
func (w *Watchdog) Stop() {
|
||||
w.timer.Stop()
|
||||
}
|
||||
|
||||
func (w *Watchdog) Kick() {
|
||||
w.timer.Stop()
|
||||
w.timer.Reset(w.interval)
|
||||
}
|
2421
battle_srv/protos/room_downsync_frame.pb.go
Normal file
3
battle_srv/start_daemon.sh
Normal file → Executable file
@@ -7,6 +7,7 @@ fi
|
||||
|
||||
basedir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
PROJECTNAME=server.exe
|
||||
OS_USER=$USER
|
||||
ServerEnv=$1
|
||||
LOG_PATH="/var/log/treasure-hunter.log"
|
||||
@@ -17,5 +18,5 @@ PID_FILE="$basedir/treasure-hunter.pid"
|
||||
sudo su - root -c "touch $LOG_PATH"
|
||||
sudo su - root -c "chown $OS_USER:$OS_USER $LOG_PATH"
|
||||
|
||||
ServerEnv=$ServerEnv $basedir/server >$LOG_PATH 2>&1 &
|
||||
ServerEnv=$ServerEnv $basedir/$PROJECTNAME >$LOG_PATH 2>&1 &
|
||||
echo $! > $PID_FILE
|
||||
|
0
battle_srv/stop_daemon.sh
Normal file → Executable file
@@ -1,7 +1,7 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
. "server/common"
|
||||
. "battle_srv/common"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
@@ -1,8 +1,8 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
. "battle_srv/common"
|
||||
"fmt"
|
||||
. "server/common"
|
||||
|
||||
"github.com/go-redis/redis"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
|
@@ -1,16 +1,17 @@
|
||||
package ws
|
||||
|
||||
import (
|
||||
. "battle_srv/common"
|
||||
"battle_srv/models"
|
||||
pb "battle_srv/protos"
|
||||
"container/heap"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/gorilla/websocket"
|
||||
"go.uber.org/zap"
|
||||
"net"
|
||||
"net/http"
|
||||
. "server/common"
|
||||
"server/models"
|
||||
pb "server/pb_output"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -46,10 +47,20 @@ func Serve(c *gin.Context) {
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
Logger.Info("Finding PlayerLogin record for ws authentication:", zap.Any("intAuthToken", token))
|
||||
|
||||
boundRoomId := 0
|
||||
expectRoomId := 0
|
||||
expectedRoomId := 0
|
||||
speciesId := 0
|
||||
var err error
|
||||
if speciesIdStr, hasSpeciesId := c.GetQuery("speciesId"); hasSpeciesId {
|
||||
speciesId, err = strconv.Atoi(speciesIdStr)
|
||||
if err != nil {
|
||||
// TODO: Abort with specific message.
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if boundRoomIdStr, hasBoundRoomId := c.GetQuery("boundRoomId"); hasBoundRoomId {
|
||||
boundRoomId, err = strconv.Atoi(boundRoomIdStr)
|
||||
if err != nil {
|
||||
@@ -57,27 +68,28 @@ func Serve(c *gin.Context) {
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
Logger.Info("Finding PlayerLogin record for ws authentication:", zap.Any("intAuthToken", token), zap.Any("boundRoomId", boundRoomId))
|
||||
}
|
||||
if expectRoomIdStr, hasExpectRoomId := c.GetQuery("expectedRoomId"); hasExpectRoomId {
|
||||
expectRoomId, err = strconv.Atoi(expectRoomIdStr)
|
||||
Logger.Debug("Finding PlayerLogin record for ws authentication:", zap.Any("intAuthToken", token), zap.Any("boundRoomId", boundRoomId))
|
||||
} else if expectedRoomIdStr, hasExpectRoomId := c.GetQuery("expectedRoomId"); hasExpectRoomId {
|
||||
expectedRoomId, err = strconv.Atoi(expectedRoomIdStr)
|
||||
if err != nil {
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
Logger.Info("Finding PlayerLogin record for ws authentication:", zap.Any("intAuthToken", token), zap.Any("expectedRoomId", expectRoomId))
|
||||
Logger.Debug("Finding PlayerLogin record for ws authentication:", zap.Any("intAuthToken", token), zap.Any("expectedRoomId", expectedRoomId))
|
||||
} else {
|
||||
Logger.Debug("Finding PlayerLogin record for ws authentication:", zap.Any("intAuthToken", token))
|
||||
}
|
||||
|
||||
// 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.Info("PlayerLogin record not found for ws authentication:", zap.Any("intAuthToken", token))
|
||||
Logger.Warn("PlayerLogin record not found for ws authentication:", zap.Any("intAuthToken", token))
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
Logger.Info("PlayerLogin record has been found for ws authentication:", zap.Any("playerId", playerId))
|
||||
Logger.Info("PlayerLogin record has been found for ws authentication:", zap.Any("playerId", playerId), zap.Any("intAuthToken", token), zap.Any("boundRoomId", boundRoomId), zap.Any("expectedRoomId", expectedRoomId))
|
||||
|
||||
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
|
||||
if err != nil {
|
||||
@@ -104,7 +116,7 @@ func Serve(c *gin.Context) {
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
Logger.Warn("Recovered from: ", zap.Any("panic", r))
|
||||
Logger.Error("Recovered from: ", zap.Any("panic", r))
|
||||
}
|
||||
}()
|
||||
/**
|
||||
@@ -159,14 +171,14 @@ func Serve(c *gin.Context) {
|
||||
signalToCloseConnOfThisPlayer(Constants.RetCode.PlayerNotFound, "")
|
||||
}
|
||||
|
||||
Logger.Info("Player has logged in and its profile is found from persistent storage:", zap.Any("playerId", playerId), zap.Any("play", pPlayer))
|
||||
Logger.Debug("Player has logged in and its profile is found from persistent storage:", zap.Any("playerId", playerId), zap.Any("player", pPlayer))
|
||||
|
||||
// Find a room to join.
|
||||
Logger.Info("About to acquire RoomHeapMux for player:", zap.Any("playerId", playerId))
|
||||
Logger.Debug("About to acquire RoomHeapMux for player:", zap.Any("playerId", playerId))
|
||||
(*(models.RoomHeapMux)).Lock()
|
||||
defer func() {
|
||||
(*(models.RoomHeapMux)).Unlock()
|
||||
Logger.Info("Released RoomHeapMux for player:", zap.Any("playerId", playerId))
|
||||
Logger.Debug("Released RoomHeapMux for player:", zap.Any("playerId", playerId))
|
||||
}()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@@ -174,40 +186,35 @@ func Serve(c *gin.Context) {
|
||||
signalToCloseConnOfThisPlayer(Constants.RetCode.UnknownError, "")
|
||||
}
|
||||
}()
|
||||
Logger.Info("Acquired RoomHeapMux for player:", zap.Any("playerId", playerId))
|
||||
Logger.Debug("Acquired RoomHeapMux for player:", zap.Any("playerId", playerId))
|
||||
// Logger.Info("The RoomHeapManagerIns has:", zap.Any("addr", fmt.Sprintf("%p", models.RoomHeapManagerIns)), zap.Any("size", len(*(models.RoomHeapManagerIns))))
|
||||
playerSuccessfullyAddedToRoom := false
|
||||
playerRoomRelation := Constants.RetCode.UnknownError
|
||||
if 0 < boundRoomId {
|
||||
if tmpPRoom, existent := (*models.RoomMapManagerIns)[int32(boundRoomId)]; existent {
|
||||
pRoom = tmpPRoom
|
||||
Logger.Info("Successfully got:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forBoundRoomId", boundRoomId))
|
||||
res := pRoom.ReAddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer)
|
||||
if !res {
|
||||
playerRoomRelation = pRoom.ReAddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer)
|
||||
if Constants.RetCode.Ok != playerRoomRelation {
|
||||
Logger.Warn("Failed to get:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forBoundRoomId", boundRoomId))
|
||||
} else {
|
||||
playerSuccessfullyAddedToRoom = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if 0 < expectRoomId {
|
||||
if tmpRoom, existent := (*models.RoomMapManagerIns)[int32(expectRoomId)]; existent {
|
||||
} else if 0 < expectedRoomId {
|
||||
if tmpRoom, existent := (*models.RoomMapManagerIns)[int32(expectedRoomId)]; existent {
|
||||
pRoom = tmpRoom
|
||||
Logger.Info("Successfully got:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forExpectedRoomId", expectRoomId))
|
||||
|
||||
if pRoom.ReAddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer) {
|
||||
playerSuccessfullyAddedToRoom = true
|
||||
} else if pRoom.AddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer) {
|
||||
playerSuccessfullyAddedToRoom = true
|
||||
} else {
|
||||
Logger.Warn("Failed to get:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forExpectedRoomId", expectRoomId))
|
||||
playerSuccessfullyAddedToRoom = false
|
||||
playerRoomRelation = pRoom.ReAddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer)
|
||||
if Constants.RetCode.Ok != playerRoomRelation {
|
||||
playerRoomRelation = pRoom.AddPlayerIfPossible(pPlayer, speciesId, conn, signalToCloseConnOfThisPlayer)
|
||||
}
|
||||
if Constants.RetCode.Ok != playerRoomRelation {
|
||||
Logger.Warn("Failed to get:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Any("forExpectedRoomId", expectedRoomId))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if false == playerSuccessfullyAddedToRoom {
|
||||
if Constants.RetCode.SamePlayerAlreadyInSameRoom == playerRoomRelation {
|
||||
signalToCloseConnOfThisPlayer(playerRoomRelation, fmt.Sprintf("playerId == %v is already in a room, this account is possibly stolen!", playerId))
|
||||
}
|
||||
|
||||
if Constants.RetCode.Ok != playerRoomRelation {
|
||||
defer func() {
|
||||
if pRoom != nil {
|
||||
heap.Push(models.RoomHeapManagerIns, pRoom)
|
||||
@@ -220,10 +227,10 @@ func Serve(c *gin.Context) {
|
||||
signalToCloseConnOfThisPlayer(Constants.RetCode.LocallyNoAvailableRoom, fmt.Sprintf("Cannot pop a (*Room) for playerId == %v!", playerId))
|
||||
} else {
|
||||
pRoom = tmpRoom
|
||||
Logger.Info("Successfully popped:\n", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId))
|
||||
res := pRoom.AddPlayerIfPossible(pPlayer, conn, signalToCloseConnOfThisPlayer)
|
||||
if !res {
|
||||
signalToCloseConnOfThisPlayer(Constants.RetCode.PlayerNotAddableToRoom, fmt.Sprintf("AddPlayerIfPossible returns false for roomId == %v, playerId == %v!", pRoom.Id, playerId))
|
||||
Logger.Info("Successfully popped:\n", zap.Any("roomId", pRoom.Id), zap.Any("forPlayerId", playerId))
|
||||
playerRoomRelation = pRoom.AddPlayerIfPossible(pPlayer, speciesId, conn, signalToCloseConnOfThisPlayer)
|
||||
if Constants.RetCode.Ok != playerRoomRelation {
|
||||
signalToCloseConnOfThisPlayer(playerRoomRelation, fmt.Sprintf("AddPlayerIfPossible returns false for roomId == %v, playerId == %v!", pRoom.Id, playerId))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -244,35 +251,40 @@ func Serve(c *gin.Context) {
|
||||
|
||||
// Construct "battleColliderInfo" to downsync
|
||||
bciFrame := &pb.BattleColliderInfo{
|
||||
BoundRoomId: pRoom.Id,
|
||||
StageName: pRoom.StageName,
|
||||
StrToVec2DListMap: models.ToPbVec2DListMap(pRoom.RawBattleStrToVec2DListMap),
|
||||
StrToPolygon2DListMap: models.ToPbPolygon2DListMap(pRoom.RawBattleStrToPolygon2DListMap),
|
||||
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
|
||||
RollbackEstimatedDt: pRoom.RollbackEstimatedDt,
|
||||
RollbackEstimatedDtMillis: pRoom.RollbackEstimatedDtMillis,
|
||||
RollbackEstimatedDtNanos: pRoom.RollbackEstimatedDtNanos,
|
||||
|
||||
SpaceOffsetX: pRoom.SpaceOffsetX,
|
||||
SpaceOffsetY: pRoom.SpaceOffsetY,
|
||||
|
||||
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))
|
||||
@@ -354,7 +366,7 @@ func Serve(c *gin.Context) {
|
||||
receivingLoopAgainstPlayer := func() error {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
Logger.Warn("Goroutine `receivingLoopAgainstPlayer`, recovery spot#1, recovered from: ", zap.Any("panic", r))
|
||||
Logger.Error("Goroutine `receivingLoopAgainstPlayer`, recovery spot#1, recovered from: ", zap.Any("panic", r))
|
||||
}
|
||||
Logger.Info("Goroutine `receivingLoopAgainstPlayer` is stopped for:", zap.Any("playerId", playerId), zap.Any("roomId", pRoom.Id))
|
||||
}()
|
||||
@@ -363,10 +375,10 @@ func Serve(c *gin.Context) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Tries to receive from client-side in a non-blocking manner.
|
||||
// TODO: Is there any potential edge-trigger improvement like the epoll approach mentioned above for the following statement? See discussion in https://github.com/gorilla/websocket/issues/122
|
||||
_, bytes, err := conn.ReadMessage()
|
||||
if nil != err {
|
||||
Logger.Error("About to `signalToCloseConnOfThisPlayer`", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Error(err))
|
||||
Logger.Error("About to `signalToCloseConnOfThisPlayer` due to conn.ReadMessage err", zap.Any("roomId", pRoom.Id), zap.Any("playerId", playerId), zap.Error(err))
|
||||
signalToCloseConnOfThisPlayer(Constants.RetCode.UnknownError, "")
|
||||
return nil
|
||||
}
|
||||
@@ -385,7 +397,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 {
|
||||
@@ -402,3 +414,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)
|
||||
}
|
||||
|
BIN
charts/AttackTriggerCases.jpg
Normal file
After Width: | Height: | Size: 176 KiB |
BIN
charts/AvoidingFloatingPointAccumulationErr.jpg
Normal file
After Width: | Height: | Size: 144 KiB |
BIN
charts/How-to-play-1.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
charts/How-to-play-2.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
charts/How-to-play-3.png
Normal file
After Width: | Height: | Size: 92 KiB |
BIN
charts/How-to-play-4.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
charts/Merged_cut_annotated_spedup.gif
Normal file
After Width: | Height: | Size: 7.4 MiB |
BIN
charts/NativeBuildReload.png
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
charts/PackageNameIssueInCcc.png
Normal file
After Width: | Height: | Size: 135 KiB |
BIN
charts/Phone4g_battle_spedup.gif
Normal file
After Width: | Height: | Size: 22 MiB |
28
charts/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Double playback speed of a video
|
||||
```
|
||||
ffmpeg -i input.mp4 -filter:v "setpts=0.5*PTS" output.mp4
|
||||
```
|
||||
|
||||
# GIF creation cmd reference
|
||||
```
|
||||
ffmpeg -ss 12 -t 13 -i input.mp4 -vf "fps=10,scale=480:-1" -loop 0 output.gif
|
||||
```
|
||||
|
||||
# Extract GIF (with alpha channel, e.g. exported from Fighter Factory Studio) to PNG sequence
|
||||
```
|
||||
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
After Width: | Height: | Size: 79 KiB |
BIN
charts/UDPEssentials.jpg
Normal file
After Width: | Height: | Size: 472 KiB |
BIN
charts/VisualStudioSetup.png
Normal file
After Width: | Height: | Size: 191 KiB |
BIN
charts/networkstats.png
Normal file
After Width: | Height: | Size: 2.2 MiB |
Before Width: | Height: | Size: 430 KiB |
Before Width: | Height: | Size: 684 KiB |
@@ -2,10 +2,11 @@ PROJECTNAME=viscol.exe
|
||||
ROOT_DIR=.
|
||||
all: help
|
||||
## Available proxies for downloading go modules are listed in "https://github.com/golang/go/wiki/Modules#how-do-i-use-vendoring-with-modules-is-vendoring-going-away".
|
||||
GOPROXY=https://mirrors.aliyun.com/goproxy
|
||||
#GOPROXY=https://mirrors.aliyun.com/goproxy
|
||||
GOPROXY=https://goproxy.io
|
||||
|
||||
build:
|
||||
go build -o $(ROOT_DIR)/$(PROJECTNAME)
|
||||
GOPROXY=$(GOPROXY) go build -o $(ROOT_DIR)/$(PROJECTNAME)
|
||||
|
||||
run: build
|
||||
./$(PROJECTNAME)
|
||||
|
1
collider_visualizer/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This module is no longer useful, as we can now use GopherJs+OfflineMap to visualize experimental game dynamics.
|
@@ -2,8 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/solarlune/resolv"
|
||||
"image/color"
|
||||
"resolv"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@@ -1,27 +1,44 @@
|
||||
module viscol
|
||||
|
||||
go 1.19
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
jsexport v0.0.0
|
||||
dnmshared v0.0.0
|
||||
resolv v0.0.0
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
github.com/hajimehoshi/ebiten/v2 v2.4.7
|
||||
github.com/solarlune/resolv v0.5.1
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69
|
||||
dnmshared v0.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ebitengine/purego v0.0.0-20220905075623-aeed57cda744 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20220806181222-55e207c401ad // indirect
|
||||
github.com/hajimehoshi/file2byteslice v0.0.0-20210813153925-5340248a8f41 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jezek/xgb v1.0.1 // indirect
|
||||
github.com/kvartborg/vector v0.0.0-20200419093813-2cba0cabb4f0 // indirect
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86 // indirect
|
||||
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c // indirect
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/spf13/cobra v1.2.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.23.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 // indirect
|
||||
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105 // indirect
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
|
||||
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 // indirect
|
||||
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
)
|
||||
|
||||
replace dnmshared => ../dnmshared
|
||||
replace (
|
||||
dnmshared => ../dnmshared
|
||||
jsexport => ../jsexport
|
||||
resolv => ../resolv_tailored
|
||||
)
|
||||
|
@@ -1,12 +1,153 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/ebitengine/purego v0.0.0-20220905075623-aeed57cda744 h1:A8UnJ/5OKzki4HBDwoRQz7I6sxKsokpMXcGh+fUxpfc=
|
||||
github.com/ebitengine/purego v0.0.0-20220905075623-aeed57cda744/go.mod h1:Eh8I3yvknDYZeCuXH9kRNaPuHEwvXDCk378o9xszmHg=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20220806181222-55e207c401ad h1:kX51IjbsJPCvzV9jUoVQG9GEUqIq5hjfYzXTqQ52Rh8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20220806181222-55e207c401ad/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
|
||||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||
github.com/gopherjs/gopherjs v1.18.0-beta1 h1:IbykhVEq4SAjwyBRuNHl0aOO6w6IqgL3RUdMhoBo4mY=
|
||||
github.com/gopherjs/gopherjs v1.18.0-beta1/go.mod h1:6UY8PXRnu51MqjYCCY4toG0S5GeH5uVJ3qDxIsa+kqo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hajimehoshi/bitmapfont/v2 v2.2.1 h1:y7zcy02/UgO24IL3COqYtrRZzhRucNBtmCo/SNU648k=
|
||||
github.com/hajimehoshi/bitmapfont/v2 v2.2.1/go.mod h1:wjrYAy8vKgj9JsFgnYAOK346/uvE22TlmqouzdnYIs0=
|
||||
github.com/hajimehoshi/ebiten/v2 v2.4.7 h1:XuvB7R0Rbw/O7g6vNU8gqr5b9e7MNhhAONMSsyreLDI=
|
||||
@@ -16,63 +157,292 @@ github.com/hajimehoshi/file2byteslice v0.0.0-20210813153925-5340248a8f41/go.mod
|
||||
github.com/hajimehoshi/go-mp3 v0.3.3/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
|
||||
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||
github.com/hajimehoshi/oto/v2 v2.3.1/go.mod h1:seWLbgHH7AyUMYKfKYT9pg7PhUu9/SisyJvNTT+ASQo=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jakecoffman/cp v1.2.1/go.mod h1:JjY/Fp6d8E1CHnu74gWNnU0+b9VzEdUVPoJxg2PsTQg=
|
||||
github.com/jezek/xgb v1.0.1 h1:YUGhxps0aR7J2Xplbs23OHnV1mWaxFVcOl9b+1RQkt8=
|
||||
github.com/jezek/xgb v1.0.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
|
||||
github.com/jfreymuth/oggvorbis v1.0.4/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII=
|
||||
github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kvartborg/vector v0.0.0-20200419093813-2cba0cabb4f0 h1:v8lWpj5957KtDMKu+xQtlu6G3ZoZR6Tn9bsfZCRG5Xw=
|
||||
github.com/kvartborg/vector v0.0.0-20200419093813-2cba0cabb4f0/go.mod h1:GAX7tMJqXx9fB1BrsTWPOXy6IBRX+J461BffVPAdpwo=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86 h1:D6paGObi5Wud7xg83MaEFyjxQB1W5bz5d0IFppr+ymk=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c h1:bY6ktFuJkt+ZXkX0RChQch2FtHpWQLVS8Qo1YasiIVk=
|
||||
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk=
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/solarlune/resolv v0.5.1 h1:Ul6PAs/zaxiMUOEYz1Z6VeUj5k3CDcWMvSh+kivybDY=
|
||||
github.com/solarlune/resolv v0.5.1/go.mod h1:HjM2f/0NoVjVdZsi26GtugX5aFbA62COEFEXkOhveRw=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
|
||||
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY=
|
||||
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105 h1:3vUV5x5+3LfQbgk7paCM6INOaJG9xXQbn79xoNkwfIk=
|
||||
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -81,16 +451,200 @@ golang.org/x/sys v0.0.0-20220818161305-2296e01440c6 h1:Sx/u41w+OwrInGdEckYmEuU5g
|
||||
golang.org/x/sys v0.0.0-20220818161305-2296e01440c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8=
|
||||
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
@@ -11,13 +11,13 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
"github.com/hajimehoshi/ebiten/v2/text"
|
||||
"github.com/solarlune/resolv"
|
||||
"golang.org/x/image/font"
|
||||
|
||||
"encoding/xml"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"resolv"
|
||||
|
||||
. "dnmshared"
|
||||
)
|
||||
@@ -85,8 +85,9 @@ type Game struct {
|
||||
|
||||
func NewGame() *Game {
|
||||
|
||||
stageName := "simple" // Use this for calibration
|
||||
// stageName := "simple" // Use this for calibration in isometric orientation
|
||||
// stageName := "richsoil"
|
||||
stageName := "dungeon"
|
||||
stageDiscreteW, stageDiscreteH, stageTileW, stageTileH, playerPosMap, barrierMap, err := parseStage(stageName)
|
||||
if nil != err {
|
||||
panic(err)
|
||||
|
@@ -4,9 +4,10 @@ import (
|
||||
. "dnmshared"
|
||||
"fmt"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/solarlune/resolv"
|
||||
"go.uber.org/zap"
|
||||
"image/color"
|
||||
. "jsexport/battle"
|
||||
"resolv"
|
||||
)
|
||||
|
||||
type WorldColliderDisplay struct {
|
||||
@@ -19,7 +20,7 @@ func (world *WorldColliderDisplay) Init() {
|
||||
|
||||
func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTileW, stageTileH int32, playerPosMap StrToVec2DListMap, barrierMap StrToPolygon2DListMap) *WorldColliderDisplay {
|
||||
|
||||
playerList := *(playerPosMap["PlayerStartingPos"])
|
||||
playerPosList := *(playerPosMap["PlayerStartingPos"])
|
||||
barrierList := *(barrierMap["Barrier"])
|
||||
|
||||
world := &WorldColliderDisplay{Game: game}
|
||||
@@ -32,20 +33,27 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
|
||||
spaceOffsetX := float64(spaceW) * 0.5
|
||||
spaceOffsetY := float64(spaceH) * 0.5
|
||||
|
||||
playerColliderRadius := float64(32)
|
||||
playerColliders := make([]*resolv.Object, len(playerList))
|
||||
space := resolv.NewSpace(int(spaceW), int(spaceH), 16, 16)
|
||||
for i, player := range playerList {
|
||||
playerCollider := GenerateRectCollider(player.X, player.Y, playerColliderRadius*2, playerColliderRadius*2, spaceOffsetX, spaceOffsetY, "Player") // [WARNING] Deliberately not using a circle because "resolv v0.5.1" doesn't yet align circle center with space cell center, regardless of the "specified within-object offset"
|
||||
Logger.Info(fmt.Sprintf("Player Collider#%d: player.X=%v, player.Y=%v, radius=%v, spaceOffsetX=%v, spaceOffsetY=%v, shape=%v; calibrationCheckX=player.X-radius+spaceOffsetX=%v", i, player.X, player.Y, playerColliderRadius, spaceOffsetX, spaceOffsetY, playerCollider.Shape, player.X-playerColliderRadius+spaceOffsetX))
|
||||
worldToVirtualGridRatio := float64(1000)
|
||||
virtualGridToWorldRatio := float64(1) / worldToVirtualGridRatio
|
||||
playerDefaultSpeed := 1 * worldToVirtualGridRatio
|
||||
minStep := (int(float64(playerDefaultSpeed)*virtualGridToWorldRatio) << 3)
|
||||
playerColliderRadius := float64(12)
|
||||
playerColliders := make([]*resolv.Object, len(playerPosList))
|
||||
snapIntoPlatformOverlap := float64(0.1)
|
||||
space := resolv.NewSpace(int(spaceW), int(spaceH), minStep, minStep)
|
||||
topPadding, bottomPadding, leftPadding, rightPadding := snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap, snapIntoPlatformOverlap
|
||||
for i, playerPos := range playerPosList {
|
||||
colliderWidth, colliderHeight := playerColliderRadius*2, playerColliderRadius*4
|
||||
playerCollider := GenerateRectCollider(playerPos.X, playerPos.Y, colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, nil, fmt.Sprintf("Player%d", i+1)) // [WARNING] Deliberately not using a circle because "resolv v0.5.1" doesn't yet align circle center with space cell center, regardless of the "specified within-object offset"
|
||||
Logger.Info(fmt.Sprintf("Player Collider#%d: player world pos=(%.2f, %.2f), shape=%v", i, playerPos.X, playerPos.Y, ConvexPolygonStr(playerCollider.Shape.(*resolv.ConvexPolygon))))
|
||||
playerColliders[i] = playerCollider
|
||||
space.Add(playerCollider)
|
||||
}
|
||||
|
||||
barrierLocalId := 0
|
||||
for _, barrierUnaligned := range barrierList {
|
||||
barrierCollider := GenerateConvexPolygonCollider(barrierUnaligned, spaceOffsetX, spaceOffsetY, "Barrier")
|
||||
Logger.Info(fmt.Sprintf("Added barrier: shape=%v", barrierCollider.Shape))
|
||||
barrierCollider := GenerateConvexPolygonCollider(barrierUnaligned, spaceOffsetX, spaceOffsetY, nil, "Barrier")
|
||||
Logger.Debug(fmt.Sprintf("Added barrier: shape=%v", ConvexPolygonStr(barrierCollider.Shape.(*resolv.ConvexPolygon))))
|
||||
space.Add(barrierCollider)
|
||||
barrierLocalId++
|
||||
}
|
||||
@@ -54,24 +62,97 @@ func NewWorldColliderDisplay(game *Game, stageDiscreteW, stageDiscreteH, stageTi
|
||||
|
||||
moveToCollide := true
|
||||
if moveToCollide {
|
||||
toTestPlayerCollider := playerColliders[0]
|
||||
oldDx, oldDy := -2.98, -50.0
|
||||
dx, dy := oldDx, oldDy
|
||||
if collision := toTestPlayerCollider.Check(oldDx, oldDy, "Barrier"); collision != nil {
|
||||
effPushback := Vec2D{X: float64(0), Y: float64(0)}
|
||||
colliderWidth, colliderHeight := playerColliderRadius*2, playerColliderRadius*4
|
||||
playerColliders[0].X, playerColliders[0].Y = VirtualGridToPolygonColliderBLPos(int32(-139000), int32(-474500), colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, virtualGridToWorldRatio)
|
||||
playerColliders[0].Update()
|
||||
|
||||
playerColliders[1].X, playerColliders[1].Y = VirtualGridToPolygonColliderBLPos(int32(-163000), int32(-520000), colliderWidth, colliderHeight, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, virtualGridToWorldRatio)
|
||||
playerColliders[1].Update()
|
||||
|
||||
toTestPlayerCollider := playerColliders[1]
|
||||
if collision := toTestPlayerCollider.Check(0, 0); collision != nil {
|
||||
playerShape := toTestPlayerCollider.Shape.(*resolv.ConvexPolygon)
|
||||
barrierShape := collision.Objects[0].Shape.(*resolv.ConvexPolygon)
|
||||
if overlapped, pushbackX, pushbackY := CalcPushbacks(oldDx, oldDy, playerShape, barrierShape); overlapped {
|
||||
Logger.Info(fmt.Sprintf("Collided & overlapped: player.X=%v, player.Y=%v, oldDx=%v, oldDy=%v, playerShape=%v, toCheckBarrier=%v, pushbackX=%v, pushbackY=%v", toTestPlayerCollider.X, toTestPlayerCollider.Y, oldDx, oldDy, ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape), pushbackX, pushbackY))
|
||||
dx -= pushbackX
|
||||
dy -= pushbackY
|
||||
} else {
|
||||
Logger.Info(fmt.Sprintf("Collider BUT not overlapped: player.X=%v, player.Y=%v, oldDx=%v, oldDy=%v, playerShape=%v, toCheckBarrier=%v", toTestPlayerCollider.X, toTestPlayerCollider.Y, oldDx, oldDy, ConvexPolygonStr(playerShape), ConvexPolygonStr(barrierShape)))
|
||||
for _, obj := range collision.Objects {
|
||||
bShape := obj.Shape.(*resolv.ConvexPolygon)
|
||||
Logger.Warn(fmt.Sprintf("Checking potential: a=%v, b=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(bShape)))
|
||||
if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, playerShape, bShape); overlapped {
|
||||
Logger.Warn(fmt.Sprintf("Overlapped: a=%v, b=%v, pushbackX=%v, pushbackY=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(bShape), pushbackX, pushbackY))
|
||||
effPushback.X += pushbackX
|
||||
effPushback.Y += pushbackY
|
||||
} else {
|
||||
Logger.Warn(fmt.Sprintf("Collided BUT not overlapped: a=%v, b=%v, overlapResult=%v", ConvexPolygonStr(playerShape), ConvexPolygonStr(bShape), overlapResult))
|
||||
}
|
||||
}
|
||||
//toTestPlayerCollider.X -= effPushback.X
|
||||
//toTestPlayerCollider.Y -= effPushback.Y
|
||||
//toTestPlayerCollider.Update()
|
||||
Logger.Info(fmt.Sprintf("effPushback={%v, %v}", effPushback.X, effPushback.Y))
|
||||
}
|
||||
}
|
||||
meleeBullet := &MeleeBullet{
|
||||
// for offender
|
||||
StartupFrames: int32(18),
|
||||
ActiveFrames: int32(1),
|
||||
RecoveryFrames: int32(61),
|
||||
RecoveryFramesOnBlock: int32(61),
|
||||
RecoveryFramesOnHit: int32(61),
|
||||
SelfMoveforwardX: 0,
|
||||
SelfMoveforwardY: 0,
|
||||
HitboxOffset: float64(24.0),
|
||||
HitboxSizeX: float64(45.0),
|
||||
HitboxSizeY: float64(32.0),
|
||||
|
||||
// for defender
|
||||
HitStunFrames: int32(18),
|
||||
BlockStunFrames: int32(9),
|
||||
Pushback: float64(22.0),
|
||||
ReleaseTriggerType: int32(1), // 1: rising-edge, 2: falling-edge
|
||||
Damage: int32(5),
|
||||
}
|
||||
bulletLeftToRight := false
|
||||
if bulletLeftToRight {
|
||||
xfac := float64(1.0)
|
||||
offenderWx, offenderWy := playerPosList[0].X, playerPosList[0].Y
|
||||
bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
|
||||
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSizeX, meleeBullet.HitboxSizeY, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, nil, "MeleeBullet")
|
||||
space.Add(newBulletCollider)
|
||||
bulletShape := newBulletCollider.Shape.(*resolv.ConvexPolygon)
|
||||
Logger.Warn(fmt.Sprintf("bullet ->: Added bullet collider to space: a=%v", ConvexPolygonStr(bulletShape)))
|
||||
|
||||
if collision := newBulletCollider.Check(0, 0); collision != nil {
|
||||
for _, obj := range collision.Objects {
|
||||
objShape := obj.Shape.(*resolv.ConvexPolygon)
|
||||
if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, bulletShape, objShape); overlapped {
|
||||
Logger.Warn(fmt.Sprintf("bullet ->: Overlapped: a=%v, b=%v, pushbackX=%v, pushbackY=%v", ConvexPolygonStr(bulletShape), ConvexPolygonStr(objShape), pushbackX, pushbackY))
|
||||
} else {
|
||||
Logger.Warn(fmt.Sprintf("bullet ->: Collided BUT not overlapped: a=%v, b=%v, overlapResult=%v", ConvexPolygonStr(bulletShape), ConvexPolygonStr(objShape), overlapResult))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toTestPlayerCollider.X += dx
|
||||
toTestPlayerCollider.Y += dy
|
||||
toTestPlayerCollider.Update()
|
||||
bulletRightToLeft := false
|
||||
if bulletRightToLeft {
|
||||
xfac := float64(-1.0)
|
||||
offenderWx, offenderWy := playerPosList[1].X, playerPosList[1].Y
|
||||
bulletWx, bulletWy := offenderWx+xfac*meleeBullet.HitboxOffset, offenderWy
|
||||
|
||||
newBulletCollider := GenerateRectCollider(bulletWx, bulletWy, meleeBullet.HitboxSizeX, meleeBullet.HitboxSizeY, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY, nil, "MeleeBullet")
|
||||
space.Add(newBulletCollider)
|
||||
bulletShape := newBulletCollider.Shape.(*resolv.ConvexPolygon)
|
||||
Logger.Warn(fmt.Sprintf("bullet <-: Added bullet collider to space: a=%v", ConvexPolygonStr(bulletShape)))
|
||||
|
||||
if collision := newBulletCollider.Check(0, 0); collision != nil {
|
||||
for _, obj := range collision.Objects {
|
||||
objShape := obj.Shape.(*resolv.ConvexPolygon)
|
||||
if overlapped, pushbackX, pushbackY, overlapResult := CalcPushbacks(0, 0, bulletShape, objShape); overlapped {
|
||||
Logger.Warn(fmt.Sprintf("bullet <-: Overlapped: a=%v, b=%v, pushbackX=%v, pushbackY=%v", ConvexPolygonStr(bulletShape), ConvexPolygonStr(objShape), pushbackX, pushbackY))
|
||||
} else {
|
||||
Logger.Warn(fmt.Sprintf("bullet <-: Collided BUT not overlapped: a=%v, b=%v, overlapResult=%v", ConvexPolygonStr(bulletShape), ConvexPolygonStr(objShape), overlapResult))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return world
|
||||
@@ -84,8 +165,14 @@ func (world *WorldColliderDisplay) Update() {
|
||||
func (world *WorldColliderDisplay) Draw(screen *ebiten.Image) {
|
||||
|
||||
for _, o := range world.Space.Objects() {
|
||||
if o.HasTags("Player") {
|
||||
drawColor := color.RGBA{0, 255, 0, 255}
|
||||
if o.HasTags("Player1") {
|
||||
drawColor := color.RGBA{255, 0, 0, 255}
|
||||
DrawPolygon(screen, o.Shape.(*resolv.ConvexPolygon), drawColor)
|
||||
} else if o.HasTags("Player2") {
|
||||
drawColor := color.RGBA{0, 0, 255, 255}
|
||||
DrawPolygon(screen, o.Shape.(*resolv.ConvexPolygon), drawColor)
|
||||
} else if o.HasTags("MeleeBullet") {
|
||||
drawColor := color.RGBA{78, 255, 112, 255}
|
||||
DrawPolygon(screen, o.Shape.(*resolv.ConvexPolygon), drawColor)
|
||||
} else {
|
||||
drawColor := color.RGBA{60, 60, 60, 255}
|
||||
@@ -93,7 +180,7 @@ func (world *WorldColliderDisplay) Draw(screen *ebiten.Image) {
|
||||
}
|
||||
}
|
||||
|
||||
world.Game.DebugDraw(screen, world.Space)
|
||||
//world.Game.DebugDraw(screen, world.Space)
|
||||
|
||||
if world.Game.ShowHelpText {
|
||||
|
||||
|
@@ -1,51 +0,0 @@
|
||||
package dnmshared
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// Use type `float64` for json unmarshalling of numbers.
|
||||
type Direction struct {
|
||||
Dx int32 `json:"dx,omitempty"`
|
||||
Dy int32 `json:"dy,omitempty"`
|
||||
}
|
||||
|
||||
type Vec2D struct {
|
||||
X float64 `json:"x,omitempty"`
|
||||
Y float64 `json:"y,omitempty"`
|
||||
}
|
||||
|
||||
func NormVec2D(dx, dy float64) Vec2D {
|
||||
return Vec2D{dy, -dx}
|
||||
}
|
||||
|
||||
type Polygon2D struct {
|
||||
Anchor *Vec2D `json:"-"` // This "Polygon2D.Anchor" is used to be assigned to "B2BodyDef.Position", which in turn is used as the position of the FIRST POINT of the polygon.
|
||||
Points []*Vec2D `json:"-"`
|
||||
|
||||
/*
|
||||
When used to represent a "polyline directly drawn in a `Tmx file`", we can initialize both "Anchor" and "Points" simultaneously.
|
||||
|
||||
Yet when used to represent a "polyline drawn in a `Tsx file`", we have to first initialize "Points w.r.t. center of the tile-rectangle", and then "Anchor(initially nil) of the tile positioned in the `Tmx file`".
|
||||
|
||||
Refer to https://shimo.im/docs/SmLJJhXm2C8XMzZT for more information.
|
||||
*/
|
||||
|
||||
/*
|
||||
[WARNING] Used to cache "`TileWidth & TileHeight` of a Tsx file" only.
|
||||
*/
|
||||
TileWidth int
|
||||
TileHeight int
|
||||
|
||||
/*
|
||||
[WARNING] Used to cache "`Width & TileHeight` of an object in Tmx file" only.
|
||||
*/
|
||||
TmxObjectWidth float64
|
||||
TmxObjectHeight float64
|
||||
}
|
||||
|
||||
func Distance(pt1 *Vec2D, pt2 *Vec2D) float64 {
|
||||
dx := pt1.X - pt2.X
|
||||
dy := pt1.Y - pt2.Y
|
||||
return math.Sqrt(dx*dx + dy*dy)
|
||||
}
|
@@ -1,3 +1,13 @@
|
||||
module tiled
|
||||
module dnmshared
|
||||
|
||||
go 1.19
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
resolv v0.0.0
|
||||
jsexport v0.0.0
|
||||
)
|
||||
|
||||
replace (
|
||||
resolv => ../resolv_tailored
|
||||
jsexport => ../jsexport
|
||||
)
|
||||
|
@@ -2,219 +2,25 @@ package dnmshared
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/kvartborg/vector"
|
||||
"github.com/solarlune/resolv"
|
||||
"math"
|
||||
. "jsexport/battle"
|
||||
"resolv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func NormVec2D(dx, dy float64) Vec2D {
|
||||
return Vec2D{X: dy, Y: -dx}
|
||||
}
|
||||
|
||||
func ConvexPolygonStr(body *resolv.ConvexPolygon) string {
|
||||
var s []string = make([]string, len(body.Points))
|
||||
for i, p := range body.Points {
|
||||
s[i] = fmt.Sprintf("[%v, %v]", p[0]+body.X, p[1]+body.Y)
|
||||
var s []string = make([]string, body.Points.Cnt)
|
||||
for i := int32(0); i < body.Points.Cnt; i++ {
|
||||
p := body.GetPointByOffset(i)
|
||||
s[i] = fmt.Sprintf("[%.2f, %.2f]", p[0]+body.X, p[1]+body.Y)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("[%s]", strings.Join(s, ", "))
|
||||
return fmt.Sprintf("{\n%s\n}", strings.Join(s, ",\n"))
|
||||
}
|
||||
|
||||
func GenerateRectCollider(origX, origY, w, h, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object {
|
||||
collider := resolv.NewObject(origX-w*0.5+spaceOffsetX, origY-h*0.5+spaceOffsetY, w, h, tag)
|
||||
shape := resolv.NewRectangle(0, 0, w, h)
|
||||
collider.SetShape(shape)
|
||||
return collider
|
||||
}
|
||||
|
||||
func GenerateConvexPolygonCollider(unalignedSrc *Polygon2D, spaceOffsetX, spaceOffsetY float64, tag string) *resolv.Object {
|
||||
aligned := AlignPolygon2DToBoundingBox(unalignedSrc)
|
||||
var w, h float64 = 0, 0
|
||||
|
||||
shape := resolv.NewConvexPolygon()
|
||||
for i, pi := range aligned.Points {
|
||||
for j, pj := range aligned.Points {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
if math.Abs(pj.X-pi.X) > w {
|
||||
w = math.Abs(pj.X - pi.X)
|
||||
}
|
||||
if math.Abs(pj.Y-pi.Y) > h {
|
||||
h = math.Abs(pj.Y - pi.Y)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(aligned.Points); i++ {
|
||||
p := aligned.Points[i]
|
||||
shape.AddPoints(p.X, p.Y)
|
||||
}
|
||||
|
||||
collider := resolv.NewObject(aligned.Anchor.X+spaceOffsetX, aligned.Anchor.Y+spaceOffsetY, w, h, tag)
|
||||
collider.SetShape(shape)
|
||||
|
||||
return collider
|
||||
}
|
||||
|
||||
func CalcPushbacks(oldDx, oldDy float64, playerShape, barrierShape *resolv.ConvexPolygon) (bool, float64, float64) {
|
||||
origX, origY := playerShape.Position()
|
||||
defer func() {
|
||||
playerShape.SetPosition(origX, origY)
|
||||
}()
|
||||
playerShape.SetPosition(origX+oldDx, origY+oldDy)
|
||||
overlapResult := &SatResult{
|
||||
Overlap: 0,
|
||||
OverlapX: 0,
|
||||
OverlapY: 0,
|
||||
AContainedInB: true,
|
||||
BContainedInA: true,
|
||||
Axis: vector.Vector{0, 0},
|
||||
}
|
||||
if overlapped := IsPolygonPairOverlapped(playerShape, barrierShape, overlapResult); overlapped {
|
||||
pushbackX, pushbackY := overlapResult.Overlap*overlapResult.OverlapX, overlapResult.Overlap*overlapResult.OverlapY
|
||||
return true, pushbackX, pushbackY
|
||||
} else {
|
||||
return false, 0, 0
|
||||
}
|
||||
}
|
||||
|
||||
type SatResult struct {
|
||||
Overlap float64
|
||||
OverlapX float64
|
||||
OverlapY float64
|
||||
AContainedInB bool
|
||||
BContainedInA bool
|
||||
Axis vector.Vector
|
||||
}
|
||||
|
||||
func IsPolygonPairOverlapped(a, b *resolv.ConvexPolygon, result *SatResult) bool {
|
||||
aCnt, bCnt := len(a.Points), len(b.Points)
|
||||
// Single point case
|
||||
if 1 == aCnt && 1 == bCnt {
|
||||
if nil != result {
|
||||
result.Overlap = 0
|
||||
}
|
||||
return a.Points[0].X() == b.Points[0].X() && a.Points[0].Y() == b.Points[0].Y()
|
||||
}
|
||||
|
||||
if 1 < aCnt {
|
||||
for _, axis := range a.SATAxes() {
|
||||
if isPolygonPairSeparatedByDir(a, b, axis.Unit(), result) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if 1 < bCnt {
|
||||
for _, axis := range b.SATAxes() {
|
||||
if isPolygonPairSeparatedByDir(a, b, axis.Unit(), result) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func isPolygonPairSeparatedByDir(a, b *resolv.ConvexPolygon, e vector.Vector, result *SatResult) bool {
|
||||
/*
|
||||
[WARNING] This function is deliberately made private, it shouldn't be used alone (i.e. not along the norms of a polygon), otherwise the pushbacks calculated would be meaningless.
|
||||
|
||||
Consider the following example
|
||||
a: {
|
||||
anchor: [1337.19 1696.74]
|
||||
points: [[0 0] [24 0] [24 24] [0 24]]
|
||||
},
|
||||
b: {
|
||||
anchor: [1277.72 1570.56]
|
||||
points: [[642.57 319.16] [0 319.16] [5.73 0] [643.75 0.90]]
|
||||
}
|
||||
|
||||
e = (-2.98, 1.49).Unit()
|
||||
*/
|
||||
|
||||
var aStart, aEnd, bStart, bEnd float64 = math.MaxFloat64, -math.MaxFloat64, math.MaxFloat64, -math.MaxFloat64
|
||||
for _, p := range a.Points {
|
||||
dot := (p.X()+a.X)*e.X() + (p.Y()+a.Y)*e.Y()
|
||||
|
||||
if aStart > dot {
|
||||
aStart = dot
|
||||
}
|
||||
|
||||
if aEnd < dot {
|
||||
aEnd = dot
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range b.Points {
|
||||
dot := (p.X()+b.X)*e.X() + (p.Y()+b.Y)*e.Y()
|
||||
|
||||
if bStart > dot {
|
||||
bStart = dot
|
||||
}
|
||||
|
||||
if bEnd < dot {
|
||||
bEnd = dot
|
||||
}
|
||||
}
|
||||
|
||||
if aStart > bEnd || aEnd < bStart {
|
||||
// Separated by unit vector "e"
|
||||
return true
|
||||
}
|
||||
|
||||
if nil != result {
|
||||
result.Axis = e
|
||||
overlap := float64(0)
|
||||
|
||||
if aStart < bStart {
|
||||
result.AContainedInB = false
|
||||
|
||||
if aEnd < bEnd {
|
||||
overlap = aEnd - bStart
|
||||
result.BContainedInA = false
|
||||
} else {
|
||||
option1 := aEnd - bStart
|
||||
option2 := bEnd - aStart
|
||||
if option1 < option2 {
|
||||
overlap = option1
|
||||
} else {
|
||||
overlap = -option2
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result.BContainedInA = false
|
||||
|
||||
if aEnd > bEnd {
|
||||
overlap = aStart - bEnd
|
||||
result.AContainedInB = false
|
||||
} else {
|
||||
option1 := aEnd - bStart
|
||||
option2 := bEnd - aStart
|
||||
if option1 < option2 {
|
||||
overlap = option1
|
||||
} else {
|
||||
overlap = -option2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentOverlap := result.Overlap
|
||||
absoluteOverlap := overlap
|
||||
if overlap < 0 {
|
||||
absoluteOverlap = -overlap
|
||||
}
|
||||
|
||||
if 0 == currentOverlap || currentOverlap > absoluteOverlap {
|
||||
var sign float64 = 1
|
||||
if overlap < 0 {
|
||||
sign = -1
|
||||
}
|
||||
|
||||
result.Overlap = absoluteOverlap
|
||||
result.OverlapX = e.X() * sign
|
||||
result.OverlapY = e.Y() * sign
|
||||
}
|
||||
}
|
||||
|
||||
// the specified unit vector "e" doesn't separate "a" and "b", overlap result is generated
|
||||
return false
|
||||
func RectCenterStr(body *resolv.Object, halfBoundingW, halfBoundingH, topPadding, bottomPadding, leftPadding, rightPadding, spaceOffsetX, spaceOffsetY float64) string {
|
||||
return fmt.Sprintf("{%.2f, %.2f}", body.X+leftPadding+halfBoundingW-spaceOffsetX, body.Y+bottomPadding+halfBoundingH-spaceOffsetY)
|
||||
}
|
||||
|
427
dnmshared/sharedprotos/geometry.pb.go
Normal file
@@ -0,0 +1,427 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.1
|
||||
// protoc v3.21.4
|
||||
// source: geometry.proto
|
||||
|
||||
package sharedprotos
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Direction struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Dx int32 `protobuf:"varint,1,opt,name=dx,proto3" json:"dx,omitempty"`
|
||||
Dy int32 `protobuf:"varint,2,opt,name=dy,proto3" json:"dy,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Direction) Reset() {
|
||||
*x = Direction{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_geometry_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Direction) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Direction) ProtoMessage() {}
|
||||
|
||||
func (x *Direction) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_geometry_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Direction.ProtoReflect.Descriptor instead.
|
||||
func (*Direction) Descriptor() ([]byte, []int) {
|
||||
return file_geometry_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Direction) GetDx() int32 {
|
||||
if x != nil {
|
||||
return x.Dx
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Direction) GetDy() int32 {
|
||||
if x != nil {
|
||||
return x.Dy
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Vec2D struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
X float64 `protobuf:"fixed64,1,opt,name=x,proto3" json:"x,omitempty"`
|
||||
Y float64 `protobuf:"fixed64,2,opt,name=y,proto3" json:"y,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Vec2D) Reset() {
|
||||
*x = Vec2D{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_geometry_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Vec2D) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Vec2D) ProtoMessage() {}
|
||||
|
||||
func (x *Vec2D) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_geometry_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Vec2D.ProtoReflect.Descriptor instead.
|
||||
func (*Vec2D) Descriptor() ([]byte, []int) {
|
||||
return file_geometry_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Vec2D) GetX() float64 {
|
||||
if x != nil {
|
||||
return x.X
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Vec2D) GetY() float64 {
|
||||
if x != nil {
|
||||
return x.Y
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type Polygon2D struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Anchor *Vec2D `protobuf:"bytes,1,opt,name=anchor,proto3" json:"anchor,omitempty"`
|
||||
Points []*Vec2D `protobuf:"bytes,2,rep,name=points,proto3" json:"points,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Polygon2D) Reset() {
|
||||
*x = Polygon2D{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_geometry_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Polygon2D) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Polygon2D) ProtoMessage() {}
|
||||
|
||||
func (x *Polygon2D) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_geometry_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Polygon2D.ProtoReflect.Descriptor instead.
|
||||
func (*Polygon2D) Descriptor() ([]byte, []int) {
|
||||
return file_geometry_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *Polygon2D) GetAnchor() *Vec2D {
|
||||
if x != nil {
|
||||
return x.Anchor
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Polygon2D) GetPoints() []*Vec2D {
|
||||
if x != nil {
|
||||
return x.Points
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Vec2DList struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Eles []*Vec2D `protobuf:"bytes,1,rep,name=eles,proto3" json:"eles,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Vec2DList) Reset() {
|
||||
*x = Vec2DList{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_geometry_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Vec2DList) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Vec2DList) ProtoMessage() {}
|
||||
|
||||
func (x *Vec2DList) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_geometry_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Vec2DList.ProtoReflect.Descriptor instead.
|
||||
func (*Vec2DList) Descriptor() ([]byte, []int) {
|
||||
return file_geometry_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *Vec2DList) GetEles() []*Vec2D {
|
||||
if x != nil {
|
||||
return x.Eles
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Polygon2DList struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Eles []*Polygon2D `protobuf:"bytes,1,rep,name=eles,proto3" json:"eles,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Polygon2DList) Reset() {
|
||||
*x = Polygon2DList{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_geometry_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Polygon2DList) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Polygon2DList) ProtoMessage() {}
|
||||
|
||||
func (x *Polygon2DList) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_geometry_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Polygon2DList.ProtoReflect.Descriptor instead.
|
||||
func (*Polygon2DList) Descriptor() ([]byte, []int) {
|
||||
return file_geometry_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *Polygon2DList) GetEles() []*Polygon2D {
|
||||
if x != nil {
|
||||
return x.Eles
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_geometry_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_geometry_proto_rawDesc = []byte{
|
||||
0x0a, 0x0e, 0x67, 0x65, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x12, 0x0c, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x22, 0x2b,
|
||||
0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x64,
|
||||
0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x78, 0x12, 0x0e, 0x0a, 0x02, 0x64,
|
||||
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x64, 0x79, 0x22, 0x23, 0x0a, 0x05, 0x56,
|
||||
0x65, 0x63, 0x32, 0x44, 0x12, 0x0c, 0x0a, 0x01, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52,
|
||||
0x01, 0x78, 0x12, 0x0c, 0x0a, 0x01, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x01, 0x79,
|
||||
0x22, 0x65, 0x0a, 0x09, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44, 0x12, 0x2b, 0x0a,
|
||||
0x06, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e,
|
||||
0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x56, 0x65, 0x63,
|
||||
0x32, 0x44, 0x52, 0x06, 0x61, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x12, 0x2b, 0x0a, 0x06, 0x70, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x68, 0x61,
|
||||
0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x56, 0x65, 0x63, 0x32, 0x44, 0x52,
|
||||
0x06, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0x34, 0x0a, 0x09, 0x56, 0x65, 0x63, 0x32, 0x44,
|
||||
0x4c, 0x69, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x04, 0x65, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x73, 0x2e, 0x56, 0x65, 0x63, 0x32, 0x44, 0x52, 0x04, 0x65, 0x6c, 0x65, 0x73, 0x22, 0x3c, 0x0a,
|
||||
0x0d, 0x50, 0x6f, 0x6c, 0x79, 0x67, 0x6f, 0x6e, 0x32, 0x44, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2b,
|
||||
0x0a, 0x04, 0x65, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73,
|
||||
0x68, 0x61, 0x72, 0x65, 0x64, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x50, 0x6f, 0x6c, 0x79,
|
||||
0x67, 0x6f, 0x6e, 0x32, 0x44, 0x52, 0x04, 0x65, 0x6c, 0x65, 0x73, 0x42, 0x18, 0x5a, 0x16, 0x64,
|
||||
0x6e, 0x6d, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_geometry_proto_rawDescOnce sync.Once
|
||||
file_geometry_proto_rawDescData = file_geometry_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_geometry_proto_rawDescGZIP() []byte {
|
||||
file_geometry_proto_rawDescOnce.Do(func() {
|
||||
file_geometry_proto_rawDescData = protoimpl.X.CompressGZIP(file_geometry_proto_rawDescData)
|
||||
})
|
||||
return file_geometry_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_geometry_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
||||
var file_geometry_proto_goTypes = []interface{}{
|
||||
(*Direction)(nil), // 0: sharedprotos.Direction
|
||||
(*Vec2D)(nil), // 1: sharedprotos.Vec2D
|
||||
(*Polygon2D)(nil), // 2: sharedprotos.Polygon2D
|
||||
(*Vec2DList)(nil), // 3: sharedprotos.Vec2DList
|
||||
(*Polygon2DList)(nil), // 4: sharedprotos.Polygon2DList
|
||||
}
|
||||
var file_geometry_proto_depIdxs = []int32{
|
||||
1, // 0: sharedprotos.Polygon2D.anchor:type_name -> sharedprotos.Vec2D
|
||||
1, // 1: sharedprotos.Polygon2D.points:type_name -> sharedprotos.Vec2D
|
||||
1, // 2: sharedprotos.Vec2DList.eles:type_name -> sharedprotos.Vec2D
|
||||
2, // 3: sharedprotos.Polygon2DList.eles:type_name -> sharedprotos.Polygon2D
|
||||
4, // [4:4] is the sub-list for method output_type
|
||||
4, // [4:4] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_geometry_proto_init() }
|
||||
func file_geometry_proto_init() {
|
||||
if File_geometry_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_geometry_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Direction); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_geometry_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Vec2D); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_geometry_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Polygon2D); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_geometry_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Vec2DList); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_geometry_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Polygon2DList); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_geometry_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 5,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_geometry_proto_goTypes,
|
||||
DependencyIndexes: file_geometry_proto_depIdxs,
|
||||
MessageInfos: file_geometry_proto_msgTypes,
|
||||
}.Build()
|
||||
File_geometry_proto = out.File
|
||||
file_geometry_proto_rawDesc = nil
|
||||
file_geometry_proto_goTypes = nil
|
||||
file_geometry_proto_depIdxs = nil
|
||||
}
|
@@ -6,8 +6,10 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go.uber.org/zap"
|
||||
"io/ioutil"
|
||||
. "jsexport/battle"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -42,13 +44,13 @@ type TmxOrTsxPolyline struct {
|
||||
|
||||
type TmxOrTsxObject struct {
|
||||
Id int `xml:"id,attr"`
|
||||
Gid *int `xml:"gid,attr"`
|
||||
Gid int `xml:"gid,attr"`
|
||||
X float64 `xml:"x,attr"`
|
||||
Y float64 `xml:"y,attr"`
|
||||
Properties *TmxOrTsxProperties `xml:"properties"`
|
||||
Polyline *TmxOrTsxPolyline `xml:"polyline"`
|
||||
Width *float64 `xml:"width,attr"`
|
||||
Height *float64 `xml:"height,attr"`
|
||||
Width float64 `xml:"width,attr"`
|
||||
Height float64 `xml:"height,attr"`
|
||||
}
|
||||
|
||||
type TmxOrTsxObjectGroup struct {
|
||||
@@ -173,10 +175,8 @@ func (l *TmxLayer) decodeBase64() ([]uint32, error) {
|
||||
return gids, nil
|
||||
}
|
||||
|
||||
type Vec2DList []*Vec2D
|
||||
type Polygon2DList []*Polygon2D
|
||||
type StrToVec2DListMap map[string]*Vec2DList
|
||||
type StrToPolygon2DListMap map[string]*Polygon2DList
|
||||
type StrToVec2DListMap map[string](*[]*Vec2D)
|
||||
type StrToPolygon2DListMap map[string](*[]*Polygon2D)
|
||||
|
||||
func tmxPolylineToPolygon2D(pTmxMapIns *TmxMap, singleObjInTmxFile *TmxOrTsxObject, targetPolyline *TmxOrTsxPolyline) (*Polygon2D, error) {
|
||||
if nil == targetPolyline {
|
||||
@@ -233,10 +233,8 @@ func tsxPolylineToOffsetsWrtTileCenter(pTmxMapIns *TmxMap, singleObjInTsxFile *T
|
||||
pointsCount := len(singleValueArray)
|
||||
|
||||
thePolygon2DFromPolyline := &Polygon2D{
|
||||
Anchor: nil,
|
||||
Points: make([]*Vec2D, pointsCount),
|
||||
TileWidth: pTsxIns.TileWidth,
|
||||
TileHeight: pTsxIns.TileHeight,
|
||||
Anchor: nil,
|
||||
Points: make([]*Vec2D, pointsCount),
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -323,14 +321,12 @@ func DeserializeTsxToColliderDict(pTmxMapIns *TmxMap, byteArrOfTsxFile []byte, f
|
||||
theStrToPolygon2DListMap = gidBoundariesMap[globalGid]
|
||||
}
|
||||
|
||||
var pThePolygon2DList *Polygon2DList
|
||||
if _, ok := theStrToPolygon2DListMap[key]; ok {
|
||||
pThePolygon2DList = theStrToPolygon2DListMap[key]
|
||||
} else {
|
||||
thePolygon2DList := make(Polygon2DList, 0)
|
||||
theStrToPolygon2DListMap[key] = &thePolygon2DList
|
||||
pThePolygon2DList = theStrToPolygon2DListMap[key]
|
||||
var pThePolygon2DList *[]*Polygon2D = nil
|
||||
if _, ok := theStrToPolygon2DListMap[key]; !ok {
|
||||
tmp := make([]*Polygon2D, 0)
|
||||
theStrToPolygon2DListMap[key] = &tmp
|
||||
}
|
||||
pThePolygon2DList = theStrToPolygon2DListMap[key]
|
||||
|
||||
thePolygon2DFromPolyline, err := tsxPolylineToOffsetsWrtTileCenter(pTmxMapIns, singleObj, singleObj.Polyline, pTsxIns)
|
||||
if nil != err {
|
||||
@@ -349,11 +345,10 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMap map[int]StrToP
|
||||
for _, objGroup := range pTmxMapIns.ObjectGroups {
|
||||
switch objGroup.Name {
|
||||
case "PlayerStartingPos":
|
||||
var pTheVec2DListToCache *Vec2DList
|
||||
_, ok := toRetStrToVec2DListMap[objGroup.Name]
|
||||
if false == ok {
|
||||
theVec2DListToCache := make(Vec2DList, 0)
|
||||
toRetStrToVec2DListMap[objGroup.Name] = &theVec2DListToCache
|
||||
var pTheVec2DListToCache *[]*Vec2D = nil
|
||||
if _, ok := toRetStrToVec2DListMap[objGroup.Name]; !ok {
|
||||
tmp := make([]*Vec2D, 0)
|
||||
toRetStrToVec2DListMap[objGroup.Name] = &tmp
|
||||
}
|
||||
pTheVec2DListToCache = toRetStrToVec2DListMap[objGroup.Name]
|
||||
for _, singleObjInTmxFile := range objGroup.Objects {
|
||||
@@ -366,20 +361,39 @@ func ParseTmxLayersAndGroups(pTmxMapIns *TmxMap, gidBoundariesMap map[int]StrToP
|
||||
}
|
||||
case "Barrier":
|
||||
// Note that in this case, the "Polygon2D.Anchor" of each "TmxOrTsxObject" is exactly overlapping with "Polygon2D.Points[0]".
|
||||
var pThePolygon2DListToCache *Polygon2DList
|
||||
_, ok := toRetStrToPolygon2DListMap[objGroup.Name]
|
||||
if false == ok {
|
||||
thePolygon2DListToCache := make(Polygon2DList, 0)
|
||||
toRetStrToPolygon2DListMap[objGroup.Name] = &thePolygon2DListToCache
|
||||
var pThePolygon2DListToCache *[]*Polygon2D = nil
|
||||
if _, ok := toRetStrToPolygon2DListMap[objGroup.Name]; !ok {
|
||||
tmp := make([]*Polygon2D, 0)
|
||||
toRetStrToPolygon2DListMap[objGroup.Name] = &tmp
|
||||
}
|
||||
pThePolygon2DListToCache = toRetStrToPolygon2DListMap[objGroup.Name]
|
||||
|
||||
for _, singleObjInTmxFile := range objGroup.Objects {
|
||||
if nil == singleObjInTmxFile.Polyline {
|
||||
continue
|
||||
}
|
||||
if nil == singleObjInTmxFile.Properties.Property || "boundary_type" != singleObjInTmxFile.Properties.Property[0].Name || "barrier" != singleObjInTmxFile.Properties.Property[0].Value {
|
||||
continue
|
||||
pts := make([]*Vec2D, 4)
|
||||
s := make([]string, 0)
|
||||
pts[0] = &Vec2D{
|
||||
X: float64(0),
|
||||
Y: float64(0),
|
||||
}
|
||||
pts[1] = &Vec2D{
|
||||
X: float64(0),
|
||||
Y: singleObjInTmxFile.Height,
|
||||
}
|
||||
pts[2] = &Vec2D{
|
||||
X: singleObjInTmxFile.Width,
|
||||
Y: singleObjInTmxFile.Height,
|
||||
}
|
||||
pts[3] = &Vec2D{
|
||||
X: singleObjInTmxFile.Width,
|
||||
Y: float64(0),
|
||||
}
|
||||
for _, pt := range pts {
|
||||
s = append(s, fmt.Sprintf("%v,%v", pt.X, pt.Y))
|
||||
}
|
||||
singleObjInTmxFile.Polyline = &TmxOrTsxPolyline{
|
||||
Points: strings.Join(s, " "),
|
||||
}
|
||||
}
|
||||
|
||||
thePolygon2DInWorld, err := tmxPolylineToPolygon2D(pTmxMapIns, singleObjInTmxFile, singleObjInTmxFile.Polyline)
|
||||
@@ -405,6 +419,12 @@ type TileRectilinearSize struct {
|
||||
}
|
||||
|
||||
func (pTmxMapIns *TmxMap) continuousObjLayerVecToContinuousMapNodeVec(continuousObjLayerVec *Vec2D) Vec2D {
|
||||
if "orthogonal" == pTmxMapIns.Orientation {
|
||||
return Vec2D{
|
||||
X: continuousObjLayerVec.X,
|
||||
Y: -continuousObjLayerVec.Y,
|
||||
}
|
||||
}
|
||||
var tileRectilinearSize TileRectilinearSize
|
||||
tileRectilinearSize.Width = float64(pTmxMapIns.TileWidth)
|
||||
tileRectilinearSize.Height = float64(pTmxMapIns.TileHeight)
|
||||
@@ -427,55 +447,24 @@ func (pTmxMapIns *TmxMap) continuousObjLayerVecToContinuousMapNodeVec(continuous
|
||||
}
|
||||
|
||||
func (pTmxMapIns *TmxMap) continuousObjLayerOffsetToContinuousMapNodePos(continuousObjLayerOffset *Vec2D) Vec2D {
|
||||
layerOffset := Vec2D{
|
||||
X: 0,
|
||||
Y: float64(pTmxMapIns.Height*pTmxMapIns.TileHeight) * 0.5,
|
||||
var layerOffset Vec2D
|
||||
if "orthogonal" == pTmxMapIns.Orientation {
|
||||
layerOffset = Vec2D{
|
||||
X: -float64(pTmxMapIns.Width*pTmxMapIns.TileWidth) * 0.5,
|
||||
Y: float64(pTmxMapIns.Height*pTmxMapIns.TileHeight) * 0.5,
|
||||
}
|
||||
} else {
|
||||
// "isometric" == pTmxMapIns.Orientation
|
||||
layerOffset = Vec2D{
|
||||
X: 0,
|
||||
Y: float64(pTmxMapIns.Height*pTmxMapIns.TileHeight) * 0.5,
|
||||
}
|
||||
}
|
||||
|
||||
calibratedVec := continuousObjLayerOffset
|
||||
convertedVec := pTmxMapIns.continuousObjLayerVecToContinuousMapNodeVec(calibratedVec)
|
||||
convertedVec := pTmxMapIns.continuousObjLayerVecToContinuousMapNodeVec(continuousObjLayerOffset)
|
||||
|
||||
toRet := Vec2D{
|
||||
return Vec2D{
|
||||
X: layerOffset.X + convertedVec.X,
|
||||
Y: layerOffset.Y + convertedVec.Y,
|
||||
}
|
||||
|
||||
return toRet
|
||||
}
|
||||
|
||||
func AlignPolygon2DToBoundingBox(input *Polygon2D) *Polygon2D {
|
||||
// Transform again to put "anchor" at the top-left point of the bounding box for "resolv"
|
||||
float64Max := float64(99999999999999.9)
|
||||
boundingBoxTL := &Vec2D{
|
||||
X: float64Max,
|
||||
Y: float64Max,
|
||||
}
|
||||
for _, p := range input.Points {
|
||||
if p.X < boundingBoxTL.X {
|
||||
boundingBoxTL.X = p.X
|
||||
}
|
||||
if p.Y < boundingBoxTL.Y {
|
||||
boundingBoxTL.Y = p.Y
|
||||
}
|
||||
}
|
||||
|
||||
// Now "input.Anchor" should move to "input.Anchor+boundingBoxTL", thus "boundingBoxTL" is also the value of the negative diff for all "input.Points"
|
||||
output := &Polygon2D{
|
||||
Anchor: &Vec2D{
|
||||
X: input.Anchor.X + boundingBoxTL.X,
|
||||
Y: input.Anchor.Y + boundingBoxTL.Y,
|
||||
},
|
||||
Points: make([]*Vec2D, len(input.Points)),
|
||||
TileWidth: input.TileWidth,
|
||||
TileHeight: input.TileHeight,
|
||||
}
|
||||
|
||||
for i, p := range input.Points {
|
||||
output.Points[i] = &Vec2D{
|
||||
X: p.X - boundingBoxTL.X,
|
||||
Y: p.Y - boundingBoxTL.Y,
|
||||
}
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
BIN
dragonBonesProjects/SoldierElf.dbproj
Normal file
BIN
dragonBonesProjects/SoldierFireGhost.dbproj
Normal file
BIN
dragonBonesProjects/SoldierWaterGhost.dbproj
Normal file
1
dragonBonesProjects/library/SoldierElf.json
Normal file
@@ -0,0 +1 @@
|
||||
{"width":128,"imagePath":"SoldierElf_tex.png","height":128,"name":"SoldierElf","SubTexture":[{"frameHeight":45,"y":1,"frameX":0,"width":34,"frameY":0,"height":44,"name":"cape","frameWidth":34,"x":70},{"width":10,"y":107,"height":14,"name":"shouder_l","x":74},{"width":11,"y":107,"height":14,"name":"forearm_l","x":61},{"width":15,"y":93,"height":16,"name":"hand_l","x":1},{"width":30,"y":61,"height":30,"name":"weapon_hand_l","x":1},{"width":8,"y":101,"height":11,"name":"thigh_l","x":86},{"width":12,"y":93,"height":17,"name":"calf_l","x":18},{"width":20,"y":113,"height":8,"name":"foot_l","x":39},{"width":28,"y":61,"height":31,"name":"pelvis","x":33},{"width":8,"y":88,"height":11,"name":"thigh_r","x":77},{"width":12,"y":88,"height":17,"name":"calf_r","x":63},{"width":20,"y":113,"height":8,"name":"foot_r","x":17},{"width":13,"y":94,"height":12,"name":"shouder_r","x":45},{"width":67,"y":1,"height":58,"name":"chest","x":1},{"width":11,"y":94,"height":17,"name":"forearm_r","x":32},{"width":14,"y":111,"height":13,"name":"hand_r","x":1},{"frameHeight":39,"y":47,"frameX":-2,"width":34,"frameY":0,"height":39,"name":"we_bl_4_f_1","frameWidth":36,"x":70}]}
|
BIN
dragonBonesProjects/library/SoldierElf.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
1
dragonBonesProjects/library/SoldierFireGhost.json
Normal file
@@ -0,0 +1 @@
|
||||
{"imagePath":"Soldier_02_tex.png","width":128,"name":"Soldier_02","SubTexture":[{"x":53,"y":44,"width":23,"name":"biu","height":22},{"x":76,"y":68,"width":9,"name":"rightArm","height":14},{"y":35,"frameY":0,"height":32,"frameWidth":29,"frameX":-1,"frameHeight":32,"width":27,"name":"yinmoqe00","x":89},{"x":53,"y":1,"width":34,"name":"body","height":41},{"x":78,"y":44,"width":9,"name":"rightShoulder","height":13},{"y":50,"frameY":0,"height":18,"frameWidth":19,"frameX":0,"frameHeight":18,"width":19,"name":"rightFrontArm","x":23},{"x":23,"y":70,"width":14,"name":"rightHand","height":14},{"y":68,"frameY":0,"height":12,"frameWidth":12,"frameX":0,"frameHeight":12,"width":12,"name":"leftArm","x":62},{"x":1,"y":73,"width":13,"name":"leftShoulder","height":12},{"x":1,"y":50,"width":20,"name":"leftFrontArm","height":21},{"x":89,"y":1,"width":33,"name":"head","height":32},{"x":1,"y":1,"width":50,"name":"head2","height":47},{"x":44,"y":68,"width":16,"name":"leftHand","height":14},{"y":59,"frameY":-2,"height":4,"frameWidth":8,"frameX":-1,"frameHeight":8,"width":4,"name":"huomiao01","x":78}],"height":128}
|
BIN
dragonBonesProjects/library/SoldierFireGhost.png
Normal file
After Width: | Height: | Size: 5.4 KiB |
1
dragonBonesProjects/library/SoldierWaterGhost.json
Normal file
@@ -0,0 +1 @@
|
||||
{"width":128,"SubTexture":[{"frameWidth":23,"y":50,"frameX":-2,"frameHeight":22,"frameY":-2,"width":19,"height":19,"name":"biu","x":1},{"width":9,"y":50,"height":14,"name":"rightArm","x":42},{"frameWidth":29,"y":34,"frameX":-6,"frameHeight":32,"frameY":0,"width":20,"height":32,"name":"yinmoqe00","x":88},{"frameWidth":34,"y":1,"frameX":0,"frameHeight":41,"frameY":0,"width":33,"height":39,"name":"body","x":53},{"width":9,"y":56,"height":13,"name":"rightShoulder","x":74},{"frameWidth":19,"y":50,"frameX":0,"frameHeight":18,"frameY":0,"width":18,"height":17,"name":"rightFrontArm","x":22},{"width":14,"y":50,"height":14,"name":"rightHand","x":110},{"width":12,"y":42,"height":12,"name":"leftArm","x":74},{"width":13,"y":66,"height":12,"name":"leftShoulder","x":110},{"frameWidth":20,"y":42,"frameX":-1,"frameHeight":21,"frameY":0,"width":19,"height":21,"name":"leftFrontArm","x":53},{"width":50,"y":1,"height":47,"name":"head2","x":1},{"frameWidth":33,"y":1,"frameX":-1,"frameHeight":32,"frameY":0,"width":32,"height":31,"name":"head","x":88},{"width":16,"y":34,"height":14,"name":"leftHand","x":110},{"frameWidth":8,"y":1,"frameX":-2,"frameHeight":8,"frameY":-3,"width":2,"height":2,"name":"huomiao01","x":122}],"height":128,"name":"SoldierWaterGhost","imagePath":"SoldierWaterGhost_tex.png"}
|
BIN
dragonBonesProjects/library/SoldierWaterGhost.png
Normal file
After Width: | Height: | Size: 6.8 KiB |
@@ -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;
|
@@ -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() {};
|
||||
|
@@ -23,9 +23,9 @@ var constants = {
|
||||
FILE_NAME: {
|
||||
TREASURE_PICKEDUP: "TreasurePicked",
|
||||
CRASHED_BY_TRAP_BULLET: "CrashedByTrapBullet",
|
||||
HIGH_SCORE_TREASURE_PICKED:"HighScoreTreasurePicked",
|
||||
COUNT_DOWN_10SEC_TO_END:"countDown10SecToEnd",
|
||||
BGM: "BGM"
|
||||
HIGH_SCORE_TREASURE_PICKED: "HighScoreTreasurePicked",
|
||||
COUNT_DOWN_10SEC_TO_END: "countDown10SecToEnd",
|
||||
BGM: "BGM"
|
||||
}
|
||||
},
|
||||
ROUTE_PATH: (_ROUTE_PATH = {
|
||||
@@ -55,39 +55,41 @@ var constants = {
|
||||
},
|
||||
RET_CODE: {
|
||||
/**
|
||||
* NOTE: The "RET_CODE"s from 1000-1015 are reserved for the websocket "WebsocketStdCloseCode"s.
|
||||
* NOTE: The "RET_CODE"s from 1000-1015 are reserved for the websocket "WebsocketStdCloseCode"s, custom codes should be between 3000-4999
|
||||
*
|
||||
* References
|
||||
* - https://tools.ietf.org/html/rfc6455#section-7.4
|
||||
* - https://godoc.org/github.com/gorilla/websocket#pkg-constants.
|
||||
*/
|
||||
"__comment__": "基础",
|
||||
"OK": 9000,
|
||||
"UNKNOWN_ERROR": 9001,
|
||||
"INVALID_REQUEST_PARAM": 9002,
|
||||
"IS_TEST_ACC": 9003,
|
||||
"MYSQL_ERROR": 9004,
|
||||
"NONEXISTENT_ACT": 9005,
|
||||
"LACK_OF_DIAMOND": 9006,
|
||||
"LACK_OF_GOLD": 9007,
|
||||
"LACK_OF_ENERGY": 9008,
|
||||
"NONEXISTENT_ACT_HANDLER": 9009,
|
||||
"LOCALLY_NO_AVAILABLE_ROOM": 9010,
|
||||
"LOCALLY_NO_SPECIFIED_ROOM": 9011,
|
||||
"PLAYER_NOT_ADDABLE_TO_ROOM": 9012,
|
||||
"PLAYER_NOT_READDABLE_TO_ROOM": 9013,
|
||||
"PLAYER_NOT_FOUND": 9014,
|
||||
"PLAYER_CHEATING": 9015,
|
||||
|
||||
"__comment__": "Websocket",
|
||||
"OK": 3000,
|
||||
"UNKNOWN_ERROR": 3001,
|
||||
"INVALID_REQUEST_PARAM": 3002,
|
||||
"IS_TEST_ACC": 3003,
|
||||
"MYSQL_ERROR": 3004,
|
||||
"NONEXISTENT_ACT": 3005,
|
||||
"LACK_OF_DIAMOND": 3006,
|
||||
"LACK_OF_GOLD": 3007,
|
||||
"LACK_OF_ENERGY": 3008,
|
||||
"NONEXISTENT_ACT_HANDLER": 3009,
|
||||
"LOCALLY_NO_AVAILABLE_ROOM": 3010,
|
||||
"LOCALLY_NO_SPECIFIED_ROOM": 3011,
|
||||
"PLAYER_NOT_ADDABLE_TO_ROOM": 3012,
|
||||
"PLAYER_NOT_READDABLE_TO_ROOM": 3013,
|
||||
"PLAYER_NOT_FOUND": 3014,
|
||||
"PLAYER_CHEATING": 3015,
|
||||
"WECHAT_SERVER_ERROR": 3016,
|
||||
"IS_BOT_ACC": 3017,
|
||||
"ACTIVE_WATCHDOG": 3018,
|
||||
"BATTLE_STOPPED": 3019,
|
||||
"CLIENT_MISMATCHED_RENDER_FRAME": 3020,
|
||||
|
||||
"__comment__": "SMS",
|
||||
"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY": 5001,
|
||||
"SMS_CAPTCHA_NOT_MATCH": 5002,
|
||||
"__comment__": "OTHERS",
|
||||
"INVALID_TOKEN": 2001,
|
||||
|
||||
"DUPLICATED": 2002,
|
||||
"INCORRECT_HANDLE": 2004,
|
||||
"NONEXISTENT_HANDLE": 2005,
|
||||
|
||||
"INCORRECT_PASSWORD": 2006,
|
||||
"INCORRECT_CAPTCHA": 2007,
|
||||
"INVALID_EMAIL_LITERAL": 2008,
|
||||
@@ -99,9 +101,15 @@ var constants = {
|
||||
"FAILED_TO_DELETE": 2015,
|
||||
"FAILED_TO_CREATE": 2016,
|
||||
"INCORRECT_PHONE_NUMBER": 2018,
|
||||
"PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY": 4000,
|
||||
"TRADE_CREATION_TOO_FREQUENTLY": 4002,
|
||||
"MAP_NOT_UNLOCKED": 4003,
|
||||
"INSUFFICIENT_MEM_TO_ALLOCATE_CONNECTION": 2019,
|
||||
"PASSWORD_RESET_CODE_GENERATION_PER_EMAIL_TOO_FREQUENTLY": 2020,
|
||||
"TRADE_CREATION_TOO_FREQUENTLY": 2021,
|
||||
"MAP_NOT_UNLOCKED": 2022,
|
||||
|
||||
"GET_SMS_CAPTCHA_RESP_ERROR_CODE": 2023,
|
||||
"SMS_CAPTCHA_REQUESTED_TOO_FREQUENTLY": 2024,
|
||||
"SMS_CAPTCHA_NOT_MATCH": 2025,
|
||||
"SAME_PLAYER_ALREADY_IN_SAME_ROOM": 2026,
|
||||
|
||||
"NOT_IMPLEMENTED_YET": 65535
|
||||
},
|
||||
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "115ea7bb-d47f-4d3c-a52a-f46584346c3f",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "a1bf7c7c-b9f7-4b65-86e3-f86a9e798fb6",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "d5af527a-9f0c-4398-b2dd-84426be7bd32",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "b60618d7-569d-4f13-bdeb-f20341fbadb6",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "Right",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "a6ec6a1c-dde5-459d-84f9-7b2b8a163e7b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "b5d11244-f30a-4b0d-b67b-23648d253d44"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "0b3fb38e-9110-4191-9b72-6b64a224d049",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "Top",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "8967d249-e9cf-4e44-85e8-6b9377129d9e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "492a57fb-6a5c-423a-bcfe-0695a7828881"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "1bc6de53-800b-4da3-ab8e-4a45e3aa4230",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "TopLeft",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "96187689-85df-46e8-b4db-410eae03c135"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "6b002583-7688-43d3-b3fa-102ae0046628"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "ee0d670c-893e-4e4d-96dd-5571db18ee97",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"__type__": "cc.AnimationClip",
|
||||
"_name": "TopRight",
|
||||
"_objFlags": 0,
|
||||
"_native": "",
|
||||
"_duration": 0.25,
|
||||
"sample": 12,
|
||||
"speed": 1,
|
||||
"wrapMode": "2",
|
||||
"curveData": {
|
||||
"comps": {
|
||||
"cc.Sprite": {
|
||||
"spriteFrame": [
|
||||
{
|
||||
"frame": 0,
|
||||
"value": {
|
||||
"__uuid__": "ba89046f-8b70-4edb-9f61-534dff476325"
|
||||
}
|
||||
},
|
||||
{
|
||||
"frame": 0.16666666666666666,
|
||||
"value": {
|
||||
"__uuid__": "bc1ef316-d6ad-4538-b223-a0fed8094609"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"events": []
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "596df84a-2e4e-4f1d-967c-a82649f564a8",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "8acc4e9f-3c47-4b66-9a9d-d012709680f6",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "c7cda0cd-dbce-4722-abd2-aeca28263a21",
|
||||
"subMetas": {}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "135f388e-7e75-4ece-b267-4e07835cba74",
|
||||
"uuid": "c7c2ac6e-f1ea-4233-b6a4-aa5b96b61e17",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
@@ -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": []
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "7941215a-2b8c-4798-954b-4f1b16d5f6f5",
|
||||
"subMetas": {}
|
||||
}
|
@@ -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": []
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "14b92f5c-af81-416a-a162-e5822d20fe68",
|
||||
"subMetas": {}
|
||||
}
|
@@ -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": []
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": "2.1.0",
|
||||
"uuid": "0dbb90ed-a08a-448c-b06e-4831260e9213",
|
||||
"subMetas": {}
|
||||
}
|
@@ -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": []
|
||||
}
|