From ad3a6df431e4198accf7fb8f9e8c3d9694e4d790 Mon Sep 17 00:00:00 2001 From: Srayan Jana Date: Wed, 25 Jun 2025 19:11:40 -0700 Subject: [PATCH 1/2] Add simple ebiten game --- go.mod | 18 +- go.sum | 93 ++++++- simple-ebiten-game/LICENSE.md | 7 + simple-ebiten-game/README.md | 13 + simple-ebiten-game/gopher.png | Bin 0 -> 43718 bytes simple-ebiten-game/gopher.png.license | 2 + simple-ebiten-game/main.go | 371 ++++++++++++++++++++++++++ 7 files changed, 499 insertions(+), 5 deletions(-) create mode 100644 simple-ebiten-game/LICENSE.md create mode 100644 simple-ebiten-game/README.md create mode 100644 simple-ebiten-game/gopher.png create mode 100644 simple-ebiten-game/gopher.png.license create mode 100644 simple-ebiten-game/main.go diff --git a/go.mod b/go.mod index 7974515e..314aa066 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,18 @@ module github.com/pion/example-webrtc-applications/v3 -go 1.22 +go 1.23.0 -toolchain go1.23.6 +toolchain go1.24.2 require ( github.com/asticode/go-astiav v0.19.0 github.com/at-wat/ebml-go v0.17.1 + github.com/ebitengine/debugui v0.1.1 github.com/emiago/sipgo v0.33.0 github.com/go-gst/go-gst v1.3.0 github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.3 + github.com/hajimehoshi/ebiten/v2 v2.8.8 github.com/notedit/janus-go v0.0.0-20210115013133-fdce1b146d0e github.com/pion/interceptor v0.1.40 github.com/pion/logging v0.2.4 @@ -25,12 +27,19 @@ require ( require ( github.com/asticode/go-astikit v0.42.0 // indirect + github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 // indirect + github.com/ebitengine/hideconsole v1.0.0 // indirect + github.com/ebitengine/purego v0.8.0 // indirect github.com/go-gst/go-glib v1.3.0 // indirect + github.com/go-text/typesetting v0.2.0 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect github.com/gobwas/ws v1.3.2 // indirect + github.com/hajimehoshi/bitmapfont/v3 v3.2.1 // indirect github.com/icholy/digest v1.1.0 // indirect + github.com/jezek/xgb v1.1.1 // indirect github.com/mattn/go-pointer v0.0.1 // indirect + github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pion/datachannel v1.5.10 // indirect github.com/pion/dtls/v3 v3.0.6 // indirect github.com/pion/ice/v4 v4.0.10 // indirect @@ -41,9 +50,12 @@ require ( github.com/pion/stun/v3 v3.0.0 // indirect github.com/pion/transport/v3 v3.0.7 // indirect github.com/pion/turn/v4 v4.0.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/rs/xid v1.5.0 // indirect github.com/wlynxg/anet v0.0.5 // indirect golang.org/x/crypto v0.33.0 // indirect golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect - golang.org/x/sys v0.30.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/text v0.22.0 // indirect ) diff --git a/go.sum b/go.sum index cf080270..322c2ad3 100644 --- a/go.sum +++ b/go.sum @@ -6,12 +6,24 @@ github.com/at-wat/ebml-go v0.17.1 h1:pWG1NOATCFu1hnlowCzrA1VR/3s8tPY6qpU+2FwW7X4 github.com/at-wat/ebml-go v0.17.1/go.mod h1:w1cJs7zmGsb5nnSvhWGKLCxvfu4FVx5ERvYDIalj1ww= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/ebitengine/debugui v0.1.1 h1:3b4cIujNvKYhozlBjag9TWuuyo67Di3DgXWAz+f7xAY= +github.com/ebitengine/debugui v0.1.1/go.mod h1:wIKIq5RvNFb3+nFfJcYqSLvpC1ioD/BglWDtuWFSDz0= +github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 h1:Gk1XUEttOk0/hb6Tq3WkmutWa0ZLhNn/6fc6XZpM7tM= +github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325/go.mod h1:ulhSQcbPioQrallSuIzF8l1NKQoD7xmMZc5NxzibUMY= +github.com/ebitengine/hideconsole v1.0.0 h1:5J4U0kXF+pv/DhiXt5/lTz0eO5ogJ1iXb8Yj1yReDqE= +github.com/ebitengine/hideconsole v1.0.0/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A= +github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE= +github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/emiago/sipgo v0.33.0 h1:UxPKCoPREffSjrRE6oesG/RPz5/ZSp8tA8Jc6YvYUsk= github.com/emiago/sipgo v0.33.0/go.mod h1:gbOLw/kZHZ3wS/5PIa9qVjpdil/IKLdigbZFIYFpHTs= github.com/go-gst/go-glib v1.3.0 h1:u+mPUdLmrDFA/MskIxInJY+M0O1RSkHeZYggnJGWlPk= github.com/go-gst/go-glib v1.3.0/go.mod h1:JybIYeoHNwCkHGaBf1fHNIaM4sQTrJPkPLsi7dmPNOU= github.com/go-gst/go-gst v1.3.0 h1:z4mQ7CNJXd6ZfkibzIT9kZKwtgEFJo7jJGlX9cXFzz0= github.com/go-gst/go-gst v1.3.0/go.mod h1:2li6ghiCBz7/R6DA7itVto3gsYh0QKicwSxEefNVYqE= +github.com/go-text/typesetting v0.2.0 h1:fbzsgbmk04KiWtE+c3ZD4W2nmCRzBqrqQOvYlwAOdho= +github.com/go-text/typesetting v0.2.0/go.mod h1:2+owI/sxa73XA581LAzVuEBZ3WEEV2pXeDswCH/3i1I= +github.com/go-text/typesetting-utils v0.0.0-20240317173224-1986cbe96c66 h1:GUrm65PQPlhFSKjLPGOZNPNxLCybjzjYBzjfoBGaDUY= +github.com/go-text/typesetting-utils v0.0.0-20240317173224-1986cbe96c66/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= @@ -24,12 +36,20 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hajimehoshi/bitmapfont/v3 v3.2.1 h1:33Lw85DZolX3upouUqf6Qza8HYGIROvr7SYin7PzIZ8= +github.com/hajimehoshi/bitmapfont/v3 v3.2.1/go.mod h1:8gLqGatKVu0pwcNCJguW3Igg9WQqVXF0zg/RvrGQWyg= +github.com/hajimehoshi/ebiten/v2 v2.8.8 h1:xyMxOAn52T1tQ+j3vdieZ7auDBOXmvjUprSrxaIbsi8= +github.com/hajimehoshi/ebiten/v2 v2.8.8/go.mod h1:durJ05+OYnio9b8q0sEtOgaNeBEQG7Yr7lRviAciYbs= github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4= github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y= +github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4= +github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/notedit/janus-go v0.0.0-20210115013133-fdce1b146d0e h1:L1QWI1FyFkgLOLSP/BlbkLiyLyqUuyxCCRJyULDinx8= github.com/notedit/janus-go v0.0.0-20210115013133-fdce1b146d0e/go.mod h1:BN/Txse3qz8tZOmCm2OfajB2wHVujWmX3o9nVdsI6gE= +github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= +github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= github.com/pion/dtls/v3 v3.0.6 h1:7Hkd8WhAJNbRgq9RgdNh1aaWlZlGpYTzdqjy9x9sK2E= @@ -62,27 +82,96 @@ github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM= github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA= github.com/pion/webrtc/v4 v4.1.2 h1:mpuUo/EJ1zMNKGE79fAdYNFZBX790KE7kQQpLMjjR54= github.com/pion/webrtc/v4 v4.1.2/go.mod h1:xsCXiNAmMEjIdFxAYU0MbB3RwRieJsegSB2JZsGN+8U= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= gocv.io/x/gocv v0.40.0 h1:kGBu/UVj+dO6A9dhQmGOnCICSL7ke7b5YtX3R3azdXI= gocv.io/x/gocv v0.40.0/go.mod h1:zYdWMj29WAEznM3Y8NsU3A0TRq/wR/cy75jeUypThqU= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM= golang.org/x/image v0.23.0 h1:HseQ7c2OpPKTPVzNjG5fwJsOTCiiwS4QdsYi5XU6H68= golang.org/x/image v0.23.0/go.mod h1:wJJBTdLfCCf3tiHa1fNxpZmUI4mmoZvwMCPP0ddoNKY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= diff --git a/simple-ebiten-game/LICENSE.md b/simple-ebiten-game/LICENSE.md new file mode 100644 index 00000000..00ae6127 --- /dev/null +++ b/simple-ebiten-game/LICENSE.md @@ -0,0 +1,7 @@ +## gopher.png + +``` +The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/) +The design is licensed under the Creative Commons 4.0 Attributions license. +Read this article for more details: https://blog.golang.org/gopher +``` \ No newline at end of file diff --git a/simple-ebiten-game/README.md b/simple-ebiten-game/README.md new file mode 100644 index 00000000..430caad5 --- /dev/null +++ b/simple-ebiten-game/README.md @@ -0,0 +1,13 @@ +# Ebitengine Game! + +This is a pretty nifty demo on how to use [ebitengine](https://ebitengine.org/) and [pion](https://github.com/pion/webrtc) to pull off a cross platform game! + +You can have a client running on the browser and one running on a desktop and they can talk to each other, provided they share SDPs. + +Do ``go run .`` for running the game on desktop + +(see [this tutorial for more information on how to build for WebAssembly](https://ebitengine.org/en/documents/webassembly.html)) + +To play: Just move around with the arrow keys once you have connected! + +Right now this only supports two clients diff --git a/simple-ebiten-game/gopher.png b/simple-ebiten-game/gopher.png new file mode 100644 index 0000000000000000000000000000000000000000..b11c17039442e0972a4756043cdd3ebb38cefb67 GIT binary patch literal 43718 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 HF!=uf$Few2 literal 0 HcmV?d00001 diff --git a/simple-ebiten-game/gopher.png.license b/simple-ebiten-game/gopher.png.license new file mode 100644 index 00000000..54b7f842 --- /dev/null +++ b/simple-ebiten-game/gopher.png.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: 2016 The Go Authors +SPDX-License-Identifier: CC-BY-3.0 \ No newline at end of file diff --git a/simple-ebiten-game/main.go b/simple-ebiten-game/main.go new file mode 100644 index 00000000..97f92844 --- /dev/null +++ b/simple-ebiten-game/main.go @@ -0,0 +1,371 @@ +// SPDX-FileCopyrightText: 2025 The Pion community +// SPDX-License-Identifier: MIT + +package main + +import ( + "bufio" + "encoding/base64" + "encoding/gob" + "encoding/json" + "errors" + "fmt" + "image" + "io" + "log" + "os" + "strings" + "time" + + "github.com/ebitengine/debugui" + "github.com/hajimehoshi/ebiten/v2" + "github.com/hajimehoshi/ebiten/v2/ebitenutil" + "github.com/pion/webrtc/v4" +) + +type NetworkMessage struct { + X float64 + Y float64 +} + +var img *ebiten.Image +var player_x float64 = 0 +var player_y float64 = 0 + +var remote_player_x float64 = 0 +var remote_player_y float64 = 0 + +const PlayerSpeed = 2 + +var isClient bool = false +var isHost bool = false + +func init() { + var err error + img, _, err = ebitenutil.NewImageFromFile("gopher.png") + if err != nil { + log.Fatal(err) + } +} + +type Game struct { + debugui debugui.DebugUI + peerConnection *webrtc.PeerConnection +} + +func (g *Game) Update() error { + // Update player position based on input + if ebiten.IsKeyPressed(ebiten.KeyArrowUp) { + player_y -= PlayerSpeed + } + if ebiten.IsKeyPressed(ebiten.KeyArrowDown) { + player_y += PlayerSpeed + } + if ebiten.IsKeyPressed(ebiten.KeyArrowLeft) { + player_x -= PlayerSpeed + } + if ebiten.IsKeyPressed(ebiten.KeyArrowRight) { + player_x += PlayerSpeed + } + + // ui stuff + if _, err := g.debugui.Update(func(ctx *debugui.Context) error { + ctx.Window("Test", image.Rect(60, 60, 160, 180), func(layout debugui.ContainerLayout) { + ctx.Button("Host Button").On(func() { + if !isHost { + g.runHost() + isHost = true + } + }) + ctx.Button("Client Button").On(func() { + if !isClient { + g.runClient() + isClient = true + } + }) + }) + return nil + }); err != nil { + return err + } + + return nil +} + +func (g *Game) Draw(screen *ebiten.Image) { + // local player + op := &ebiten.DrawImageOptions{} + op.GeoM.Translate(player_x, player_y) + screen.DrawImage(img, op) + // remote player + op = &ebiten.DrawImageOptions{} + op.GeoM.Translate(remote_player_x, remote_player_y) + screen.DrawImage(img, op) + + // render debug UI + g.debugui.Draw(screen) +} + +func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) { + return outsideWidth, outsideHeight +} + +func (g *Game) networkSetup() { + // Since this behavior diverges from the WebRTC API it has to be + // enabled using a settings engine. Mixing both detached and the + // OnMessage DataChannel API is not supported. + + // Create a SettingEngine and enable Detach + s := webrtc.SettingEngine{} + s.DetachDataChannels() + + // Create an API object with the engine + api := webrtc.NewAPI(webrtc.WithSettingEngine(s)) + + // Everything below is the Pion WebRTC API! Thanks for using it ❤️. + + // Prepare the configuration + config := webrtc.Configuration{ + ICEServers: []webrtc.ICEServer{ + { + URLs: []string{"stun:stun.l.google.com:19302"}, + }, + }, + } + + // Create a new RTCPeerConnection using the API object + peerConnection, err := api.NewPeerConnection(config) + if err != nil { + panic(err) + } + /* + defer func() { + if cErr := peerConnection.Close(); cErr != nil { + fmt.Printf("cannot close peerConnection: %v\n", cErr) + } + }() + */ + + g.peerConnection = peerConnection + + // Set the handler for Peer connection state + // This will notify you when the peer has connected/disconnected + g.peerConnection.OnConnectionStateChange(func(state webrtc.PeerConnectionState) { + fmt.Printf("Peer Connection State has changed: %s\n", state.String()) + + if state == webrtc.PeerConnectionStateFailed { + // Wait until PeerConnection has had no network activity for 30 seconds or another failure. + // It may be reconnected using an ICE Restart. + // Use webrtc.PeerConnectionStateDisconnected if you are interested in detecting faster timeout. + // Note that the PeerConnection may come back from PeerConnectionStateDisconnected. + fmt.Println("Peer Connection has gone to failed exiting") + os.Exit(0) + } + + if state == webrtc.PeerConnectionStateClosed { + // PeerConnection was explicitly closed. This usually happens from a DTLS CloseNotify + fmt.Println("Peer Connection has gone to closed exiting") + os.Exit(0) + } + }) +} + +func (g *Game) runClient() { + g.networkSetup() + // Create a data channel with the default label and options + dataChannel, err := g.peerConnection.CreateDataChannel("data", nil) + if err != nil { + panic(err) + } + fmt.Printf("Created DataChannel %s %d\n", dataChannel.Label(), dataChannel.ID()) + + // Register channel opening handling + dataChannel.OnOpen(func() { + fmt.Printf("Data channel '%s'-'%d' open.\n", dataChannel.Label(), dataChannel.ID()) + + // Detach the data channel + raw, dErr := dataChannel.Detach() + if dErr != nil { + panic(dErr) + } + + // Handle reading from the data channel + go ReadLoop(raw) + + // Handle writing to the data channel + go WriteLoop(raw) + }) + + offer, err := g.peerConnection.CreateOffer(nil) + if err != nil { + panic(err) + } + + err = g.peerConnection.SetLocalDescription(offer) + if err != nil { + panic(err) + } + + // Output the answer in base64 so we can paste it in browser + fmt.Println("Printing SDP Offer, give this to the client:") + fmt.Println(encode(&offer)) + + // Wait for the answer to be pasted + fmt.Println("Waiting for answer from client:") + answer := webrtc.SessionDescription{} + decode(readUntilNewline(), &answer) + + // Set the remote SessionDescription + err = g.peerConnection.SetRemoteDescription(answer) + if err != nil { + panic(err) + } + + fmt.Println("Remote description set, client should now be able to connect") +} + +func (g *Game) runHost() { + g.networkSetup() + // callback for when we receive a new data channel + // Register data channel creation handling + g.peerConnection.OnDataChannel(func(dataChannel *webrtc.DataChannel) { + fmt.Printf("New DataChannel %s %d\n", dataChannel.Label(), dataChannel.ID()) + + // Register channel opening handling + dataChannel.OnOpen(func() { + fmt.Printf("Data channel '%s'-'%d' open.\n", dataChannel.Label(), dataChannel.ID()) + + // Detach the data channel + raw, dErr := dataChannel.Detach() + if dErr != nil { + panic(dErr) + } + + // Handle reading from the data channel + go ReadLoop(raw) + + // Handle writing to the data channel + go WriteLoop(raw) + }) + }) + fmt.Println("Waiting for SDP Offer from host:") + // Wait for the offer to be pasted + offer := webrtc.SessionDescription{} + decode(readUntilNewline(), &offer) + + // Set the remote SessionDescription + err := g.peerConnection.SetRemoteDescription(offer) + if err != nil { + panic(err) + } + + // Create answer + answer, err := g.peerConnection.CreateAnswer(nil) + if err != nil { + panic(err) + } + + // Create channel that is blocked until ICE Gathering is complete + gatherComplete := webrtc.GatheringCompletePromise(g.peerConnection) + + // Sets the LocalDescription, and starts our UDP listeners + err = g.peerConnection.SetLocalDescription(answer) + if err != nil { + panic(err) + } + + // Block until ICE Gathering is complete, disabling trickle ICE + // we do this because we only can exchange one signaling message + // in a production application you should exchange ICE Candidates via OnICECandidate + <-gatherComplete + + // Output the answer in base64 so we can paste it in browser + fmt.Println("Printing SDP Answer, give this to the host:") + fmt.Println(encode(g.peerConnection.CurrentLocalDescription())) +} + +func main() { + ebiten.SetWindowSize(640, 480) + ebiten.SetWindowTitle("Render an image") + if err := ebiten.RunGame(&Game{}); err != nil { + log.Fatal(err) + } +} + +// ReadLoop shows how to read from the datachannel directly. +func ReadLoop(d io.Reader) { + dec := gob.NewDecoder(d) + for { + var message NetworkMessage + if err := dec.Decode(&message); err != nil { + fmt.Println("Datachannel closed; Exit the readloop:", err) + + return + } + + //fmt.Printf("Message from DataChannel: %#v\n", message) + remote_player_x = message.X + remote_player_y = message.Y + } +} + +// WriteLoop shows how to write to the datachannel directly. +func WriteLoop(d io.Writer) { + enc := gob.NewEncoder(d) + ticker := time.NewTicker(16 * time.Millisecond) // roughly 60 FPS + defer ticker.Stop() + for range ticker.C { + message := NetworkMessage{ + X: player_x, + Y: player_y, + } + //fmt.Printf("Sending %#v \n", message) + if err := enc.Encode(message); err != nil { + fmt.Println("Datachannel closed; Exit the writeloop:", err) + panic(err) + } + } +} + +// Read from stdin until we get a newline. +func readUntilNewline() (in string) { + var err error + + r := bufio.NewReader(os.Stdin) + for { + in, err = r.ReadString('\n') + if err != nil && !errors.Is(err, io.EOF) { + panic(err) + } + + if in = strings.TrimSpace(in); len(in) > 0 { + break + } + } + + fmt.Println("") + + return +} + +// JSON encode + base64 a SessionDescription. +func encode(obj *webrtc.SessionDescription) string { + b, err := json.Marshal(obj) + if err != nil { + panic(err) + } + + return base64.StdEncoding.EncodeToString(b) +} + +// Decode a base64 and unmarshal JSON into a SessionDescription. +func decode(in string, obj *webrtc.SessionDescription) { + b, err := base64.StdEncoding.DecodeString(in) + if err != nil { + panic(err) + } + + if err = json.Unmarshal(b, obj); err != nil { + panic(err) + } +} From 2c6dfdbbb597f29fc4f800607841a5b69883989a Mon Sep 17 00:00:00 2001 From: Srayan Jana Date: Wed, 25 Jun 2025 19:20:06 -0700 Subject: [PATCH 2/2] add license --- LICENSES/CC-BY-3.0.txt | 319 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 LICENSES/CC-BY-3.0.txt diff --git a/LICENSES/CC-BY-3.0.txt b/LICENSES/CC-BY-3.0.txt new file mode 100644 index 00000000..1a16e055 --- /dev/null +++ b/LICENSES/CC-BY-3.0.txt @@ -0,0 +1,319 @@ +Creative Commons Legal Code + +Attribution 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. + +1. Definitions + + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + d. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + e. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + f. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + g. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + h. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + i. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: + + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: + + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor waives the + exclusive right to collect such royalties for any exercise by You + of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License. + +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved. + +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: + + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(b), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(b), as requested. + b. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and (iv) , consistent with Section 3(b), in the case of an Adaptation, + a credit identifying the use of the Work in the Adaptation (e.g., + "French translation of the Work by Original Author," or "Screenplay + based on original Work by Original Author"). The credit required by + this Section 4 (b) may be implemented in any reasonable manner; + provided, however, that in the case of a Adaptation or Collection, at + a minimum such credit will appear, if a credit for all contributing + authors of the Adaptation or Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + c. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. + +8. Miscellaneous + + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. + + +Creative Commons Notice + + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. + + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of this License. + + Creative Commons may be contacted at https://creativecommons.org/.