Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 163 KiB |
Before Width: | Height: | Size: 79 KiB |
@ -0,0 +1,2 @@
|
||||
**/__pycache__
|
||||
*.swp
|
@ -0,0 +1,464 @@
|
||||
.
|
||||
|-- 123.txt
|
||||
|-- acapp
|
||||
| |-- __init__.py
|
||||
| |-- __pycache__
|
||||
| | |-- __init__.cpython-38.pyc
|
||||
| | |-- asgi.cpython-38.pyc
|
||||
| | |-- settings.cpython-38.pyc
|
||||
| | |-- urls.cpython-38.pyc
|
||||
| | `-- wsgi.cpython-38.pyc
|
||||
| |-- asgi.py
|
||||
| |-- settings.py
|
||||
| |-- urls.py
|
||||
| `-- wsgi.py
|
||||
|-- db.sqlite3
|
||||
|-- game
|
||||
| |-- __init__.py
|
||||
| |-- __pycache__
|
||||
| | |-- __init__.cpython-38.pyc
|
||||
| | |-- admin.cpython-38.pyc
|
||||
| | |-- apps.cpython-38.pyc
|
||||
| | |-- channelsmiddleware.cpython-38.pyc
|
||||
| | `-- routing.cpython-38.pyc
|
||||
| |-- admin.py
|
||||
| |-- apps.py
|
||||
| |-- channelsmiddleware.py
|
||||
| |-- consumers
|
||||
| | |-- __init__.py
|
||||
| | |-- __pycache__
|
||||
| | | `-- __init__.cpython-38.pyc
|
||||
| | `-- multiplayer
|
||||
| | |-- __init__.py
|
||||
| | |-- __pycache__
|
||||
| | | |-- __init__.cpython-38.pyc
|
||||
| | | `-- index.cpython-38.pyc
|
||||
| | `-- index.py
|
||||
| |-- migrations
|
||||
| | |-- 0001_initial.py
|
||||
| | |-- 0002_rename_phote_player_photo.py
|
||||
| | |-- 0003_player_openid.py
|
||||
| | |-- 0004_player_score.py
|
||||
| | |-- __init__.py
|
||||
| | `-- __pycache__
|
||||
| | |-- 0001_initial.cpython-38.pyc
|
||||
| | |-- 0002_rename_phote_player_photo.cpython-38.pyc
|
||||
| | |-- 0003_player_openid.cpython-38.pyc
|
||||
| | |-- 0004_player_score.cpython-38.pyc
|
||||
| | `-- __init__.cpython-38.pyc
|
||||
| |-- models
|
||||
| | |-- __init__.py
|
||||
| | |-- __pycache__
|
||||
| | | `-- __init__.cpython-38.pyc
|
||||
| | `-- player
|
||||
| | |-- __init__.py
|
||||
| | |-- __pycache__
|
||||
| | | |-- __init__.cpython-38.pyc
|
||||
| | | `-- player.cpython-38.pyc
|
||||
| | `-- player.py
|
||||
| |-- routing.py
|
||||
| |-- static
|
||||
| | |-- css
|
||||
| | | `-- game.css
|
||||
| | |-- image
|
||||
| | | |-- lxq.jpg
|
||||
| | | |-- menu
|
||||
| | | | |-- 123.gif
|
||||
| | | | |-- background.gif
|
||||
| | | | `-- ch.jpg
|
||||
| | | |-- playground
|
||||
| | | |-- settings
|
||||
| | | | `-- acwing_logo.png
|
||||
| | | |-- swgq.jpg
|
||||
| | | |-- user_photo
|
||||
| | | `-- zyj.jpg
|
||||
| | `-- js
|
||||
| | |-- dist
|
||||
| | | `-- game.js
|
||||
| | `-- src
|
||||
| | |-- menu
|
||||
| | | |-- cphoto
|
||||
| | | | `-- base.js
|
||||
| | | `-- zbase.js
|
||||
| | |-- playground
|
||||
| | | |-- ac_game_object
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- chat_field
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- game_map
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- notice_board
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- particle
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- player
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- score_board
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- skill
|
||||
| | | | `-- fireball
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- socket
|
||||
| | | | `-- multiplayer
|
||||
| | | | `-- zbase.js
|
||||
| | | `-- zbase.js
|
||||
| | |-- settings
|
||||
| | | `-- zbase.js
|
||||
| | `-- zbase.js
|
||||
| |-- templates
|
||||
| | |-- menu
|
||||
| | | |-- new.html
|
||||
| | | |-- profile.html
|
||||
| | | `-- ranklist\ html
|
||||
| | |-- multiends
|
||||
| | | `-- web.html
|
||||
| | |-- plaground
|
||||
| | `-- settings
|
||||
| |-- tests.py
|
||||
| |-- urls
|
||||
| | |-- __init__.py
|
||||
| | |-- __pycache__
|
||||
| | | |-- __init__.cpython-38.pyc
|
||||
| | | `-- index.cpython-38.pyc
|
||||
| | |-- index.py
|
||||
| | |-- menu
|
||||
| | | |-- __init__.py
|
||||
| | | |-- __pycache__
|
||||
| | | | |-- __init__.cpython-38.pyc
|
||||
| | | | `-- index.cpython-38.pyc
|
||||
| | | `-- index.py
|
||||
| | |-- playground
|
||||
| | | |-- __init__.py
|
||||
| | | |-- __pycache__
|
||||
| | | | |-- __init__.cpython-38.pyc
|
||||
| | | | `-- index.cpython-38.pyc
|
||||
| | | `-- index.py
|
||||
| | `-- settings
|
||||
| | |-- __init__.py
|
||||
| | |-- __pycache__
|
||||
| | | |-- __init__.cpython-38.pyc
|
||||
| | | `-- index.cpython-38.pyc
|
||||
| | |-- acwing
|
||||
| | | |-- __init__.py
|
||||
| | | |-- __pycache__
|
||||
| | | | |-- __init__.cpython-38.pyc
|
||||
| | | | `-- index.cpython-38.pyc
|
||||
| | | `-- index.py
|
||||
| | `-- index.py
|
||||
| `-- views
|
||||
| |-- __init__.py
|
||||
| |-- __pycache__
|
||||
| | |-- __init__.cpython-38.pyc
|
||||
| | `-- index.cpython-38.pyc
|
||||
| |-- index.py
|
||||
| |-- menu
|
||||
| | `-- __init__.py
|
||||
| |-- playground
|
||||
| | `-- __init__.py
|
||||
| `-- settings
|
||||
| |-- __init__.py
|
||||
| |-- __pycache__
|
||||
| | |-- __init__.cpython-38.pyc
|
||||
| | |-- getinfo.cpython-38.pyc
|
||||
| | |-- login.cpython-38.pyc
|
||||
| | |-- logout.cpython-38.pyc
|
||||
| | |-- ranklist.cpython-38.pyc
|
||||
| | `-- register.cpython-38.pyc
|
||||
| |-- acwing
|
||||
| | |-- __init__.py
|
||||
| | |-- __pycache__
|
||||
| | | `-- __init__.cpython-38.pyc
|
||||
| | |-- acapp
|
||||
| | | |-- __init__.py
|
||||
| | | |-- __pycache__
|
||||
| | | | |-- __init__.cpython-38.pyc
|
||||
| | | | |-- apply_code.cpython-38.pyc
|
||||
| | | | `-- receive_code.cpython-38.pyc
|
||||
| | | |-- apply_code.py
|
||||
| | | `-- receive_code.py
|
||||
| | `-- web
|
||||
| | |-- __init__.py
|
||||
| | |-- __pycache__
|
||||
| | | |-- __init__.cpython-38.pyc
|
||||
| | | |-- apply_code.cpython-38.pyc
|
||||
| | | `-- receive_code.cpython-38.pyc
|
||||
| | |-- apply_code.py
|
||||
| | `-- receive_code.py
|
||||
| |-- getinfo.py
|
||||
| |-- ranklist.py
|
||||
| `-- register.py
|
||||
|-- manage.py
|
||||
|-- match_system
|
||||
| |-- __init__.py
|
||||
| |-- __pycache__
|
||||
| | `-- __init__.cpython-38.pyc
|
||||
| |-- src
|
||||
| | |-- __init__.py
|
||||
| | |-- __pycache__
|
||||
| | | `-- __init__.cpython-38.pyc
|
||||
| | |-- main.py
|
||||
| | `-- match_server
|
||||
| | |-- __init__.py
|
||||
| | |-- __pycache__
|
||||
| | | `-- __init__.cpython-38.pyc
|
||||
| | `-- match_service
|
||||
| | |-- Match-remote
|
||||
| | |-- Match.py
|
||||
| | |-- __init__.py
|
||||
| | |-- __pycache__
|
||||
| | | |-- Match.cpython-38.pyc
|
||||
| | | |-- __init__.cpython-38.pyc
|
||||
| | | `-- ttypes.cpython-38.pyc
|
||||
| | |-- constants.py
|
||||
| | `-- ttypes.py
|
||||
| `-- thrift
|
||||
| `-- match.thrift
|
||||
|-- readme.md
|
||||
|-- scripts
|
||||
| |-- compress_game_js.sh
|
||||
| `-- uwsgi.ini
|
||||
|-- static
|
||||
| |-- admin
|
||||
| | |-- css
|
||||
| | | |-- autocomplete.css
|
||||
| | | |-- base.css
|
||||
| | | |-- changelists.css
|
||||
| | | |-- dark_mode.css
|
||||
| | | |-- dashboard.css
|
||||
| | | |-- fonts.css
|
||||
| | | |-- forms.css
|
||||
| | | |-- login.css
|
||||
| | | |-- nav_sidebar.css
|
||||
| | | |-- responsive.css
|
||||
| | | |-- responsive_rtl.css
|
||||
| | | |-- rtl.css
|
||||
| | | |-- vendor
|
||||
| | | | `-- select2
|
||||
| | | | |-- LICENSE-SELECT2.md
|
||||
| | | | |-- select2.css
|
||||
| | | | `-- select2.min.css
|
||||
| | | `-- widgets.css
|
||||
| | |-- fonts
|
||||
| | | |-- LICENSE.txt
|
||||
| | | |-- README.txt
|
||||
| | | |-- Roboto-Bold-webfont.woff
|
||||
| | | |-- Roboto-Light-webfont.woff
|
||||
| | | `-- Roboto-Regular-webfont.woff
|
||||
| | |-- img
|
||||
| | | |-- LICENSE
|
||||
| | | |-- README.txt
|
||||
| | | |-- calendar-icons.svg
|
||||
| | | |-- gis
|
||||
| | | | |-- move_vertex_off.svg
|
||||
| | | | `-- move_vertex_on.svg
|
||||
| | | |-- icon-addlink.svg
|
||||
| | | |-- icon-alert.svg
|
||||
| | | |-- icon-calendar.svg
|
||||
| | | |-- icon-changelink.svg
|
||||
| | | |-- icon-clock.svg
|
||||
| | | |-- icon-deletelink.svg
|
||||
| | | |-- icon-no.svg
|
||||
| | | |-- icon-unknown-alt.svg
|
||||
| | | |-- icon-unknown.svg
|
||||
| | | |-- icon-viewlink.svg
|
||||
| | | |-- icon-yes.svg
|
||||
| | | |-- inline-delete.svg
|
||||
| | | |-- search.svg
|
||||
| | | |-- selector-icons.svg
|
||||
| | | |-- sorting-icons.svg
|
||||
| | | |-- tooltag-add.svg
|
||||
| | | `-- tooltag-arrowright.svg
|
||||
| | `-- js
|
||||
| | |-- SelectBox.js
|
||||
| | |-- SelectFilter2.js
|
||||
| | |-- actions.js
|
||||
| | |-- admin
|
||||
| | | |-- DateTimeShortcuts.js
|
||||
| | | `-- RelatedObjectLookups.js
|
||||
| | |-- autocomplete.js
|
||||
| | |-- calendar.js
|
||||
| | |-- cancel.js
|
||||
| | |-- change_form.js
|
||||
| | |-- collapse.js
|
||||
| | |-- core.js
|
||||
| | |-- filters.js
|
||||
| | |-- inlines.js
|
||||
| | |-- jquery.init.js
|
||||
| | |-- nav_sidebar.js
|
||||
| | |-- popup_response.js
|
||||
| | |-- prepopulate.js
|
||||
| | |-- prepopulate_init.js
|
||||
| | |-- theme.js
|
||||
| | |-- urlify.js
|
||||
| | `-- vendor
|
||||
| | |-- jquery
|
||||
| | | |-- LICENSE.txt
|
||||
| | | |-- jquery.js
|
||||
| | | `-- jquery.min.js
|
||||
| | |-- select2
|
||||
| | | |-- LICENSE.md
|
||||
| | | |-- i18n
|
||||
| | | | |-- af.js
|
||||
| | | | |-- ar.js
|
||||
| | | | |-- az.js
|
||||
| | | | |-- bg.js
|
||||
| | | | |-- bn.js
|
||||
| | | | |-- bs.js
|
||||
| | | | |-- ca.js
|
||||
| | | | |-- cs.js
|
||||
| | | | |-- da.js
|
||||
| | | | |-- de.js
|
||||
| | | | |-- dsb.js
|
||||
| | | | |-- el.js
|
||||
| | | | |-- en.js
|
||||
| | | | |-- es.js
|
||||
| | | | |-- et.js
|
||||
| | | | |-- eu.js
|
||||
| | | | |-- fa.js
|
||||
| | | | |-- fi.js
|
||||
| | | | |-- fr.js
|
||||
| | | | |-- gl.js
|
||||
| | | | |-- he.js
|
||||
| | | | |-- hi.js
|
||||
| | | | |-- hr.js
|
||||
| | | | |-- hsb.js
|
||||
| | | | |-- hu.js
|
||||
| | | | |-- hy.js
|
||||
| | | | |-- id.js
|
||||
| | | | |-- is.js
|
||||
| | | | |-- it.js
|
||||
| | | | |-- ja.js
|
||||
| | | | |-- ka.js
|
||||
| | | | |-- km.js
|
||||
| | | | |-- ko.js
|
||||
| | | | |-- lt.js
|
||||
| | | | |-- lv.js
|
||||
| | | | |-- mk.js
|
||||
| | | | |-- ms.js
|
||||
| | | | |-- nb.js
|
||||
| | | | |-- ne.js
|
||||
| | | | |-- nl.js
|
||||
| | | | |-- pl.js
|
||||
| | | | |-- ps.js
|
||||
| | | | |-- pt-BR.js
|
||||
| | | | |-- pt.js
|
||||
| | | | |-- ro.js
|
||||
| | | | |-- ru.js
|
||||
| | | | |-- sk.js
|
||||
| | | | |-- sl.js
|
||||
| | | | |-- sq.js
|
||||
| | | | |-- sr-Cyrl.js
|
||||
| | | | |-- sr.js
|
||||
| | | | |-- sv.js
|
||||
| | | | |-- th.js
|
||||
| | | | |-- tk.js
|
||||
| | | | |-- tr.js
|
||||
| | | | |-- uk.js
|
||||
| | | | |-- vi.js
|
||||
| | | | |-- zh-CN.js
|
||||
| | | | `-- zh-TW.js
|
||||
| | | |-- select2.full.js
|
||||
| | | `-- select2.full.min.js
|
||||
| | `-- xregexp
|
||||
| | |-- LICENSE.txt
|
||||
| | |-- xregexp.js
|
||||
| | `-- xregexp.min.js
|
||||
| |-- css
|
||||
| | `-- game.css
|
||||
| |-- image
|
||||
| | |-- lxq.jpg
|
||||
| | |-- menu
|
||||
| | | |-- 1.gif
|
||||
| | | |-- 123.gif
|
||||
| | | |-- background.gif
|
||||
| | | `-- ch.jpg
|
||||
| | |-- settings
|
||||
| | | `-- acwing_logo.png
|
||||
| | |-- swgq.jpg
|
||||
| | |-- user_photo
|
||||
| | | |-- lxq.jpg
|
||||
| | | `-- zyj.jpg
|
||||
| | `-- zyj.jpg
|
||||
| |-- js
|
||||
| | |-- dist
|
||||
| | | |-- game.js
|
||||
| | | `-- game.jspython3
|
||||
| | `-- src
|
||||
| | |-- menu
|
||||
| | | |-- cphoto
|
||||
| | | | `-- base.js
|
||||
| | | |-- ranklist
|
||||
| | | `-- zbase.js
|
||||
| | |-- playground
|
||||
| | | |-- ac_game_object
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- chat_field
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- game_map
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- notice_board
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- particle
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- player
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- score_board
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- skill
|
||||
| | | | `-- fireball
|
||||
| | | | `-- zbase.js
|
||||
| | | |-- socket
|
||||
| | | | `-- multiplayer
|
||||
| | | | `-- zbase.js
|
||||
| | | `-- zbase.js
|
||||
| | |-- settings
|
||||
| | | `-- zbase.js
|
||||
| | `-- zbase.js
|
||||
| `-- rest_framework
|
||||
| |-- css
|
||||
| | |-- bootstrap-theme.min.css
|
||||
| | |-- bootstrap-theme.min.css.map
|
||||
| | |-- bootstrap-tweaks.css
|
||||
| | |-- bootstrap.min.css
|
||||
| | |-- bootstrap.min.css.map
|
||||
| | |-- default.css
|
||||
| | |-- font-awesome-4.0.3.css
|
||||
| | `-- prettify.css
|
||||
| |-- docs
|
||||
| | |-- css
|
||||
| | | |-- base.css
|
||||
| | | |-- highlight.css
|
||||
| | | `-- jquery.json-view.min.css
|
||||
| | |-- img
|
||||
| | | |-- favicon.ico
|
||||
| | | `-- grid.png
|
||||
| | `-- js
|
||||
| | |-- api.js
|
||||
| | |-- highlight.pack.js
|
||||
| | `-- jquery.json-view.min.js
|
||||
| |-- fonts
|
||||
| | |-- fontawesome-webfont.eot
|
||||
| | |-- fontawesome-webfont.svg
|
||||
| | |-- fontawesome-webfont.ttf
|
||||
| | |-- fontawesome-webfont.woff
|
||||
| | |-- glyphicons-halflings-regular.eot
|
||||
| | |-- glyphicons-halflings-regular.svg
|
||||
| | |-- glyphicons-halflings-regular.ttf
|
||||
| | |-- glyphicons-halflings-regular.woff
|
||||
| | `-- glyphicons-halflings-regular.woff2
|
||||
| |-- img
|
||||
| | |-- glyphicons-halflings-white.png
|
||||
| | |-- glyphicons-halflings.png
|
||||
| | `-- grid.png
|
||||
| `-- js
|
||||
| |-- ajax-form.js
|
||||
| |-- bootstrap.min.js
|
||||
| |-- coreapi-0.1.1.js
|
||||
| |-- csrf.js
|
||||
| |-- default.js
|
||||
| |-- jquery-3.7.1.min.js
|
||||
| |-- load-ajax-form.js
|
||||
| `-- prettify-min.js
|
||||
`-- terser
|
||||
|
||||
124 directories, 337 files
|
@ -0,0 +1,30 @@
|
||||
import os
|
||||
|
||||
import django
|
||||
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'acapp.settings')
|
||||
|
||||
django.setup()
|
||||
|
||||
from channels.auth import AuthMiddlewareStack
|
||||
from channels.routing import ProtocolTypeRouter, URLRouter
|
||||
from django.core.asgi import get_asgi_application
|
||||
from game.routing import websocket_urlpatterns
|
||||
|
||||
|
||||
from channels.layers import get_channel_layer
|
||||
|
||||
from game.channelsmiddleware import JwtAuthMiddlewareStack
|
||||
|
||||
|
||||
channel_layer = get_channel_layer()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
application = ProtocolTypeRouter({
|
||||
"http": get_asgi_application(),
|
||||
"websocket": JwtAuthMiddlewareStack(URLRouter(websocket_urlpatterns))
|
||||
})
|
@ -0,0 +1,203 @@
|
||||
"""
|
||||
Django settings for acapp project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 3.2.8.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.2/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/3.2/ref/settings/
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
from datetime import timedelta
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'django-insecure-11un1-%3!jwqsi2y4ljne)n$xz$o^43h!+1)o3(b57vcw9==gs'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ["60.205.142.48","app6641.acapp.acwing.com.cn"]
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'channels',
|
||||
'game.apps.GameConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'rest_framework',
|
||||
'rest_framework_simplejwt',
|
||||
]
|
||||
|
||||
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'acapp.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'acapp.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
}
|
||||
}
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django_redis.cache.RedisCache',
|
||||
'LOCATION': 'redis://127.0.0.1:6379/1',
|
||||
"OPTIONS": {
|
||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/3.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'Asia/Shanghai'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.2/howto/static-files/
|
||||
|
||||
STATIC_ROOT = os.path.join(BASE_DIR,'static')
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
|
||||
|
||||
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
|
||||
|
||||
|
||||
ASGI_APPLICATION = 'acapp.asgi.application'
|
||||
CHANNEL_LAYERS = {
|
||||
"default": {
|
||||
"BACKEND": "channels_redis.core.RedisChannelLayer",
|
||||
"CONFIG": {
|
||||
"hosts": [("127.0.0.1", 6379)],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
ROOM_CAPACITY = 3
|
||||
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'rest_framework_simplejwt.authentication.JWTAuthentication',
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
SIMPLE_JWT = {
|
||||
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
|
||||
'REFRESH_TOKEN_LIFETIME': timedelta(days=14),
|
||||
'ROTATE_REFRESH_TOKENS': False,
|
||||
'BLACKLIST_AFTER_ROTATION': False,
|
||||
'UPDATE_LAST_LOGIN': False,
|
||||
|
||||
'ALGORITHM': 'HS256',
|
||||
'SIGNING_KEY': "bsk1194889353",
|
||||
'VERIFYING_KEY': None,
|
||||
'AUDIENCE': None,
|
||||
'ISSUER': None,
|
||||
'JWK_URL': None,
|
||||
'LEEWAY': 0,
|
||||
|
||||
'AUTH_HEADER_TYPES': ('Bearer',),
|
||||
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
|
||||
'USER_ID_FIELD': 'id',
|
||||
'USER_ID_CLAIM': 'user_id',
|
||||
'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
|
||||
|
||||
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
|
||||
'TOKEN_TYPE_CLAIM': 'token_type',
|
||||
'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',
|
||||
|
||||
'JTI_CLAIM': 'jti',
|
||||
|
||||
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
|
||||
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
|
||||
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
"""acapp URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/3.2/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path,include
|
||||
|
||||
urlpatterns = [
|
||||
path('',include('game.urls.index')),
|
||||
path('admin/', admin.site.urls),
|
||||
]
|
@ -0,0 +1,16 @@
|
||||
"""
|
||||
WSGI config for acapp project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'acapp.settings')
|
||||
|
||||
application = get_wsgi_application()
|
@ -0,0 +1,4 @@
|
||||
from django.contrib import admin
|
||||
from game.models.player.player import Player
|
||||
# Register your models here.
|
||||
admin.site.register(Player)
|
@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class GameConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'game'
|
@ -0,0 +1,58 @@
|
||||
"""General web socket middlewares
|
||||
"""
|
||||
|
||||
from channels.db import database_sync_to_async
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from rest_framework_simplejwt.exceptions import InvalidToken, TokenError
|
||||
from rest_framework_simplejwt.tokens import UntypedToken
|
||||
from rest_framework_simplejwt.authentication import JWTTokenUserAuthentication
|
||||
from channels.middleware import BaseMiddleware
|
||||
from channels.auth import AuthMiddlewareStack
|
||||
from django.db import close_old_connections
|
||||
from urllib.parse import parse_qs
|
||||
from jwt import decode as jwt_decode
|
||||
from django.conf import settings
|
||||
@database_sync_to_async
|
||||
def get_user(validated_token):
|
||||
try:
|
||||
user = get_user_model().objects.get(id=validated_token["user_id"])
|
||||
# return get_user_model().objects.get(id=toke_id)
|
||||
return user
|
||||
|
||||
except:
|
||||
return AnonymousUser()
|
||||
|
||||
|
||||
|
||||
class JwtAuthMiddleware(BaseMiddleware):
|
||||
def __init__(self, inner):
|
||||
self.inner = inner
|
||||
|
||||
async def __call__(self, scope, receive, send):
|
||||
# Close old database connections to prevent usage of timed out connections
|
||||
close_old_connections()
|
||||
|
||||
# Try to authenticate the user
|
||||
try:
|
||||
# Get the token
|
||||
token = parse_qs(scope["query_string"].decode("utf8"))["token"][0]
|
||||
|
||||
# This will automatically validate the token and raise an error if token is invalid
|
||||
UntypedToken(token)
|
||||
except:
|
||||
# Token is invalid
|
||||
|
||||
scope["user"] = AnonymousUser()
|
||||
else:
|
||||
# Then token is valid, decode it
|
||||
decoded_data = jwt_decode(token, settings.SIMPLE_JWT["SIGNING_KEY"], algorithms=["HS256"])
|
||||
|
||||
# Get the user using ID
|
||||
scope["user"] = await get_user(validated_token=decoded_data)
|
||||
return await super().__call__(scope, receive, send)
|
||||
|
||||
|
||||
def JwtAuthMiddlewareStack(inner):
|
||||
return JwtAuthMiddleware(AuthMiddlewareStack(inner))
|
||||
|
@ -0,0 +1,176 @@
|
||||
from channels.generic.websocket import AsyncWebsocketConsumer
|
||||
import json
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
|
||||
from thrift import Thrift
|
||||
from thrift.transport import TSocket
|
||||
from thrift.transport import TTransport
|
||||
from thrift.protocol import TBinaryProtocol
|
||||
|
||||
from match_system.src.match_server.match_service import Match
|
||||
from game.models.player.player import Player
|
||||
from channels.db import database_sync_to_async
|
||||
|
||||
class MultiPlayer(AsyncWebsocketConsumer):
|
||||
async def connect(self):
|
||||
user = self.scope['user']
|
||||
print(user,user.is_authenticated)
|
||||
if user.is_authenticated:
|
||||
await self.accept()
|
||||
else:
|
||||
await self.close()
|
||||
|
||||
|
||||
async def disconnect(self, close_code):
|
||||
if hasattr(self,'room_name') and self.room_name:
|
||||
await self.channel_layer.group_discard(self.room_name, self.channel_name);
|
||||
|
||||
|
||||
async def create_player(self, data):
|
||||
self.room_name = None
|
||||
self.uuid = data['uuid']
|
||||
# Make socket
|
||||
transport = TSocket.TSocket('127.0.0.1', 9090)
|
||||
# Buffering is critical. Raw sockets are very slow
|
||||
transport = TTransport.TBufferedTransport(transport)
|
||||
|
||||
# Wrap in a protocol
|
||||
protocol = TBinaryProtocol.TBinaryProtocol(transport)
|
||||
|
||||
# Create a client to use the protocol encoder
|
||||
client = Match.Client(protocol)
|
||||
|
||||
def db_get_player():
|
||||
return Player.objects.get(user__username=data['username'])
|
||||
|
||||
player = await database_sync_to_async(db_get_player)()
|
||||
|
||||
# Connect!
|
||||
transport.open()
|
||||
|
||||
client.add_player(player.score, data['uuid'], data['username'], data['photo'], self.channel_name)
|
||||
|
||||
# Close!
|
||||
transport.close()
|
||||
|
||||
|
||||
async def group_send_event(self, data):
|
||||
if not self.room_name:
|
||||
keys = cache.keys('*%s*' % (self.uuid))
|
||||
if keys:
|
||||
self.room_name = keys[0]
|
||||
await self.send(text_data=json.dumps(data))
|
||||
|
||||
async def move_to(self, data):
|
||||
await self.channel_layer.group_send(
|
||||
self.room_name,
|
||||
{
|
||||
'type': "group_send_event",
|
||||
'event': "move_to",
|
||||
'uuid': data['uuid'],
|
||||
'tx': data['tx'],
|
||||
'ty': data['ty'],
|
||||
}
|
||||
)
|
||||
|
||||
async def shoot_fireball(self, data):
|
||||
await self.channel_layer.group_send(
|
||||
self.room_name,
|
||||
{
|
||||
'type': "group_send_event",
|
||||
'event': "shoot_fireball",
|
||||
'uuid': data['uuid'],
|
||||
'tx': data['tx'],
|
||||
'ty': data['ty'],
|
||||
'ball_uuid': data['ball_uuid'],
|
||||
}
|
||||
)
|
||||
|
||||
async def attack(self, data):
|
||||
if not self.room_name:
|
||||
return
|
||||
players = cache.get(self.room_name)
|
||||
|
||||
if not players:
|
||||
return
|
||||
|
||||
for player in players:
|
||||
if player['uuid'] == data['attackee_uuid']:
|
||||
player['hp'] -= 25
|
||||
|
||||
remain_cnt = 0
|
||||
for player in players:
|
||||
if player['hp'] > 0:
|
||||
remain_cnt += 1
|
||||
|
||||
if remain_cnt > 1:
|
||||
if self.room_name:
|
||||
cache.set(self.room_name, players, 3600)
|
||||
else:
|
||||
def db_update_player_score(username, score):
|
||||
player = Player.objects.get(user__username=username)
|
||||
player.score += score
|
||||
player.save()
|
||||
for player in players:
|
||||
if player['hp'] <= 0:
|
||||
await database_sync_to_async(db_update_player_score)(player['username'], -10)
|
||||
print("down")
|
||||
else:
|
||||
await database_sync_to_async(db_update_player_score)(player['username'], 10)
|
||||
print("up")
|
||||
await self.channel_layer.group_send(
|
||||
self.room_name,
|
||||
{
|
||||
'type': "group_send_event",
|
||||
'event': "attack",
|
||||
'uuid': data['uuid'],
|
||||
'attackee_uuid': data['attackee_uuid'],
|
||||
'x': data['x'],
|
||||
'y': data['y'],
|
||||
'angle': data['angle'],
|
||||
'damage': data['damage'],
|
||||
'ball_uuid': data['ball_uuid'],
|
||||
}
|
||||
)
|
||||
|
||||
async def blink(self, data):
|
||||
await self.channel_layer.group_send(
|
||||
self.room_name,
|
||||
{
|
||||
'type': "group_send_event",
|
||||
'event': "blink",
|
||||
'uuid': data['uuid'],
|
||||
'tx': data['tx'],
|
||||
'ty': data['ty'],
|
||||
}
|
||||
)
|
||||
|
||||
async def message(self, data):
|
||||
await self.channel_layer.group_send(
|
||||
self.room_name,
|
||||
{
|
||||
'type': "group_send_event",
|
||||
'event': "message",
|
||||
'uuid': data['uuid'],
|
||||
'username': data['username'],
|
||||
'text': data['text'],
|
||||
}
|
||||
)
|
||||
|
||||
async def receive(self, text_data):
|
||||
data = json.loads(text_data)
|
||||
event = data['event']
|
||||
if event == "create_player":
|
||||
await self.create_player(data)
|
||||
elif event == "move_to":
|
||||
await self.move_to(data)
|
||||
elif event == "shoot_fireball":
|
||||
await self.shoot_fireball(data)
|
||||
elif event == "attack":
|
||||
await self.attack(data)
|
||||
elif event == "blink":
|
||||
await self.blink(data)
|
||||
elif event == "message":
|
||||
await self.message(data)
|
||||
|
@ -0,0 +1,25 @@
|
||||
# Generated by Django 3.2.8 on 2024-05-15 08:40
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Player',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('phote', models.URLField(blank=True, max_length=256)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.8 on 2024-05-15 08:47
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('game', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='player',
|
||||
old_name='phote',
|
||||
new_name='photo',
|
||||
),
|
||||
]
|
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.8 on 2024-06-11 13:56
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('game', '0002_rename_phote_player_photo'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='player',
|
||||
name='openid',
|
||||
field=models.CharField(blank=True, default='', max_length=50, null=True),
|
||||
),
|
||||
]
|
@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.8 on 2024-08-03 02:43
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('game', '0003_player_openid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='player',
|
||||
name='score',
|
||||
field=models.IntegerField(default=1500),
|
||||
),
|
||||
]
|
@ -0,0 +1,11 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
class Player (models.Model):
|
||||
user = models.OneToOneField(User,on_delete=models.CASCADE)
|
||||
photo = models.URLField(max_length=256,blank=True)
|
||||
openid = models.CharField(default="",max_length=50,blank =True,null=True)
|
||||
score = models.IntegerField(default = 1500)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.user)
|
@ -0,0 +1,5 @@
|
||||
from django.urls import path
|
||||
from game.consumers.multiplayer.index import MultiPlayer
|
||||
websocket_urlpatterns = [
|
||||
path("wss/multiplayer/",MultiPlayer.as_asgi(),name = "wss_multiplayer"),
|
||||
]
|
@ -0,0 +1,203 @@
|
||||
.ac-game-settings{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url("/static/image/menu/123.gif");
|
||||
background-size: 100% 100%;
|
||||
user-select: none;
|
||||
}
|
||||
.ac-game-settings-login{
|
||||
height: 50vh;
|
||||
width: 20vw;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
background-color: rgba(0,0,0,0.7);
|
||||
border-radius: 5px;
|
||||
|
||||
}
|
||||
.ac-game-settings-register{
|
||||
height: 55vh;
|
||||
width: 20vw;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
background-color: rgba(0,0,0,0.7);
|
||||
|
||||
}
|
||||
.ac-game-settings-title {
|
||||
color: white;
|
||||
font-size: 3vh;
|
||||
text-align: center;
|
||||
height: 7vh;
|
||||
padding-top:2vh;
|
||||
margin-bottom:2vh;
|
||||
|
||||
}
|
||||
.ac-game-settings-password{
|
||||
display:block;
|
||||
height:7vh;
|
||||
}
|
||||
.ac-game-settings-submit{
|
||||
display:block;
|
||||
height:7vh;
|
||||
}
|
||||
.ac-game-settings-username{
|
||||
display: block;
|
||||
height:7vh;
|
||||
}
|
||||
.ac-game-settings-item {
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
.ac-game-settings-item > input{
|
||||
width:90%;
|
||||
line-height:3vh;
|
||||
position: relative;
|
||||
top:50%;
|
||||
left:50%;
|
||||
transform: translate(-50%,-50%);
|
||||
|
||||
}
|
||||
.ac-game-settings-item > button{
|
||||
color:white;
|
||||
width:90%;
|
||||
line-height:3vh;
|
||||
position: relative;
|
||||
top:50%;
|
||||
left:50%;
|
||||
transform: translate(-50%,-50%);
|
||||
background-color:#4CAF50;
|
||||
border-radius:5px;
|
||||
|
||||
|
||||
}
|
||||
.ac-game-settings-error-message{
|
||||
color:red;
|
||||
font-size:2vh;
|
||||
display: inline;
|
||||
float:left;
|
||||
padding-left:2vw;
|
||||
}
|
||||
.ac-game-settings-option{
|
||||
color:white;
|
||||
font-size:2vh;
|
||||
display:inline;
|
||||
float:right;
|
||||
padding-right:1vw;
|
||||
cursor:pointer;
|
||||
|
||||
}
|
||||
.ac-game-settings-acwing{
|
||||
display:block;
|
||||
height:7vh;
|
||||
}
|
||||
.ac-game-settings-acwing > img {
|
||||
position: relative;
|
||||
top:50%;
|
||||
left:50%;
|
||||
transform: translate(-50%,-50%);
|
||||
cursor:pointer;
|
||||
clear:both;
|
||||
}
|
||||
.ac-game-settings-acwing > div{
|
||||
color:white;
|
||||
font-size:1.5vh;
|
||||
text-align:center;
|
||||
}
|
||||
.ac-game-menu{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url("/static/image/menu/background.gif");
|
||||
background-size: 100% 100%;
|
||||
user-select: none;
|
||||
|
||||
}
|
||||
|
||||
.ac-game-menu-field{
|
||||
width: 20vw;
|
||||
position: relative;
|
||||
top: 20%;
|
||||
left: 20%;
|
||||
|
||||
}
|
||||
|
||||
.ac-game-menu-field-item{
|
||||
color: white;
|
||||
height: 7vh;
|
||||
width: 50vw;
|
||||
font-size: 5vh;
|
||||
font-style: italic;
|
||||
padding: 2vh;
|
||||
text-align: center;
|
||||
background-color:rgba(39,21,28,0.6);
|
||||
border-radius: 10px;
|
||||
letter-spacing: 0.5vw;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ac-game-menu-field-item:hover{
|
||||
transform: scale(1.2);
|
||||
transition: 100ms;
|
||||
}
|
||||
|
||||
.ac-game-playground{
|
||||
height:100%;
|
||||
width: 100%;
|
||||
user-select:none;
|
||||
background-color:grey;
|
||||
|
||||
}
|
||||
|
||||
.ac-game-playground > canvas {
|
||||
position: relative;
|
||||
top:50%;
|
||||
left:50%;
|
||||
transform: translate(-50%,-50%);
|
||||
|
||||
|
||||
}
|
||||
|
||||
.ac-game-chat-field-history {
|
||||
position: absolute;
|
||||
top: 66%;
|
||||
left: 20%;
|
||||
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
width: 20%;
|
||||
height: 32%;
|
||||
|
||||
color: white;
|
||||
font-size: 2vh;
|
||||
|
||||
padding: 5px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.ac-game-chat-field-history::-webkit-scrollbar {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.ac-game-chat-field-input {
|
||||
position: absolute;
|
||||
top: 86%;
|
||||
left: 20%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
width: 20%;
|
||||
height: 3vh;
|
||||
|
||||
color: white;
|
||||
font-size: 2vh;
|
||||
|
||||
background-color: rgba(222,225,230, 0.2);
|
||||
}
|
||||
|
||||
|
||||
.single-rule{
|
||||
color:white;
|
||||
|
||||
|
||||
}
|
After Width: | Height: | Size: 130 KiB |
After Width: | Height: | Size: 7.2 MiB |
After Width: | Height: | Size: 7.2 MiB |
After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 269 KiB |
@ -0,0 +1,30 @@
|
||||
class Cphoto {
|
||||
constructor(root){
|
||||
this.root = root;
|
||||
this.$cphoto = $(`<div style="background-color: black; color: white; padding: 20px;width: 100%; height:100%;z-index : 9999"></div>`);
|
||||
//this.hide();
|
||||
//this.root.$ac_game.append(this.$cphoto);
|
||||
this.start();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
start(){
|
||||
|
||||
}
|
||||
|
||||
hide(){
|
||||
this.$cphoto.hide();
|
||||
|
||||
}
|
||||
show(){
|
||||
this.$cphoto.show();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,192 @@
|
||||
class AcGameMenu {
|
||||
constructor(root) {
|
||||
this.root = root;
|
||||
this.$menu = $(`
|
||||
<div class="ac-game-menu">
|
||||
<div class="ac-game-menu-field">
|
||||
<div class="ac-game-menu-field-item ac-game-menu-field-item-cphoto">
|
||||
头像选择
|
||||
</div>
|
||||
<div class="ac-game-menu-field-item ac-game-menu-field-item-single-mode">
|
||||
单人模式
|
||||
</div>
|
||||
<br>
|
||||
<div class="ac-game-menu-field-item ac-game-menu-field-item-multi-mode">
|
||||
多人模式
|
||||
</div>
|
||||
<div class="ac-game-menu-field-item ac-game-menu-field-item-ranklist">
|
||||
天梯榜
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="ac-game-menu-field-item ac-game-menu-field-item-settings">
|
||||
退出
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
this.$menu.hide();
|
||||
this.root.$ac_game.append(this.$menu);
|
||||
this.$single_mode = this.$menu.find('.ac-game-menu-field-item-single-mode');
|
||||
this.$multi_mode = this.$menu.find('.ac-game-menu-field-item-multi-mode');
|
||||
this.$settings = this.$menu.find('.ac-game-menu-field-item-settings');
|
||||
this.$cphoto_button = this.$menu.find('.ac-game-menu-field-item-cphoto');
|
||||
this.$ranklist_button = this.$menu.find('.ac-game-menu-field-item-ranklist')
|
||||
this.start();
|
||||
}
|
||||
|
||||
start() {
|
||||
this.add_listening_events();
|
||||
}
|
||||
|
||||
add_listening_events() {
|
||||
|
||||
let outer = this;
|
||||
this.$single_mode.click(function () {
|
||||
outer.hide();
|
||||
outer.root.playground.show("single mode");
|
||||
|
||||
});
|
||||
this.$multi_mode.click(function () {
|
||||
|
||||
|
||||
outer.hide();
|
||||
outer.root.playground.show("multi mode");
|
||||
});
|
||||
this.$settings.click(function () {
|
||||
outer.root.settings.logout_on_remote();
|
||||
});
|
||||
this.$cphoto_button.click(function () {
|
||||
window.location.href = '/photo';
|
||||
|
||||
console.log(outer.root.settings.photo);
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
this.$ranklist_button.click(function () {
|
||||
$.ajax({
|
||||
url: "https://app6641.acapp.acwing.com.cn/settings/ranklist/",
|
||||
type: "GET",
|
||||
headers: {
|
||||
'Authorization': "Bearer " + outer.root.access,
|
||||
},
|
||||
success: function (resp) {
|
||||
// 清空当前页面内容
|
||||
document.body.innerHTML = `
|
||||
<div style="text-align: center; margin-top: 20px;">
|
||||
<button id="logout-button" style="
|
||||
padding: 10px 20px;
|
||||
background-color: #f44336;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
margin-bottom: 20px;
|
||||
">退出</button>
|
||||
<h1>用户排名</h1>
|
||||
</div>
|
||||
<table style="
|
||||
width: 60%;
|
||||
margin: auto;
|
||||
border-collapse: collapse;
|
||||
">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
">排名</th>
|
||||
<th style="
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
">头像</th>
|
||||
<th style="
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
">用户名</th>
|
||||
<th style="
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
">分数</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="ranklist-body">
|
||||
<!-- 用户排名信息将通过 JavaScript 插入到这里 -->
|
||||
</tbody>
|
||||
</table>
|
||||
`;
|
||||
|
||||
// 获取表格主体的 DOM 元素
|
||||
const ranklistBody = document.getElementById('ranklist-body');
|
||||
|
||||
// 遍历用户数据并生成 HTML 行
|
||||
resp.forEach((user, index) => {
|
||||
const row = document.createElement('tr');
|
||||
|
||||
// 排名
|
||||
const rankCell = document.createElement('td');
|
||||
rankCell.textContent = index + 1;
|
||||
rankCell.setAttribute("style", "padding: 10px; border: 1px solid #ddd; text-align: center;");
|
||||
row.appendChild(rankCell);
|
||||
|
||||
// 头像
|
||||
const photoCell = document.createElement('td');
|
||||
const img = document.createElement('img');
|
||||
img.src = user.photo;
|
||||
img.alt = user.username;
|
||||
img.setAttribute("style", "width: 50px; height: 50px; border-radius: 50%;");
|
||||
photoCell.appendChild(img);
|
||||
photoCell.setAttribute("style", "padding: 10px; border: 1px solid #ddd; text-align: center;");
|
||||
row.appendChild(photoCell);
|
||||
|
||||
// 用户名
|
||||
const usernameCell = document.createElement('td');
|
||||
usernameCell.textContent = user.username;
|
||||
usernameCell.setAttribute("style", "padding: 10px; border: 1px solid #ddd; text-align: center;");
|
||||
row.appendChild(usernameCell);
|
||||
|
||||
// 分数
|
||||
const scoreCell = document.createElement('td');
|
||||
scoreCell.textContent = user.score;
|
||||
scoreCell.setAttribute("style", "padding: 10px; border: 1px solid #ddd; text-align: center;");
|
||||
row.appendChild(scoreCell);
|
||||
|
||||
// 将行添加到表格主体中
|
||||
ranklistBody.appendChild(row);
|
||||
});
|
||||
|
||||
// 添加“退出”按钮点击事件
|
||||
document.getElementById('logout-button').addEventListener('click', () => {
|
||||
window.location.href = "https://app6641.acapp.acwing.com.cn/"; // 将此路径替换为实际的注销页面路径
|
||||
});
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
console.error("请求失败:", error);
|
||||
alert("无法获取排名列表,请稍后重试。");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
show() {
|
||||
this.$menu.show();
|
||||
}
|
||||
|
||||
|
||||
hide() {
|
||||
this.$menu.hide();
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
let AC_GAME_OBJECTS = [];
|
||||
|
||||
class AcGameObject {
|
||||
constructor() {
|
||||
AC_GAME_OBJECTS.push(this);
|
||||
|
||||
this.has_called_start = false; // 是否执行过start函数
|
||||
this.timedelta = 0; // 当前帧距离上一帧的时间间隔
|
||||
this.uuid = this.create_uuid();
|
||||
}
|
||||
create_uuid() {
|
||||
let res = "";
|
||||
for(let i = 0;i < 8 ; i++){
|
||||
let x = parseInt(Math.floor(Math.random()*10));
|
||||
res += x;
|
||||
}
|
||||
return res;
|
||||
|
||||
|
||||
}
|
||||
start() { // 只会在第一帧执行一次
|
||||
}
|
||||
|
||||
update() { // 每一帧均会执行一次
|
||||
}
|
||||
|
||||
|
||||
late_update(){
|
||||
|
||||
|
||||
}
|
||||
|
||||
on_destroy() { // 在被销毁前执行一次
|
||||
}
|
||||
|
||||
destroy() { // 删掉该物体
|
||||
this.on_destroy();
|
||||
|
||||
for (let i = 0; i < AC_GAME_OBJECTS.length; i ++ ) {
|
||||
if (AC_GAME_OBJECTS[i] === this) {
|
||||
AC_GAME_OBJECTS.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let last_timestamp;
|
||||
let AC_GAME_ANIMATION = function(timestamp) {
|
||||
for (let i = 0; i < AC_GAME_OBJECTS.length; i ++ ) {
|
||||
let obj = AC_GAME_OBJECTS[i];
|
||||
if (!obj.has_called_start) {
|
||||
obj.start();
|
||||
obj.has_called_start = true;
|
||||
} else {
|
||||
obj.timedelta = timestamp - last_timestamp;
|
||||
obj.update();
|
||||
}
|
||||
}
|
||||
|
||||
for(let i = 0;i< AC_GAME_OBJECTS.length;i++){
|
||||
let obj = AC_GAME_OBJECTS[i];
|
||||
obj.late_update();
|
||||
|
||||
}
|
||||
last_timestamp = timestamp;
|
||||
|
||||
requestAnimationFrame(AC_GAME_ANIMATION);
|
||||
}
|
||||
|
||||
|
||||
requestAnimationFrame(AC_GAME_ANIMATION);
|
||||
|
@ -0,0 +1,97 @@
|
||||
class ChatField{
|
||||
constructor(playground){
|
||||
console.log("chat");
|
||||
this.playground = playground;
|
||||
this.$history = $(`<div class = "ac-game-chat-field-history"></div>`)
|
||||
this.$input = $(`<input type="text" class = "ac-game-chat-field-input">`)
|
||||
|
||||
this.$history.hide();
|
||||
this.$input.hide();
|
||||
this.playground.$playground.append(this.$history);
|
||||
this.playground.$playground.append(this.$input);
|
||||
this.start();
|
||||
this.function_id = null;
|
||||
|
||||
}
|
||||
start(){
|
||||
this.add_listening_events();
|
||||
|
||||
}
|
||||
|
||||
add_listening_events(){
|
||||
let outer =this;
|
||||
this.$input.keydown(function(e){
|
||||
if(e.which === 27){
|
||||
outer.hide_input();
|
||||
return false;
|
||||
|
||||
|
||||
|
||||
}else if (e.which === 13){
|
||||
let username = outer.playground.root.settings.username;
|
||||
let text = outer.$input.val();
|
||||
if(text){
|
||||
outer.$input.val("");
|
||||
|
||||
outer.add_message(username,text);
|
||||
outer.playground.mps.send_message(text);
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
show_history(){
|
||||
let outer = this;
|
||||
|
||||
this.$history.fadeIn();
|
||||
if(this.function_id){
|
||||
|
||||
clearTimeout(this.function_id);
|
||||
|
||||
}
|
||||
this.function_id = setTimeout(function(){
|
||||
outer.$history.fadeOut();
|
||||
outer.function_id = null;
|
||||
|
||||
},3000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
show_input(){
|
||||
this.show_history();
|
||||
|
||||
|
||||
this.$input.show();
|
||||
this.$input.focus();
|
||||
|
||||
|
||||
}
|
||||
|
||||
hide_input(){
|
||||
this.$input.hide();
|
||||
this.playground.game_map.$canvas.focus();
|
||||
|
||||
}
|
||||
add_message(username,text){
|
||||
this.show_history();
|
||||
|
||||
let message = `[${username}]${text}`
|
||||
this.$history.append(this.render_message(message));
|
||||
this.$history.scrollTop(this.$history[0].scrollHeight);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
render_message(message){
|
||||
return $(`<div>${message}</div>`);
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
class GameMap extends AcGameObject{
|
||||
constructor(playground){
|
||||
super();
|
||||
this.playground=playground;
|
||||
this.$canvas = $(`<canvas tabindex = 0></canvas>`);
|
||||
this.ctx = this.$canvas[0].getContext('2d');
|
||||
this.ctx.canvas.width = this.playground.width;
|
||||
this.ctx.canvas.height = this.playground.height;
|
||||
this.playground.$playground.append(this.$canvas);
|
||||
|
||||
}
|
||||
start(){
|
||||
this.$canvas.focus();
|
||||
|
||||
}
|
||||
|
||||
resize(){
|
||||
this.ctx.canvas.width = this.playground.width;
|
||||
this.ctx.canvas.height = this.playground.height;
|
||||
this.ctx.fillStyle = "rgba(0,0,0)";
|
||||
this.ctx.fillRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height);
|
||||
|
||||
}
|
||||
update(){
|
||||
this.render();
|
||||
}
|
||||
|
||||
render(){
|
||||
this.ctx.fillStyle = "rgba(0,0,0,0.2)";
|
||||
this.ctx.fillRect(0,0,this.ctx.canvas.width,this.ctx.canvas.height);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
class Particle extends AcGameObject{
|
||||
constructor(playground,x,y,radius,vx,vy,color,speed,move_length){
|
||||
super();
|
||||
this.playground = playground;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.radius = radius;
|
||||
this.vx= vx;
|
||||
this.vy = vy;
|
||||
this.color = color;
|
||||
this.speed = speed;
|
||||
this.ctx = this.playground.game_map.ctx;
|
||||
this.fraction = 0.9;
|
||||
this.eps = 0.01;
|
||||
this.move_length = move_length;
|
||||
}
|
||||
start(){
|
||||
|
||||
}
|
||||
|
||||
update(){
|
||||
if(this.move_length< this.eps||this.speed< this.eps){
|
||||
this.destroy();
|
||||
return false;
|
||||
|
||||
}
|
||||
let moved = Math.min(this.move_length,this.speed*this.timedelta/1000);
|
||||
this.x += this.vx*moved;
|
||||
this.y += this.vy*moved;
|
||||
this.speed *= this.fraction;
|
||||
this.move_length -= moved;
|
||||
this.render();
|
||||
}
|
||||
|
||||
render(){
|
||||
let scale = this.playground.scale;
|
||||
this.ctx.beginPath();
|
||||
this.ctx.arc(this.x * scale,this.y * scale,this.radius * scale,0,Math.PI * 2,false);
|
||||
this.ctx.fillStyle = this.color;
|
||||
this.ctx.fill();
|
||||
}
|
||||
}
|
@ -0,0 +1,364 @@
|
||||
class Player extends AcGameObject {
|
||||
constructor(playground, x, y, radius, color, speed, character, username, photo) {
|
||||
super();
|
||||
this.playground = playground;
|
||||
this.ctx = this.playground.game_map.ctx;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.vx = 0;
|
||||
this.vy = 0;
|
||||
this.damage_x = 0;
|
||||
this.damage_y = 0;
|
||||
this.damage_speed = 0;
|
||||
this.move_length = 0;
|
||||
this.radius = radius;
|
||||
this.color = color;
|
||||
this.speed = speed;
|
||||
this.character = character;
|
||||
this.username = username;
|
||||
this.photo = photo;
|
||||
this.eps = 0.01;
|
||||
this.friction = 0.9;
|
||||
this.spent_time = 0;
|
||||
this.fireballs = [];
|
||||
|
||||
this.cur_skill = null;
|
||||
|
||||
if (this.character !== "robot") {
|
||||
this.img = new Image();
|
||||
this.img.src = this.photo;
|
||||
}
|
||||
|
||||
if (this.character === "me") {
|
||||
this.fireball_coldtime = 3; // 单位:秒
|
||||
this.fireball_img = new Image();
|
||||
this.fireball_img.src = "https://cdn.acwing.com/media/article/image/2021/12/02/1_9340c86053-fireball.png";
|
||||
|
||||
this.blink_coldtime = 5; // 单位:秒
|
||||
this.blink_img = new Image();
|
||||
this.blink_img.src = "https://cdn.acwing.com/media/article/image/2021/12/02/1_daccabdc53-blink.png";
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
this.playground.player_count ++ ;
|
||||
console.log(this.playground.player_count);
|
||||
|
||||
this.playground.notice_board.write("匹配中");
|
||||
|
||||
if (this.playground.player_count >= 3) {
|
||||
this.playground.state = "fighting";
|
||||
this.playground.notice_board.write("Fighting");
|
||||
}
|
||||
|
||||
if (this.character === "me") {
|
||||
this.add_listening_events();
|
||||
} else if (this.character === "robot") {
|
||||
let tx = Math.random() * this.playground.width / this.playground.scale;
|
||||
let ty = Math.random() * this.playground.height / this.playground.scale;
|
||||
this.move_to(tx, ty);
|
||||
}
|
||||
}
|
||||
|
||||
add_listening_events() {
|
||||
let outer = this;
|
||||
this.playground.game_map.$canvas.on("contextmenu", function() {
|
||||
return false;
|
||||
});
|
||||
this.playground.game_map.$canvas.mousedown(function(e) {
|
||||
|
||||
|
||||
if (outer.playground.state !== "fighting")
|
||||
return true;
|
||||
|
||||
const rect = outer.ctx.canvas.getBoundingClientRect();
|
||||
if (e.which === 3) {
|
||||
let tx = (e.clientX - rect.left) / outer.playground.scale;
|
||||
let ty = (e.clientY - rect.top) / outer.playground.scale;
|
||||
outer.move_to(tx, ty);
|
||||
|
||||
if (outer.playground.mode === "multi mode") {
|
||||
outer.playground.mps.send_move_to(tx, ty);
|
||||
}
|
||||
} else if (e.which === 1) {
|
||||
let tx = (e.clientX - rect.left) / outer.playground.scale;
|
||||
let ty = (e.clientY - rect.top) / outer.playground.scale;
|
||||
if (outer.cur_skill === "fireball") {
|
||||
if (outer.fireball_coldtime > outer.eps)
|
||||
return false;
|
||||
|
||||
let fireball = outer.shoot_fireball(tx, ty);
|
||||
|
||||
if (outer.playground.mode === "multi mode") {
|
||||
outer.playground.mps.send_shoot_fireball(tx, ty, fireball.uuid);
|
||||
}
|
||||
} else if (outer.cur_skill === "blink") {
|
||||
if (outer.blink_coldtime > outer.eps)
|
||||
return false;
|
||||
|
||||
outer.blink(tx, ty);
|
||||
|
||||
if (outer.playground.mode === "multi mode") {
|
||||
outer.playground.mps.send_blink(tx, ty);
|
||||
}
|
||||
}
|
||||
|
||||
outer.cur_skill = null;
|
||||
}
|
||||
});
|
||||
|
||||
this.playground.game_map.$canvas.keydown(function(e) {
|
||||
console.log(e.which);
|
||||
if(e.which === 13){
|
||||
if(outer.playground.mode === "multi mode")
|
||||
outer.playground.chat_field.show_input();//打开了聊天框
|
||||
|
||||
|
||||
|
||||
} else if (e.which === 27){
|
||||
if(outer.playground.mode === "multi mode"){
|
||||
outer.playground.chat_field.hide_input();
|
||||
}
|
||||
}
|
||||
|
||||
if (outer.playground.state !== "fighting")
|
||||
return true;
|
||||
|
||||
if (e.which === 81) { // q
|
||||
if (outer.fireball_coldtime > outer.eps)
|
||||
return true;
|
||||
|
||||
outer.cur_skill = "fireball";
|
||||
return false;
|
||||
} else if (e.which === 70) { // f
|
||||
if (outer.blink_coldtime > outer.eps)
|
||||
return true;
|
||||
|
||||
outer.cur_skill = "blink";
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
shoot_fireball(tx, ty) {
|
||||
let x = this.x, y = this.y;
|
||||
let radius = 0.01;
|
||||
let angle = Math.atan2(ty - this.y, tx - this.x);
|
||||
let vx = Math.cos(angle), vy = Math.sin(angle);
|
||||
let color = "orange";
|
||||
let speed = 0.5;
|
||||
let move_length = 1;
|
||||
let fireball = new FireBall(this.playground, this, x, y, radius, vx, vy, color, speed, move_length, 0.01);
|
||||
this.fireballs.push(fireball);
|
||||
|
||||
this.fireball_coldtime = 3;
|
||||
|
||||
return fireball;
|
||||
}
|
||||
|
||||
destroy_fireball(uuid) {
|
||||
for (let i = 0; i < this.fireballs.length; i ++ ) {
|
||||
let fireball = this.fireballs[i];
|
||||
if (fireball.uuid === uuid) {
|
||||
fireball.destroy();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blink(tx, ty) {
|
||||
let d = this.get_dist(this.x, this.y, tx, ty);
|
||||
d = Math.min(d, 0.8);
|
||||
let angle = Math.atan2(ty - this.y, tx - this.x);
|
||||
this.x += d * Math.cos(angle);
|
||||
this.y += d * Math.sin(angle);
|
||||
|
||||
this.blink_coldtime = 5;
|
||||
this.move_length = 0; // 闪现完停下来
|
||||
}
|
||||
|
||||
get_dist(x1, y1, x2, y2) {
|
||||
let dx = x1 - x2;
|
||||
let dy = y1 - y2;
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
move_to(tx, ty) {
|
||||
this.move_length = this.get_dist(this.x, this.y, tx, ty);
|
||||
let angle = Math.atan2(ty - this.y, tx - this.x);
|
||||
this.vx = Math.cos(angle);
|
||||
this.vy = Math.sin(angle);
|
||||
}
|
||||
|
||||
is_attacked(angle, damage) {
|
||||
for (let i = 0; i < 20 + Math.random() * 10; i ++ ) {
|
||||
let x = this.x, y = this.y;
|
||||
let radius = this.radius * Math.random() * 0.1;
|
||||
let angle = Math.PI * 2 * Math.random();
|
||||
let vx = Math.cos(angle), vy = Math.sin(angle);
|
||||
let color = this.color;
|
||||
let speed = this.speed * 10;
|
||||
let move_length = this.radius * Math.random() * 5;
|
||||
new Particle(this.playground, x, y, radius, vx, vy, color, speed, move_length);
|
||||
}
|
||||
this.radius -= damage;
|
||||
if (this.radius < this.eps) {
|
||||
this.destroy();
|
||||
return false;
|
||||
}
|
||||
this.damage_x = Math.cos(angle);
|
||||
this.damage_y = Math.sin(angle);
|
||||
this.damage_speed = damage * 100;
|
||||
this.speed *= 0.8;
|
||||
}
|
||||
|
||||
receive_attack(x, y, angle, damage, ball_uuid, attacker) {
|
||||
attacker.destroy_fireball(ball_uuid);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.is_attacked(angle, damage);
|
||||
}
|
||||
|
||||
update() {
|
||||
this.spent_time += this.timedelta / 1000;
|
||||
this.update_win();
|
||||
|
||||
if (this.character === "me" && this.playground.state === "fighting") {
|
||||
this.update_coldtime();
|
||||
}
|
||||
this.update_move();
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
update_win(){
|
||||
if(this.playground.state === "fighting" && this.character === "me" && this.playground.players.length === 1){
|
||||
this.state = "over";
|
||||
this.playground.score_board.win();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
update_coldtime() {
|
||||
this.fireball_coldtime -= this.timedelta / 1000;
|
||||
this.fireball_coldtime = Math.max(this.fireball_coldtime, 0);
|
||||
|
||||
this.blink_coldtime -= this.timedelta / 1000;
|
||||
this.blink_coldtime = Math.max(this.blink_coldtime, 0);
|
||||
}
|
||||
|
||||
update_move() { // 更新玩家移动
|
||||
if (this.character === "robot" && this.spent_time > 4 && Math.random() < 1 / 300.0) {
|
||||
let player = this.playground.players[Math.floor(Math.random() * this.playground.players.length)];
|
||||
let tx = player.x + player.speed * this.vx * this.timedelta / 1000 * 0.3;
|
||||
let ty = player.y + player.speed * this.vy * this.timedelta / 1000 * 0.3;
|
||||
this.shoot_fireball(tx, ty);
|
||||
}
|
||||
|
||||
if (this.damage_speed > this.eps) {
|
||||
this.vx = this.vy = 0;
|
||||
this.move_length = 0;
|
||||
this.x += this.damage_x * this.damage_speed * this.timedelta / 1000;
|
||||
this.y += this.damage_y * this.damage_speed * this.timedelta / 1000;
|
||||
this.damage_speed *= this.friction;
|
||||
} else {
|
||||
if (this.move_length < this.eps) {
|
||||
this.move_length = 0;
|
||||
this.vx = this.vy = 0;
|
||||
if (this.character === "robot") {
|
||||
let tx = Math.random() * this.playground.width / this.playground.scale;
|
||||
let ty = Math.random() * this.playground.height / this.playground.scale;
|
||||
this.move_to(tx, ty);
|
||||
}
|
||||
} else {
|
||||
let moved = Math.min(this.move_length, this.speed * this.timedelta / 1000);
|
||||
this.x += this.vx * moved;
|
||||
this.y += this.vy * moved;
|
||||
this.move_length -= moved;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let scale = this.playground.scale;
|
||||
if (this.character !== "robot") {
|
||||
this.ctx.save();
|
||||
this.ctx.beginPath();
|
||||
this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false);
|
||||
this.ctx.stroke();
|
||||
this.ctx.clip();
|
||||
this.ctx.drawImage(this.img, (this.x - this.radius) * scale, (this.y - this.radius) * scale, this.radius * 2 * scale, this.radius * 2 * scale);
|
||||
this.ctx.restore();
|
||||
} else {
|
||||
this.ctx.beginPath();
|
||||
this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false);
|
||||
this.ctx.fillStyle = this.color;
|
||||
this.ctx.fill();
|
||||
}
|
||||
|
||||
if (this.character === "me" && this.playground.state === "fighting") {
|
||||
this.render_skill_coldtime();
|
||||
}
|
||||
}
|
||||
|
||||
render_skill_coldtime() {
|
||||
let scale = this.playground.scale;
|
||||
let x = 1.5, y = 0.9, r = 0.04;
|
||||
|
||||
this.ctx.save();
|
||||
this.ctx.beginPath();
|
||||
this.ctx.arc(x * scale, y * scale, r * scale, 0, Math.PI * 2, false);
|
||||
this.ctx.stroke();
|
||||
this.ctx.clip();
|
||||
this.ctx.drawImage(this.fireball_img, (x - r) * scale, (y - r) * scale, r * 2 * scale, r * 2 * scale);
|
||||
this.ctx.restore();
|
||||
|
||||
if (this.fireball_coldtime > 0) {
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(x * scale, y * scale);
|
||||
this.ctx.arc(x * scale, y * scale, r * scale, 0 - Math.PI / 2, Math.PI * 2 * (1 - this.fireball_coldtime / 3) - Math.PI / 2, true);
|
||||
this.ctx.lineTo(x * scale, y * scale);
|
||||
this.ctx.fillStyle = "rgba(0, 0, 255, 0.6)";
|
||||
this.ctx.fill();
|
||||
}
|
||||
|
||||
x = 1.62, y = 0.9, r = 0.04;
|
||||
this.ctx.save();
|
||||
this.ctx.beginPath();
|
||||
this.ctx.arc(x * scale, y * scale, r * scale, 0, Math.PI * 2, false);
|
||||
this.ctx.stroke();
|
||||
this.ctx.clip();
|
||||
this.ctx.drawImage(this.blink_img, (x - r) * scale, (y - r) * scale, r * 2 * scale, r * 2 * scale);
|
||||
this.ctx.restore();
|
||||
|
||||
if (this.blink_coldtime > 0) {
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(x * scale, y * scale);
|
||||
this.ctx.arc(x * scale, y * scale, r * scale, 0 - Math.PI / 2, Math.PI * 2 * (1 - this.blink_coldtime / 5) - Math.PI / 2, true);
|
||||
this.ctx.lineTo(x * scale, y * scale);
|
||||
this.ctx.fillStyle = "rgba(0, 0, 255, 0.6)";
|
||||
this.ctx.fill();
|
||||
}
|
||||
}
|
||||
|
||||
on_destroy() {
|
||||
if (this.character === "me"){
|
||||
if(this.playground.state === "fighting"){
|
||||
this.playground.state = "over";
|
||||
this.playground.score_board.lose();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.playground.players.length; i ++ ) {
|
||||
if (this.playground.players[i] === this) {
|
||||
this.playground.players.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,98 @@
|
||||
class FireBall extends AcGameObject {
|
||||
constructor(playground,player,x,y,radius,vx,vy,color,speed,move_length,damage){
|
||||
super();
|
||||
this.playground=playground;
|
||||
this.ctx = this.playground.game_map.ctx;
|
||||
this.player = player;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.radius = radius;
|
||||
this.vx = vx;
|
||||
this.vy = vy;
|
||||
this.color = color;
|
||||
this.speed = speed ;
|
||||
this.move_length = move_length;
|
||||
this.eps = 0.01;
|
||||
this.damage = damage;
|
||||
|
||||
}
|
||||
start(){
|
||||
}
|
||||
|
||||
update(){
|
||||
if(this.move_length < this.eps){
|
||||
this.destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
this.update_move();
|
||||
if(this.player.charactr !== "enemy"){
|
||||
this.update_attack();
|
||||
}
|
||||
this.render();
|
||||
}
|
||||
update_move(){
|
||||
let moved = Math.min(this.move_length,this.speed * this.timedelta / 1000);
|
||||
this.x += this.vx * moved;
|
||||
this.y += this.vy * moved;
|
||||
this.move_length -= moved;
|
||||
}
|
||||
|
||||
update_attack(){
|
||||
for ( let i=0;i<this.playground.players.length; i++ ){
|
||||
let player = this.playground.players[i];
|
||||
|
||||
if(this.player !== player && this.is_collision(player)){
|
||||
this.attack(player);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
get_dist(x1,y1,x2,y2){
|
||||
let dx= x1-x2;
|
||||
let dy = y1-y2;
|
||||
return Math.sqrt(dx*dx + dy*dy);
|
||||
|
||||
}
|
||||
|
||||
|
||||
is_collision(obj){
|
||||
let distance = this.get_dist(this.x,this.y,obj.x,obj.y);
|
||||
if(distance < this.radius + obj.radius)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
attack(player){
|
||||
let angle = Math.atan2(player.y - this.y,player.x-this.x);
|
||||
|
||||
player.is_attacked(angle,this.damage);
|
||||
if (this.playground.mode === "multi mode"){
|
||||
|
||||
console.log(this.damage);
|
||||
this.playground.mps.send_attack(player.uuid,player.x,player.y,angle,this.damage,this.uuid);
|
||||
|
||||
}
|
||||
this.destroy();
|
||||
|
||||
|
||||
}
|
||||
|
||||
render(){
|
||||
let scale = this.playground.scale
|
||||
this.ctx.beginPath();
|
||||
this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0,
|
||||
Math.PI * 2, false); this.ctx.fillStyle = this.color;
|
||||
this.ctx.fill(); }
|
||||
on_destroy() {
|
||||
let fireballs = this.player.fireballs;
|
||||
for(let i=0;i<fireballs.length;i++)
|
||||
if(fireballs[i] === this){
|
||||
fireballs.splice(i,1);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
class MultiPlayerSocket {
|
||||
constructor(playground) {
|
||||
this.playground = playground;
|
||||
|
||||
this.ws = new WebSocket("wss://app6641.acapp.acwing.com.cn/wss/multiplayer/?token=" + playground.root.access);
|
||||
|
||||
this.start();
|
||||
}
|
||||
|
||||
start() {
|
||||
this.receive();
|
||||
}
|
||||
|
||||
receive () {
|
||||
let outer = this;
|
||||
|
||||
this.ws.onmessage = function(e) {
|
||||
let data = JSON.parse(e.data);
|
||||
let uuid = data.uuid;
|
||||
if (uuid === outer.uuid) return false;
|
||||
|
||||
let event = data.event;
|
||||
if (event === "create_player") {
|
||||
outer.receive_create_player(uuid, data.username, data.photo);
|
||||
} else if (event === "move_to") {
|
||||
outer.receive_move_to(uuid, data.tx, data.ty);
|
||||
} else if (event === "shoot_fireball") {
|
||||
outer.receive_shoot_fireball(uuid, data.tx, data.ty, data.ball_uuid);
|
||||
} else if (event === "attack") {
|
||||
outer.receive_attack(uuid, data.attackee_uuid, data.x, data.y, data.angle, data.damage, data.ball_uuid);
|
||||
} else if (event === "blink") {
|
||||
outer.receive_blink(uuid, data.tx, data.ty);
|
||||
} else if(event === "message"){
|
||||
outer.receive_message(uuid,data.text);
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
send_create_player(username, photo) {
|
||||
let outer = this;
|
||||
this.ws.send(JSON.stringify({
|
||||
'event': "create_player",
|
||||
'uuid': outer.uuid,
|
||||
'username': username,
|
||||
'photo': photo,
|
||||
}));
|
||||
}
|
||||
|
||||
get_player(uuid) {
|
||||
let players = this.playground.players;
|
||||
for (let i = 0; i < players.length; i ++ ) {
|
||||
let player = players[i];
|
||||
if (player.uuid === uuid)
|
||||
return player;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
receive_create_player(uuid, username, photo) {
|
||||
let player = new Player(
|
||||
this.playground,
|
||||
this.playground.width / 2 / this.playground.scale,
|
||||
0.5,
|
||||
0.05,
|
||||
"white",
|
||||
0.15,
|
||||
"enemy",
|
||||
username,
|
||||
photo,
|
||||
);
|
||||
|
||||
player.uuid = uuid;
|
||||
this.playground.players.push(player);
|
||||
}
|
||||
|
||||
send_move_to(tx, ty) {
|
||||
let outer = this;
|
||||
this.ws.send(JSON.stringify({
|
||||
'event': "move_to",
|
||||
'uuid': outer.uuid,
|
||||
'tx': tx,
|
||||
'ty': ty,
|
||||
}));
|
||||
}
|
||||
|
||||
receive_move_to(uuid, tx, ty) {
|
||||
let player = this.get_player(uuid);
|
||||
|
||||
if (player) {
|
||||
player.move_to(tx, ty);
|
||||
}
|
||||
}
|
||||
|
||||
send_shoot_fireball(tx, ty, ball_uuid) {
|
||||
let outer = this;
|
||||
this.ws.send(JSON.stringify({
|
||||
'event': "shoot_fireball",
|
||||
'uuid': outer.uuid,
|
||||
'tx': tx,
|
||||
'ty': ty,
|
||||
'ball_uuid': ball_uuid,
|
||||
}));
|
||||
}
|
||||
|
||||
receive_shoot_fireball(uuid, tx, ty, ball_uuid) {
|
||||
let player = this.get_player(uuid);
|
||||
if (player) {
|
||||
let fireball = player.shoot_fireball(tx, ty);
|
||||
fireball.uuid = ball_uuid;
|
||||
}
|
||||
}
|
||||
|
||||
send_attack(attackee_uuid, x, y, angle, damage, ball_uuid) {
|
||||
let outer = this;
|
||||
this.ws.send(JSON.stringify({
|
||||
'event': "attack",
|
||||
'uuid': outer.uuid,
|
||||
'attackee_uuid': attackee_uuid,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'angle': angle,
|
||||
'damage': damage,
|
||||
'ball_uuid': ball_uuid,
|
||||
}));
|
||||
}
|
||||
|
||||
receive_attack(uuid, attackee_uuid, x, y, angle, damage, ball_uuid) {
|
||||
let attacker = this.get_player(uuid);
|
||||
let attackee = this.get_player(attackee_uuid);
|
||||
|
||||
if (attacker && attackee) {
|
||||
attackee.receive_attack(x, y, angle, damage, ball_uuid, attacker);
|
||||
}
|
||||
}
|
||||
|
||||
send_blink(tx, ty) {
|
||||
let outer = this;
|
||||
this.ws.send(JSON.stringify({
|
||||
'event': "blink",
|
||||
'uuid': outer.uuid,
|
||||
'tx': tx,
|
||||
'ty': ty,
|
||||
}));
|
||||
}
|
||||
|
||||
receive_blink(uuid, tx, ty) {
|
||||
let player = this.get_player(uuid);
|
||||
if (player) {
|
||||
player.blink(tx, ty);
|
||||
}
|
||||
}
|
||||
send_message(text){
|
||||
|
||||
let outer = this;
|
||||
this.ws.send(JSON.stringify({
|
||||
'event':"message",
|
||||
'uuid':outer.uuid,
|
||||
'text':text,
|
||||
|
||||
|
||||
|
||||
|
||||
}));
|
||||
|
||||
}
|
||||
receive_message(uuid,text){
|
||||
let player = this.get_player(uuid);
|
||||
if(player){
|
||||
player.playground.chat_field.add_message(player.username,text);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,129 @@
|
||||
class AcGamePlayground {
|
||||
constructor(root){
|
||||
this.root=root;
|
||||
this.$playground = $(`<div class="ac-game-playground"></div>`);
|
||||
this.hide();
|
||||
|
||||
this.root.$ac_game.append(this.$playground);
|
||||
this.start();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
get_random_color(){
|
||||
let colors = ["blue","red","green","pink","grey"];
|
||||
return colors[Math.floor(Math.random()*5)];
|
||||
}
|
||||
|
||||
start(){
|
||||
let outer=this;
|
||||
let uuid = this.create_uuid();
|
||||
|
||||
$(window).on(`resize.${uuid}`,function(){
|
||||
outer.resize();
|
||||
});
|
||||
|
||||
|
||||
|
||||
if(this.root.AcWingOS){
|
||||
this.root.AcWingOS.api.window.on_close(function(){
|
||||
$(window).off(`resize.${uuid}`);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
create_uuid() {
|
||||
let res = "";
|
||||
for(let i = 0;i < 8 ; i++){
|
||||
let x = parseInt(Math.floor(Math.random()*10));
|
||||
res += x;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
resize(){
|
||||
this.width = this.$playground.width();
|
||||
this.height = this.$playground.height();
|
||||
this.unit= Math.min(this.width/16,this.height/9);
|
||||
this.width = this.unit * 16;
|
||||
this.height = this.unit*9;
|
||||
this.scale = this.height;
|
||||
if(this.game_map)this.game_map.resize();
|
||||
}
|
||||
|
||||
|
||||
update(){
|
||||
|
||||
}
|
||||
|
||||
show(mode){
|
||||
let outer = this;
|
||||
this.$playground.show();
|
||||
this.$playground.resize();
|
||||
this.width= this.$playground.width();
|
||||
this.height = this.$playground.height();
|
||||
this.game_map = new GameMap(this);
|
||||
this.resize();
|
||||
this.players = [];
|
||||
this.players.push(new Player(this,this.width/2/this.scale,0.5,0.05,"white",0.15,"me",this.root.settings.username,this.root.settings.photo));
|
||||
this.mode = mode;
|
||||
this.state = "waiting";
|
||||
this.notice_board = new NoticeBoard(this);
|
||||
this.score_board = new ScoreBoard(this);
|
||||
this.player_count = 0;
|
||||
|
||||
if(mode === "single mode")
|
||||
for (let i = 0; i < 5; i ++ ) {
|
||||
this.players.push(new Player(this, this.width / 2/this.scale, 0.5, 0.05, this.get_random_color(), 0.15, "robot"));
|
||||
} else if(mode === "multi mode"){
|
||||
this.chat_field = new ChatField(this);
|
||||
|
||||
this.mps = new MultiPlayerSocket(this);
|
||||
this.mps.uuid = this.players[0].uuid;
|
||||
this.mps.ws.onopen = function(){
|
||||
outer.mps.send_create_player(outer.root.settings.username,outer.root.settings.photo);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
hide(){
|
||||
|
||||
while(this.players && this.players.length > 0){
|
||||
this.players[0].destroy();
|
||||
|
||||
}
|
||||
|
||||
if(this.game_map){
|
||||
this.game_map.destroy();
|
||||
this.game_map = null;
|
||||
|
||||
}
|
||||
|
||||
if(this.notice_board){
|
||||
this.notice_board.destroy();
|
||||
this.notice_board = null;
|
||||
|
||||
|
||||
}
|
||||
if(this.score_board){
|
||||
this.score_board.destroy();
|
||||
this.score_board = null;
|
||||
|
||||
}
|
||||
|
||||
this.$playground.empty();
|
||||
|
||||
|
||||
|
||||
this.$playground.hide();
|
||||
}
|
||||
}
|
@ -0,0 +1,388 @@
|
||||
class Settings{
|
||||
constructor(root){
|
||||
this.root = root;
|
||||
this.platform = "WEB";
|
||||
if(this.root.AcWingOS) this.platform = "ACAPP";
|
||||
this.username = "";
|
||||
this.photo = "https://cdn.acwing.com/media/user/profile/photo/355448_sm_2015d90652.jpg";
|
||||
this.$settings = $(`
|
||||
<div class="ac-game-settings">
|
||||
<div class="ac-game-settings-login">
|
||||
<div class="ac-game-settings-title">
|
||||
登录
|
||||
</div>
|
||||
<div class="ac-game-settings-username">
|
||||
<div class="ac-game-settings-item">
|
||||
<input type="text" placeholder="用户名">
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-game-settings-password">
|
||||
<div class="ac-game-settings-item">
|
||||
<input type="password" placeholder="密码">
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-game-settings-submit">
|
||||
<div class="ac-game-settings-item">
|
||||
<button>登录</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-game-settings-error-message">
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<div class="ac-game-settings-option">
|
||||
注册
|
||||
</div>
|
||||
<br>
|
||||
<div class="ac-game-settings-acwing">
|
||||
<img width="30" src="https://app165.acapp.acwing.com.cn/static/image/settings/acwing_logo.png">
|
||||
<br>
|
||||
<br>
|
||||
<div>
|
||||
AcWing一键登录
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-game-settings-register">
|
||||
<div class="ac-game-settings-title">
|
||||
注册
|
||||
</div>
|
||||
<div class="ac-game-settings-username">
|
||||
<div class="ac-game-settings-item">
|
||||
<input type="text" placeholder="用户名">
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-game-settings-password ac-game-settings-password-first">
|
||||
<div class="ac-game-settings-item">
|
||||
<input type="password" placeholder="密码">
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-game-settings-password ac-game-settings-password-second">
|
||||
<div class="ac-game-settings-item">
|
||||
<input type="password" placeholder="确认密码">
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-game-settings-submit">
|
||||
<div class="ac-game-settings-item">
|
||||
<button>注册</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ac-game-settings-error-message">
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<div class="ac-game-settings-option">
|
||||
登录
|
||||
</div>
|
||||
<div class="ac-game-settings-acwing">
|
||||
<img width="30" src="https://app165.acapp.acwing.com.cn/static/image/settings/acwing_logo.png">
|
||||
<br>
|
||||
<br>
|
||||
<div>
|
||||
AcWing一键登录
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
`);
|
||||
this.$login = this.$settings.find(".ac-game-settings-login");
|
||||
this.$login_username = this.$login.find(".ac-game-settings-username input");
|
||||
this.$login_password = this.$login.find(".ac-game-settings-password input");
|
||||
this.$login_submit = this.$login.find(".ac-game-settings-submit button");
|
||||
this.$login_error_message = this.$login.find(".ac-game-settings-error-message");
|
||||
this.$login_register = this.$login.find(".ac-game-settings-option");
|
||||
|
||||
this.$login.hide();
|
||||
|
||||
this.$register = this.$settings.find(".ac-game-settings-register");
|
||||
this.$register_username = this.$register.find(".ac-game-settings-username input");
|
||||
this.$register_password = this.$register.find(".ac-game-settings-password-first input");
|
||||
this.$register_password_confirm = this.$register.find(".ac-game-settings-password-second input");
|
||||
this.$register_submit = this.$register.find(".ac-game-settings-submit button");
|
||||
this.$register_error_message = this.$register.find(".ac-game-settings-error-message");
|
||||
this.$register_login = this.$register.find(".ac-game-settings-option");
|
||||
|
||||
|
||||
this.$register.hide();
|
||||
this.$acwing_login = this.$settings.find(".ac-game-settings-acwing img");
|
||||
|
||||
this.root.$ac_game.append(this.$settings);
|
||||
this.start();
|
||||
}
|
||||
start(){
|
||||
if (this.platform === "ACAPP"){
|
||||
this.getinfo_acapp();
|
||||
|
||||
}else{
|
||||
if(this.root.access){
|
||||
this.getinfo_web();
|
||||
this.refresh_jwt_token();
|
||||
|
||||
} else {
|
||||
|
||||
this.login();
|
||||
|
||||
}
|
||||
|
||||
this.add_listening_events();
|
||||
}
|
||||
}
|
||||
|
||||
refresh_jwt_token(){
|
||||
setInterval(() => {
|
||||
$.ajax({
|
||||
url:"https://app6641.acapp.acwing.com.cn/settings/token/refresh/",
|
||||
type:"post",
|
||||
data:{
|
||||
refresh:this.root.refresh,
|
||||
},
|
||||
success: resp => {
|
||||
this.root.access = resp.access;
|
||||
|
||||
}
|
||||
});
|
||||
},4.5*60*1000);
|
||||
|
||||
setTimeout(() => {
|
||||
$.ajax({
|
||||
url:"https://app6641.acapp.acwing.com.cn/settings/ranklist/",
|
||||
type:"GET",
|
||||
headers:{
|
||||
'Authorization': "Bearer "+ this.root.access,
|
||||
|
||||
},
|
||||
success: resp => {
|
||||
console.log(resp);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
},5000);
|
||||
|
||||
|
||||
}
|
||||
|
||||
add_listening_events(){
|
||||
let outer = this;
|
||||
this.add_listening_events_login();
|
||||
this.add_listening_events_register();
|
||||
this.$acwing_login.click(function(){
|
||||
outer.acwing_login();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
add_listening_events_login(){
|
||||
let outer =this;
|
||||
this.$login_register.click(function(){
|
||||
outer.register();
|
||||
});
|
||||
this.$login_submit.click(function(){
|
||||
outer.login_on_remote();
|
||||
});
|
||||
}
|
||||
|
||||
add_listening_events_register(){
|
||||
let outer = this;
|
||||
this.$register_login.click(function(){
|
||||
outer.login();
|
||||
});
|
||||
this.$register_submit.click(function() {
|
||||
outer.register_on_remote();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
acwing_login() {
|
||||
$.ajax({
|
||||
url: "https://app6641.acapp.acwing.com.cn/settings/acwing/web/apply_code/",
|
||||
type: "GET",
|
||||
success: function(resp) {
|
||||
if (resp.result === "success") {
|
||||
window.location.replace(resp.apply_code_url);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
login_on_remote(username , password) {
|
||||
let outer = this;
|
||||
username = username || this.$login_username.val();
|
||||
password = password || this.$login_password.val();
|
||||
this.$login_error_message.empty();
|
||||
|
||||
$.ajax({
|
||||
url: "https://app6641.acapp.acwing.com.cn/settings/token/",
|
||||
type: "post",
|
||||
data: {
|
||||
username: username,
|
||||
password: password,
|
||||
|
||||
},
|
||||
success: resp =>{
|
||||
|
||||
|
||||
this.root.access = resp.access;
|
||||
this.root.refresh = resp.refresh;
|
||||
this.refresh_jwt_token();
|
||||
|
||||
this.getinfo_web();
|
||||
|
||||
},
|
||||
error:() => {
|
||||
this.$login_error_message.html("用户名密码错误");
|
||||
|
||||
},
|
||||
});
|
||||
}
|
||||
register_on_remote(){
|
||||
let outer = this;
|
||||
let username = this.$register_username.val();
|
||||
let password = this.$register_password.val();
|
||||
let password_confirm = this.$register_password_confirm.val();
|
||||
this.$register_error_message.empty();
|
||||
|
||||
$.ajax({
|
||||
url: "https://app6641.acapp.acwing.com.cn/settings/register/",
|
||||
type: "POST",
|
||||
data: {
|
||||
username: username,
|
||||
password: password,
|
||||
password_confirm:password_confirm,
|
||||
|
||||
},
|
||||
success: resp =>{
|
||||
if(resp.result === "success"){
|
||||
this.login_on_remote(username,password);
|
||||
|
||||
} else {
|
||||
this.$register_error_message.html(resp.result);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
logout_on_remote(){
|
||||
if(this.platform === "ACAPP") {
|
||||
this.root.AcWingOS.api.window.close();
|
||||
|
||||
} else {
|
||||
|
||||
this.root.access = "";
|
||||
this.root.refresh = "";
|
||||
location.href = "/";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
login(){//打开登陆界面
|
||||
this.$register.hide();
|
||||
this.$login.show();
|
||||
}
|
||||
|
||||
|
||||
register(){// 打开注册界面
|
||||
this.$login.hide();
|
||||
this.$register.show();
|
||||
|
||||
}
|
||||
|
||||
acapp_login(appid, redirect_uri, scope, state) {
|
||||
let outer = this;
|
||||
|
||||
this.root.AcWingOS.api.oauth2.authorize(appid, redirect_uri, scope, state, function(resp) {
|
||||
if (resp.result === "success") {
|
||||
outer.username = resp.username;
|
||||
outer.photo = resp.photo;
|
||||
outer.hide();
|
||||
outer.root.menu.show();
|
||||
outer.root.access = resp.access;
|
||||
outer.root.refresh = resp.refresh;
|
||||
outer.refresh_jwt_token();
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
getinfo_acapp(){
|
||||
let outer = this;
|
||||
$.ajax({
|
||||
url: "https://app6641.acapp.acwing.com.cn/settings/acwing/acapp/receive_code/",
|
||||
type:"GET",
|
||||
success: function(resp){
|
||||
if(resp.result === "success"){
|
||||
outer.acapp_login(resp.appid,resp.redirect_uri,resp.scope,resp.state);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
getinfo_acapp() {
|
||||
let outer = this;
|
||||
|
||||
$.ajax({
|
||||
url: "https://app6641.acapp.acwing.com.cn/settings/acwing/acapp/apply_code/",
|
||||
type: "GET",
|
||||
success: function(resp) {
|
||||
if (resp.result === "success") {
|
||||
outer.acapp_login(resp.appid, resp.redirect_uri, resp.scope, resp.state);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
getinfo_web(){
|
||||
let outer = this;
|
||||
$.ajax({
|
||||
url:"https://app6641.acapp.acwing.com.cn/settings/getinfo/",
|
||||
type:"get",
|
||||
data:{
|
||||
platform:outer.platform,
|
||||
|
||||
},
|
||||
headers:{
|
||||
'authorization':"Bearer "+this.root.access,
|
||||
|
||||
},
|
||||
success:function(resp){
|
||||
console.log(resp);
|
||||
if(resp.result === "success"){
|
||||
outer.username = resp.username;
|
||||
outer.photo = resp.photo;
|
||||
outer.hide();
|
||||
outer.root.menu.show();
|
||||
} else {
|
||||
outer.login();
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
hide(){
|
||||
this.$settings.hide();
|
||||
}
|
||||
|
||||
show(){
|
||||
this.$settings.show();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
export class AcGame {
|
||||
constructor(id, AcWingOS, access, refresh) {
|
||||
this.id = id;
|
||||
this.$ac_game = $('#' + id);
|
||||
this.AcWingOS = AcWingOS;
|
||||
this.access = access;
|
||||
this.refresh = refresh;
|
||||
|
||||
this.settings = new Settings(this);
|
||||
this.menu = new AcGameMenu(this);
|
||||
this.playground = new AcGamePlayground(this);
|
||||
|
||||
this.start();
|
||||
}
|
||||
|
||||
start() {
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,158 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="icon" href="https://cdn.acwing.com/media/article/image/2021/12/17/1_be4c11ce5f-acapp.png">
|
||||
<title>头像选择</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
background-image: url("/static/image/menu/123.gif");
|
||||
}
|
||||
|
||||
.container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 48px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 40px 0;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
font-size: 48px;
|
||||
margin: 0 40px;
|
||||
cursor: pointer;
|
||||
color: aliceblue;
|
||||
}
|
||||
|
||||
.avatar-placeholder {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
border-radius: 50%;
|
||||
border: 4px solid white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28px;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.confirm-button {
|
||||
padding: 20px 40px;
|
||||
background-color: white;
|
||||
color: black;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 28px;
|
||||
margin-top: 40px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const avatars = [
|
||||
'/static/image/swgq.jpg',
|
||||
'/static/image/lxq.jpg',
|
||||
'/static/image/zyj.jpg'
|
||||
];
|
||||
let currentIndex = 0;
|
||||
|
||||
const avatarPlaceholder = document.querySelector('.avatar-placeholder');
|
||||
const leftArrow = document.querySelector('.arrow:first-child');
|
||||
const rightArrow = document.querySelector('.arrow:last-child');
|
||||
const confirmButton = document.querySelector('.confirm-button');
|
||||
const logoutButton = document.querySelector('.logout-button'); // 选择退出按钮
|
||||
|
||||
function updateAvatar() {
|
||||
avatarPlaceholder.style.backgroundImage = `url('${avatars[currentIndex]}')`;
|
||||
}
|
||||
|
||||
leftArrow.addEventListener('click', () => {
|
||||
currentIndex = (currentIndex === 0) ? avatars.length - 1 : currentIndex - 1;
|
||||
updateAvatar();
|
||||
});
|
||||
|
||||
rightArrow.addEventListener('click', () => {
|
||||
currentIndex = (currentIndex === avatars.length - 1) ? 0 : currentIndex + 1;
|
||||
updateAvatar();
|
||||
});
|
||||
|
||||
updateAvatar(); // 初始化显示第一个头像
|
||||
|
||||
// 用户信息对象
|
||||
user = {
|
||||
username: "{{ user.username|escapejs }}",
|
||||
photo: "{{ user.player.photo|escapejs }}",
|
||||
};
|
||||
|
||||
console.log("当前用户信息:", user);
|
||||
|
||||
// 绑定确认按钮的点击事件
|
||||
confirmButton.addEventListener('click', () => {
|
||||
user.photo = avatars[currentIndex];
|
||||
console.log("更新头像为:", user.photo);
|
||||
|
||||
fetch('/update-avatar/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': '{{ csrf_token }}'
|
||||
},
|
||||
body: JSON.stringify({ photo: user.photo })
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
alert("头像已更新!");
|
||||
|
||||
} else {
|
||||
alert("头像更新失败,请稍后重试。");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error("Error:", error);
|
||||
alert("头像更新失败,请检查网络连接。");
|
||||
});
|
||||
});
|
||||
|
||||
// 绑定退出按钮的点击事件
|
||||
logoutButton.addEventListener('click', () => {
|
||||
window.location.href = 'https://app6641.acapp.acwing.com.cn/'; // 重定向到注销页面
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<h1>头像选择</h1>
|
||||
<div class="avatar-container">
|
||||
<div class="arrow">◀</div>
|
||||
<div class="avatar-placeholder"></div>
|
||||
<div class="arrow">▶</div>
|
||||
</div>
|
||||
<button class="confirm-button">确认</button>
|
||||
<button class="logout-button">退出</button> <!-- 新增退出按钮 -->
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>用户资料</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>用户资料</h1>
|
||||
<p>用户名: {{ user.username }}</p>
|
||||
<p>邮箱: {{ user.email }}</p>
|
||||
<p>头像: <img src="{{ user.avatar.url }}" alt="用户头像" width="100"></p> <!-- 假设你的用户模型有头像字段 -->
|
||||
|
||||
<a href="{% url 'update_avatar' %}">更新头像</a>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -0,0 +1,19 @@
|
||||
{% load static %}
|
||||
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://cdn.acwing.com/static/jquery-ui-dist/jquery-ui.min.css">
|
||||
<script src="https://cdn.acwing.com/static/jquery/js/jquery-3.3.1.min.js"></script>
|
||||
<link rel="stylesheet" href="{% static 'css/game.css' %}">
|
||||
<link rel="icon" href="https://cdn.acwing.com/media/article/image/2021/12/17/1_be4c11ce5f-acapp.png">
|
||||
</head>
|
||||
|
||||
<body style="margin: 0">
|
||||
<div id="ac_game_12345678"></div>
|
||||
<script type = "module">
|
||||
import {AcGame} from "{% static 'js/dist/game.js' %}";
|
||||
$(document).ready(function(){
|
||||
let ac_game = new AcGame("ac_game_12345678",null,"{{ access }}","{{ refresh }}");
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
@ -0,0 +1,16 @@
|
||||
|
||||
from django.urls import path ,include
|
||||
from game.views.index import index
|
||||
from game.views.index import new_page,update_avatar
|
||||
from game.views.settings.ranklist import RankListView
|
||||
|
||||
urlpatterns = [
|
||||
path("",index,name="index"),
|
||||
path("menu/",include("game.urls.menu.index")),
|
||||
|
||||
path("playground/",include("game.urls.playground.index")),
|
||||
path("settings/",include("game.urls.settings.index")),
|
||||
path("photo/",new_page),
|
||||
path('update-avatar/', update_avatar, name='update_avatar'),
|
||||
|
||||
]
|
@ -0,0 +1,5 @@
|
||||
from django.urls import path
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
]
|
@ -0,0 +1,4 @@
|
||||
from django.urls import path
|
||||
|
||||
urlpatterns = [
|
||||
]
|
@ -0,0 +1,13 @@
|
||||
from django.urls import path
|
||||
from game.views.settings.acwing.web.apply_code import apply_code as web_apply_code
|
||||
from game.views.settings.acwing.web.receive_code import receive_code as web_receive_code
|
||||
from game.views.settings.acwing.acapp.apply_code import apply_code as acapp_apply_code
|
||||
from game.views.settings.acwing.acapp.receive_code import receive_code as acapp_receive_code
|
||||
|
||||
urlpatterns = [
|
||||
path("web/apply_code/",web_apply_code,name="settings_acwing_web_apply_code"),
|
||||
path("web/receive_code/",web_receive_code,name="settings_acwing_web_receive_code"),
|
||||
path("acapp/apply_code/",acapp_apply_code,name="settings_acwing_acapp_apply_code"),
|
||||
path("acapp/receive_code/",acapp_receive_code,name="settings_acwing_acapp_receive_code"),
|
||||
|
||||
]
|
@ -0,0 +1,23 @@
|
||||
from django.urls import path, include
|
||||
from game.views.settings.getinfo import InfoView
|
||||
|
||||
from game.views.settings.register import PlayerView
|
||||
|
||||
|
||||
from game.views.settings.ranklist import RankListView
|
||||
|
||||
from rest_framework_simplejwt.views import (
|
||||
TokenObtainPairView,
|
||||
TokenRefreshView,
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
path('token/', TokenObtainPairView.as_view(), name='settings_token'),
|
||||
path('token/refresh/', TokenRefreshView.as_view(), name='settings_token_refresh'),
|
||||
path("getinfo/", InfoView.as_view(), name="settings_getinfo"),
|
||||
path("register/", PlayerView.as_view(), name="settings_register"),
|
||||
path("acwing/", include("game.urls.settings.acwing.index")),
|
||||
path("ranklist/",RankListView.as_view(),name="settings_ranklsit"),
|
||||
|
||||
]
|
||||
|
@ -0,0 +1,41 @@
|
||||
from django.shortcuts import render
|
||||
from django.shortcuts import render
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
from django.shortcuts import render, redirect
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
|
||||
|
||||
def index(request):
|
||||
data = request.GET
|
||||
context = {
|
||||
'access':data.get('access',""),
|
||||
'refresh':data.get('refresh',""),
|
||||
}
|
||||
return render(request,"multiends/web.html",context)
|
||||
|
||||
|
||||
|
||||
def new_page(request):
|
||||
return render(request, 'menu/new.html', {'user': request.user})
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import JsonResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
import json
|
||||
|
||||
@login_required
|
||||
@csrf_exempt
|
||||
def update_avatar(request):
|
||||
if request.method == 'POST':
|
||||
data = json.loads(request.body)
|
||||
new_photo = data.get('photo')
|
||||
if new_photo:
|
||||
# 更新用户的头像
|
||||
player = request.user.player # 假设User模型和Player模型之间有OneToOne关系
|
||||
player.photo = new_photo
|
||||
player.save()
|
||||
return JsonResponse({'status': 'success'})
|
||||
else:
|
||||
return JsonResponse({'status': 'error', 'message': 'No photo URL provided'}, status=400)
|
||||
return JsonResponse({'status': 'error', 'message': 'Invalid request method'}, status=405)
|
@ -0,0 +1,29 @@
|
||||
from django.http import JsonResponse
|
||||
from urllib.parse import quote
|
||||
from random import randint
|
||||
from django.core.cache import cache
|
||||
|
||||
|
||||
def get_state():
|
||||
res = ""
|
||||
for i in range(8):
|
||||
res += str(randint(0, 9))
|
||||
return res
|
||||
|
||||
|
||||
def apply_code(request):
|
||||
appid = "6641"
|
||||
redirect_uri = quote("https://app6641.acapp.acwing.com.cn/settings/acwing/acapp/receive_code/")
|
||||
scope = "userinfo"
|
||||
state = get_state()
|
||||
|
||||
cache.set(state, True, 7200) # 有效期2小时
|
||||
|
||||
return JsonResponse({
|
||||
'result': "success",
|
||||
'appid':appid,
|
||||
'redirect_uri': redirect_uri,
|
||||
'scope':scope,
|
||||
'state':state
|
||||
})
|
||||
|
@ -0,0 +1,78 @@
|
||||
|
||||
from django.http import JsonResponse
|
||||
from django.core.cache import cache
|
||||
import requests
|
||||
from django.contrib.auth.models import User
|
||||
from game.models.player.player import Player
|
||||
from random import randint
|
||||
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
def receive_code(request):
|
||||
data = request.GET
|
||||
|
||||
if "errcode" in data:
|
||||
return JsonResponse({
|
||||
'result': "apply failed",
|
||||
'errcode': data['errcode'],
|
||||
'errmsg': data['errmsg'],
|
||||
})
|
||||
|
||||
code = data.get('code')
|
||||
state = data.get('state')
|
||||
|
||||
if not cache.has_key(state):
|
||||
return JsonResponse({
|
||||
'result': "state not exist"
|
||||
})
|
||||
cache.delete(state)
|
||||
|
||||
apply_access_token_url = "https://www.acwing.com/third_party/api/oauth2/access_token/"
|
||||
params = {
|
||||
'appid': "6641",
|
||||
'secret': "aff89abe48f44aac93feab52df88b965",
|
||||
'code': code
|
||||
}
|
||||
|
||||
access_token_res = requests.get(apply_access_token_url, params=params).json()
|
||||
|
||||
access_token = access_token_res['access_token']
|
||||
openid = access_token_res['openid']
|
||||
|
||||
players = Player.objects.filter(openid=openid)
|
||||
if players.exists(): # 如果该用户已存在,则无需重新获取信息,直接登录即可
|
||||
player = players[0]
|
||||
refresh = RefreshToken.for_user(player.user)
|
||||
return JsonResponse({
|
||||
'result': "success",
|
||||
'username': player.user.username,
|
||||
'photo': player.photo,
|
||||
'access':str(refresh.access_token),
|
||||
'refresh':str(refresh),
|
||||
|
||||
})
|
||||
|
||||
|
||||
get_userinfo_url = "https://www.acwing.com/third_party/api/meta/identity/getinfo/"
|
||||
params = {
|
||||
"access_token": access_token,
|
||||
"openid": openid
|
||||
}
|
||||
userinfo_res = requests.get(get_userinfo_url, params=params).json()
|
||||
username = userinfo_res['username']
|
||||
photo = userinfo_res['photo']
|
||||
|
||||
while User.objects.filter(username=username).exists(): # 找到一个新用户名
|
||||
username += str(randint(0, 9))
|
||||
|
||||
user = User.objects.create(username=username)
|
||||
player = Player.objects.create(user=user, photo=photo, openid=openid)
|
||||
refresh = RefreshToken.for_user(user)
|
||||
return JsonResponse({
|
||||
'result': "success",
|
||||
'username': player.user.username,
|
||||
'photo': player.photo,
|
||||
'access':str(refresh.access_token),
|
||||
'refresh':str(refresh),
|
||||
})
|
||||
|
||||
|
@ -0,0 +1,27 @@
|
||||
from django.http import JsonResponse
|
||||
from urllib.parse import quote
|
||||
from random import randint
|
||||
from django.core.cache import cache
|
||||
|
||||
|
||||
def get_state():
|
||||
res = ""
|
||||
for i in range(8):
|
||||
res += str(randint(0, 9))
|
||||
return res
|
||||
|
||||
|
||||
def apply_code(request):
|
||||
appid = "6641"
|
||||
redirect_uri = quote("https://app6641.acapp.acwing.com.cn/settings/acwing/web/receive_code/")
|
||||
scope = "userinfo"
|
||||
state = get_state()
|
||||
|
||||
cache.set(state, True, 7200) # 有效期2小时
|
||||
|
||||
apply_code_url = "https://www.acwing.com/third_party/api/oauth2/web/authorize/"
|
||||
return JsonResponse({
|
||||
'result': "success",
|
||||
'apply_code_url': apply_code_url + "?appid=%s&redirect_uri=%s&scope=%s&state=%s" % (appid, redirect_uri, scope, state)
|
||||
})
|
||||
|
@ -0,0 +1,48 @@
|
||||
from django.shortcuts import redirect,reverse
|
||||
from django.core.cache import cache
|
||||
import requests
|
||||
from django.contrib.auth.models import User
|
||||
from game.models.player.player import Player
|
||||
from random import randint
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
def receive_code(request):
|
||||
data = request.GET
|
||||
code = data.get('code')
|
||||
state = data.get('state')
|
||||
if not cache.has_key(state):
|
||||
return redirect("index")
|
||||
cache.delete(state)
|
||||
apply_access_token_url = "https://www.acwing.com/third_party/api/oauth2/access_token/"
|
||||
params = {
|
||||
'appid': "6641",
|
||||
'secret': "aff89abe48f44aac93feab52df88b965",
|
||||
'code' : code
|
||||
|
||||
}
|
||||
access_token_res = requests.get(apply_access_token_url, params=params).json()
|
||||
access_token = access_token_res['access_token']
|
||||
openid = access_token_res['openid']
|
||||
|
||||
players = Player.objects.filter(openid = openid)
|
||||
if players.exists():
|
||||
refresh = RefreshToken.for_user(players[0].user)
|
||||
|
||||
return redirect(reverse("index") + "?access=%s&refresh=%s" % (str(refresh.access_token),str(refresh)))
|
||||
|
||||
get_userinfo_url = "https://www.acwing.com/third_party/api/meta/identity/getinfo/"
|
||||
params = {
|
||||
'access_token': access_token,
|
||||
'openid': openid
|
||||
}
|
||||
userinfo_res = requests.get(get_userinfo_url,params=params).json()
|
||||
username = userinfo_res['username']
|
||||
photo = userinfo_res['photo']
|
||||
while User.objects.filter(username = username).exists():
|
||||
username += str(randint(0,9))
|
||||
user = User.objects.create(username=username)
|
||||
player = Player.objects.create(user=user,photo=photo,openid=openid)
|
||||
|
||||
refresh = RefreshToken.for_user(user)
|
||||
return redirect(reverse("index") + "?access=%s&refresh=%s" % (str(refresh.access_token), str(refresh)))
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from rest_framework.response import Response
|
||||
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from game.models.player.player import Player
|
||||
|
||||
|
||||
class InfoView(APIView):
|
||||
permission_classes = ([IsAuthenticated])
|
||||
|
||||
def get(self,request):
|
||||
user = request.user
|
||||
player = Player.objects.get(user=user)
|
||||
return Response({
|
||||
'result':"success",
|
||||
'username':user.username,
|
||||
'photo':player.photo,
|
||||
|
||||
|
||||
})
|
@ -0,0 +1,23 @@
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from game.models.player.player import Player
|
||||
|
||||
class RankListView(APIView):
|
||||
permission_classes = ([IsAuthenticated])
|
||||
|
||||
|
||||
def get(self,request):
|
||||
players = Player.objects.all().order_by('-score')[:8]
|
||||
resp = []
|
||||
for player in players:
|
||||
resp.append({
|
||||
'username': player.user.username,
|
||||
'photo':player.photo,
|
||||
'score':player.score,
|
||||
|
||||
|
||||
})
|
||||
return Response(resp)
|
@ -0,0 +1,35 @@
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from django.contrib.auth.models import User
|
||||
from game.models.player.player import Player
|
||||
|
||||
|
||||
class PlayerView(APIView):
|
||||
def post(self,request):
|
||||
|
||||
|
||||
data = request.POST
|
||||
username = data.get("username", "").strip()
|
||||
password = data.get("password", "").strip()
|
||||
password_confirm = data.get("password_confirm", "").strip()
|
||||
print(username)
|
||||
if not username or not password:
|
||||
return Response({
|
||||
'result':request.GET.get("username")
|
||||
})
|
||||
if password != password_confirm:
|
||||
return Response({
|
||||
'result': "两个密码不一致",
|
||||
})
|
||||
if User.objects.filter(username=username).exists():
|
||||
return Response({
|
||||
'result': "用户名已存在"
|
||||
})
|
||||
user = User(username=username)
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
Player.objects.create(user=user, photo="https://cdn.acwing.com/media/user/profile/photo/355448_sm_2015d90652.jpg")
|
||||
return Response({
|
||||
'result': "success",
|
||||
})
|
||||
|
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'acapp.settings')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Autogenerated by Thrift Compiler (0.16.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
# options string: py
|
||||
#
|
||||
|
||||
import sys
|
||||
import pprint
|
||||
if sys.version_info[0] > 2:
|
||||
from urllib.parse import urlparse
|
||||
else:
|
||||
from urlparse import urlparse
|
||||
from thrift.transport import TTransport, TSocket, TSSLSocket, THttpClient
|
||||
from thrift.protocol.TBinaryProtocol import TBinaryProtocol
|
||||
|
||||
from match_service import Match
|
||||
from match_service.ttypes import *
|
||||
|
||||
if len(sys.argv) <= 1 or sys.argv[1] == '--help':
|
||||
print('')
|
||||
print('Usage: ' + sys.argv[0] + ' [-h host[:port]] [-u url] [-f[ramed]] [-s[sl]] [-novalidate] [-ca_certs certs] [-keyfile keyfile] [-certfile certfile] function [arg1 [arg2...]]')
|
||||
print('')
|
||||
print('Functions:')
|
||||
print(' i32 add_player(i32 score, string uuid, string username, string photo, string channel_name)')
|
||||
print('')
|
||||
sys.exit(0)
|
||||
|
||||
pp = pprint.PrettyPrinter(indent=2)
|
||||
host = 'localhost'
|
||||
port = 9090
|
||||
uri = ''
|
||||
framed = False
|
||||
ssl = False
|
||||
validate = True
|
||||
ca_certs = None
|
||||
keyfile = None
|
||||
certfile = None
|
||||
http = False
|
||||
argi = 1
|
||||
|
||||
if sys.argv[argi] == '-h':
|
||||
parts = sys.argv[argi + 1].split(':')
|
||||
host = parts[0]
|
||||
if len(parts) > 1:
|
||||
port = int(parts[1])
|
||||
argi += 2
|
||||
|
||||
if sys.argv[argi] == '-u':
|
||||
url = urlparse(sys.argv[argi + 1])
|
||||
parts = url[1].split(':')
|
||||
host = parts[0]
|
||||
if len(parts) > 1:
|
||||
port = int(parts[1])
|
||||
else:
|
||||
port = 80
|
||||
uri = url[2]
|
||||
if url[4]:
|
||||
uri += '?%s' % url[4]
|
||||
http = True
|
||||
argi += 2
|
||||
|
||||
if sys.argv[argi] == '-f' or sys.argv[argi] == '-framed':
|
||||
framed = True
|
||||
argi += 1
|
||||
|
||||
if sys.argv[argi] == '-s' or sys.argv[argi] == '-ssl':
|
||||
ssl = True
|
||||
argi += 1
|
||||
|
||||
if sys.argv[argi] == '-novalidate':
|
||||
validate = False
|
||||
argi += 1
|
||||
|
||||
if sys.argv[argi] == '-ca_certs':
|
||||
ca_certs = sys.argv[argi+1]
|
||||
argi += 2
|
||||
|
||||
if sys.argv[argi] == '-keyfile':
|
||||
keyfile = sys.argv[argi+1]
|
||||
argi += 2
|
||||
|
||||
if sys.argv[argi] == '-certfile':
|
||||
certfile = sys.argv[argi+1]
|
||||
argi += 2
|
||||
|
||||
cmd = sys.argv[argi]
|
||||
args = sys.argv[argi + 1:]
|
||||
|
||||
if http:
|
||||
transport = THttpClient.THttpClient(host, port, uri)
|
||||
else:
|
||||
if ssl:
|
||||
socket = TSSLSocket.TSSLSocket(host, port, validate=validate, ca_certs=ca_certs, keyfile=keyfile, certfile=certfile)
|
||||
else:
|
||||
socket = TSocket.TSocket(host, port)
|
||||
if framed:
|
||||
transport = TTransport.TFramedTransport(socket)
|
||||
else:
|
||||
transport = TTransport.TBufferedTransport(socket)
|
||||
protocol = TBinaryProtocol(transport)
|
||||
client = Match.Client(protocol)
|
||||
transport.open()
|
||||
|
||||
if cmd == 'add_player':
|
||||
if len(args) != 5:
|
||||
print('add_player requires 5 args')
|
||||
sys.exit(1)
|
||||
pp.pprint(client.add_player(eval(args[0]), args[1], args[2], args[3], args[4],))
|
||||
|
||||
else:
|
||||
print('Unrecognized method %s' % cmd)
|
||||
sys.exit(1)
|
||||
|
||||
transport.close()
|
@ -0,0 +1,306 @@
|
||||
#
|
||||
# Autogenerated by Thrift Compiler (0.16.0)
|
||||
#
|
||||
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||
#
|
||||
# options string: py
|
||||
#
|
||||
|
||||
from thrift.Thrift import TType, TMessageType, TFrozenDict, TException, TApplicationException
|
||||
from thrift.protocol.TProtocol import TProtocolException
|
||||
from thrift.TRecursive import fix_spec
|
||||
|
||||
import sys
|
||||
import logging
|
||||
from .ttypes import *
|
||||
from thrift.Thrift import TProcessor
|
||||
from thrift.transport import TTransport
|
||||
all_structs = []
|
||||
|
||||
|
||||
class Iface(object):
|
||||
def add_player(self, score, uuid, username, photo, channel_name):
|
||||
"""
|
||||
Parameters:
|
||||
- score
|
||||
- uuid
|
||||
- username
|
||||
- photo
|
||||
- channel_name
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Client(Iface):
|
||||
def __init__(self, iprot, oprot=None):
|
||||
self._iprot = self._oprot = iprot
|
||||
if oprot is not None:
|
||||
self._oprot = oprot
|
||||
self._seqid = 0
|
||||
|
||||
def add_player(self, score, uuid, username, photo, channel_name):
|
||||
"""
|
||||
Parameters:
|
||||
- score
|
||||
- uuid
|
||||
- username
|
||||
- photo
|
||||
- channel_name
|
||||
|
||||
"""
|
||||
self.send_add_player(score, uuid, username, photo, channel_name)
|
||||
return self.recv_add_player()
|
||||
|
||||
def send_add_player(self, score, uuid, username, photo, channel_name):
|
||||
self._oprot.writeMessageBegin('add_player', TMessageType.CALL, self._seqid)
|
||||
args = add_player_args()
|
||||
args.score = score
|
||||
args.uuid = uuid
|
||||
args.username = username
|
||||
args.photo = photo
|
||||
args.channel_name = channel_name
|
||||
args.write(self._oprot)
|
||||
self._oprot.writeMessageEnd()
|
||||
self._oprot.trans.flush()
|
||||
|
||||
def recv_add_player(self):
|
||||
iprot = self._iprot
|
||||
(fname, mtype, rseqid) = iprot.readMessageBegin()
|
||||
if mtype == TMessageType.EXCEPTION:
|
||||
x = TApplicationException()
|
||||
x.read(iprot)
|
||||
iprot.readMessageEnd()
|
||||
raise x
|
||||
result = add_player_result()
|
||||
result.read(iprot)
|
||||
iprot.readMessageEnd()
|
||||
if result.success is not None:
|
||||
return result.success
|
||||
raise TApplicationException(TApplicationException.MISSING_RESULT, "add_player failed: unknown result")
|
||||
|
||||
|
||||
class Processor(Iface, TProcessor):
|
||||
def __init__(self, handler):
|
||||
self._handler = handler
|
||||
self._processMap = {}
|
||||
self._processMap["add_player"] = Processor.process_add_player
|
||||
self._on_message_begin = None
|
||||
|
||||
def on_message_begin(self, func):
|
||||
self._on_message_begin = func
|
||||
|
||||
def process(self, iprot, oprot):
|
||||
(name, type, seqid) = iprot.readMessageBegin()
|
||||
if self._on_message_begin:
|
||||
self._on_message_begin(name, type, seqid)
|
||||
if name not in self._processMap:
|
||||
iprot.skip(TType.STRUCT)
|
||||
iprot.readMessageEnd()
|
||||
x = TApplicationException(TApplicationException.UNKNOWN_METHOD, 'Unknown function %s' % (name))
|
||||
oprot.writeMessageBegin(name, TMessageType.EXCEPTION, seqid)
|
||||
x.write(oprot)
|
||||
oprot.writeMessageEnd()
|
||||
oprot.trans.flush()
|
||||
return
|
||||
else:
|
||||
self._processMap[name](self, seqid, iprot, oprot)
|
||||
return True
|
||||
|
||||
def process_add_player(self, seqid, iprot, oprot):
|
||||
args = add_player_args()
|
||||
args.read(iprot)
|
||||
iprot.readMessageEnd()
|
||||
result = add_player_result()
|
||||
try:
|
||||
result.success = self._handler.add_player(args.score, args.uuid, args.username, args.photo, args.channel_name)
|
||||
msg_type = TMessageType.REPLY
|
||||
except TTransport.TTransportException:
|
||||
raise
|
||||
except TApplicationException as ex:
|
||||
logging.exception('TApplication exception in handler')
|
||||
msg_type = TMessageType.EXCEPTION
|
||||
result = ex
|
||||
except Exception:
|
||||
logging.exception('Unexpected exception in handler')
|
||||
msg_type = TMessageType.EXCEPTION
|
||||
result = TApplicationException(TApplicationException.INTERNAL_ERROR, 'Internal error')
|
||||
oprot.writeMessageBegin("add_player", msg_type, seqid)
|
||||
result.write(oprot)
|
||||
oprot.writeMessageEnd()
|
||||
oprot.trans.flush()
|
||||
|
||||
# HELPER FUNCTIONS AND STRUCTURES
|
||||
|
||||
|
||||
class add_player_args(object):
|
||||
"""
|
||||
Attributes:
|
||||
- score
|
||||
- uuid
|
||||
- username
|
||||
- photo
|
||||
- channel_name
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, score=None, uuid=None, username=None, photo=None, channel_name=None,):
|
||||
self.score = score
|
||||
self.uuid = uuid
|
||||
self.username = username
|
||||
self.photo = photo
|
||||
self.channel_name = channel_name
|
||||
|
||||
def read(self, iprot):
|
||||
if iprot._fast_decode is not None and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None:
|
||||
iprot._fast_decode(self, iprot, [self.__class__, self.thrift_spec])
|
||||
return
|
||||
iprot.readStructBegin()
|
||||
while True:
|
||||
(fname, ftype, fid) = iprot.readFieldBegin()
|
||||
if ftype == TType.STOP:
|
||||
break
|
||||
if fid == 1:
|
||||
if ftype == TType.I32:
|
||||
self.score = iprot.readI32()
|
||||
else:
|
||||
iprot.skip(ftype)
|
||||
elif fid == 2:
|
||||
if ftype == TType.STRING:
|
||||
self.uuid = iprot.readString().decode('utf-8', errors='replace') if sys.version_info[0] == 2 else iprot.readString()
|
||||
else:
|
||||
iprot.skip(ftype)
|
||||
elif fid == 3:
|
||||
if ftype == TType.STRING:
|
||||
self.username = iprot.readString().decode('utf-8', errors='replace') if sys.version_info[0] == 2 else iprot.readString()
|
||||
else:
|
||||
iprot.skip(ftype)
|
||||
elif fid == 4:
|
||||
if ftype == TType.STRING:
|
||||
self.photo = iprot.readString().decode('utf-8', errors='replace') if sys.version_info[0] == 2 else iprot.readString()
|
||||
else:
|
||||
iprot.skip(ftype)
|
||||
elif fid == 5:
|
||||
if ftype == TType.STRING:
|
||||
self.channel_name = iprot.readString().decode('utf-8', errors='replace') if sys.version_info[0] == 2 else iprot.readString()
|
||||
else:
|
||||
iprot.skip(ftype)
|
||||
else:
|
||||
iprot.skip(ftype)
|
||||
iprot.readFieldEnd()
|
||||
iprot.readStructEnd()
|
||||
|
||||
def write(self, oprot):
|
||||
if oprot._fast_encode is not None and self.thrift_spec is not None:
|
||||
oprot.trans.write(oprot._fast_encode(self, [self.__class__, self.thrift_spec]))
|
||||
return
|
||||
oprot.writeStructBegin('add_player_args')
|
||||
if self.score is not None:
|
||||
oprot.writeFieldBegin('score', TType.I32, 1)
|
||||
oprot.writeI32(self.score)
|
||||
oprot.writeFieldEnd()
|
||||
if self.uuid is not None:
|
||||
oprot.writeFieldBegin('uuid', TType.STRING, 2)
|
||||
oprot.writeString(self.uuid.encode('utf-8') if sys.version_info[0] == 2 else self.uuid)
|
||||
oprot.writeFieldEnd()
|
||||
if self.username is not None:
|
||||
oprot.writeFieldBegin('username', TType.STRING, 3)
|
||||
oprot.writeString(self.username.encode('utf-8') if sys.version_info[0] == 2 else self.username)
|
||||
oprot.writeFieldEnd()
|
||||
if self.photo is not None:
|
||||
oprot.writeFieldBegin('photo', TType.STRING, 4)
|
||||
oprot.writeString(self.photo.encode('utf-8') if sys.version_info[0] == 2 else self.photo)
|
||||
oprot.writeFieldEnd()
|
||||
if self.channel_name is not None:
|
||||
oprot.writeFieldBegin('channel_name', TType.STRING, 5)
|
||||
oprot.writeString(self.channel_name.encode('utf-8') if sys.version_info[0] == 2 else self.channel_name)
|
||||
oprot.writeFieldEnd()
|
||||
oprot.writeFieldStop()
|
||||
oprot.writeStructEnd()
|
||||
|
||||
def validate(self):
|
||||
return
|
||||
|
||||
def __repr__(self):
|
||||
L = ['%s=%r' % (key, value)
|
||||
for key, value in self.__dict__.items()]
|
||||
return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
|
||||
|
||||
def __ne__(self, other):
|
||||
return not (self == other)
|
||||
all_structs.append(add_player_args)
|
||||
add_player_args.thrift_spec = (
|
||||
None, # 0
|
||||
(1, TType.I32, 'score', None, None, ), # 1
|
||||
(2, TType.STRING, 'uuid', 'UTF8', None, ), # 2
|
||||
(3, TType.STRING, 'username', 'UTF8', None, ), # 3
|
||||
(4, TType.STRING, 'photo', 'UTF8', None, ), # 4
|
||||
(5, TType.STRING, 'channel_name', 'UTF8', None, ), # 5
|
||||
)
|
||||
|
||||
|
||||
class add_player_result(object):
|
||||
"""
|
||||
Attributes:
|
||||
- success
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, success=None,):
|
||||
self.success = success
|
||||
|
||||
def read(self, iprot):
|
||||
if iprot._fast_decode is not None and isinstance(iprot.trans, TTransport.CReadableTransport) and self.thrift_spec is not None:
|
||||
iprot._fast_decode(self, iprot, [self.__class__, self.thrift_spec])
|
||||
return
|
||||
iprot.readStructBegin()
|
||||
while True:
|
||||
(fname, ftype, fid) = iprot.readFieldBegin()
|
||||
if ftype == TType.STOP:
|
||||
break
|
||||
if fid == 0:
|
||||
if ftype == TType.I32:
|
||||
self.success = iprot.readI32()
|
||||
else:
|
||||
iprot.skip(ftype)
|
||||
else:
|
||||
iprot.skip(ftype)
|
||||
iprot.readFieldEnd()
|
||||
iprot.readStructEnd()
|
||||
|
||||
def write(self, oprot):
|
||||
if oprot._fast_encode is not None and self.thrift_spec is not None:
|
||||
oprot.trans.write(oprot._fast_encode(self, [self.__class__, self.thrift_spec]))
|
||||
return
|
||||
oprot.writeStructBegin('add_player_result')
|
||||
if self.success is not None:
|
||||
oprot.writeFieldBegin('success', TType.I32, 0)
|
||||
oprot.writeI32(self.success)
|
||||
oprot.writeFieldEnd()
|
||||
oprot.writeFieldStop()
|
||||
oprot.writeStructEnd()
|
||||
|
||||
def validate(self):
|
||||
return
|
||||
|
||||
def __repr__(self):
|
||||
L = ['%s=%r' % (key, value)
|
||||
for key, value in self.__dict__.items()]
|
||||
return '%s(%s)' % (self.__class__.__name__, ', '.join(L))
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, self.__class__) and self.__dict__ == other.__dict__
|
||||
|
||||
def __ne__(self, other):
|
||||
return not (self == other)
|
||||
all_structs.append(add_player_result)
|
||||
add_player_result.thrift_spec = (
|
||||
(0, TType.I32, 'success', None, None, ), # 0
|
||||
)
|
||||
fix_spec(all_structs)
|
||||
del all_structs
|