├── acapp ├── __init__.py ├── wsgi.py ├── asgi.py ├── urls.py └── settings.py ├── game ├── __init__.py ├── models │ ├── __init__.py │ └── player │ │ ├── __init__.py │ │ └── player.py ├── urls │ ├── __init__.py │ ├── menu │ │ ├── __init__.py │ │ └── index.py │ ├── playground │ │ ├── __init__.py │ │ └── index.py │ ├── settings │ │ ├── __init__.py │ │ ├── acwing │ │ │ ├── __init__.py │ │ │ └── index.py │ │ └── index.py │ └── index.py ├── views │ ├── __init__.py │ ├── menu │ │ └── __init__.py │ ├── playground │ │ └── __init__.py │ ├── settings │ │ ├── __init__.py │ │ ├── acwing │ │ │ ├── __init__.py │ │ │ ├── acapp │ │ │ │ ├── __init.py │ │ │ │ ├── apply_code.py │ │ │ │ └── receive_code.py │ │ │ └── web │ │ │ │ ├── __init.py │ │ │ │ ├── apply_code.py │ │ │ │ └── receive_code.py │ │ ├── logout.py │ │ ├── login.py │ │ ├── getinfo.py │ │ └── register.py │ └── index.py ├── consumers │ ├── __init__.py │ └── multiplayer │ │ ├── __init__.py │ │ └── index.py ├── migrations │ ├── __init__.py │ ├── 0003_player_score.py │ ├── 0002_player_openid.py │ └── 0001_initial.py ├── tests.py ├── static │ ├── image │ │ ├── menu │ │ │ ├── background.gif │ │ │ └── background-myimage.gif │ │ └── settings │ │ │ └── AcWing_Logo.png │ ├── js │ │ └── src │ │ │ ├── zbase.js │ │ │ ├── playground │ │ │ ├── notice_board │ │ │ │ └── zbase.js │ │ │ ├── game_map │ │ │ │ └── zbase.js │ │ │ ├── particle │ │ │ │ └── zbase.js │ │ │ ├── ac_game_object │ │ │ │ └── zbase.js │ │ │ ├── score_board │ │ │ │ └── zbase.js │ │ │ ├── chat_field │ │ │ │ └── zbase.js │ │ │ ├── skill │ │ │ │ └── fireball │ │ │ │ │ └── zbase.js │ │ │ ├── zbase.js │ │ │ └── socket │ │ │ │ └── multiplayer │ │ │ │ └── zbase.js │ │ │ └── menu │ │ │ └── zbase.js │ └── css │ │ └── game.css ├── admin.py ├── apps.py ├── routing.py └── templates │ └── multiends │ └── web.html ├── match_system ├── __init__.py ├── src │ ├── __init__.py │ ├── match_server │ │ ├── __init__.py │ │ └── match_service │ │ │ ├── __init__.py │ │ │ ├── constants.py │ │ │ ├── ttypes.py │ │ │ └── Match-remote │ └── main.py └── thrift │ └── match.thrift ├── .gitignore ├── static ├── image │ ├── menu │ │ ├── background.gif │ │ └── background-myimage.gif │ └── settings │ │ └── AcWing_Logo.png ├── admin │ ├── fonts │ │ ├── Roboto-Bold-webfont.woff │ │ ├── Roboto-Light-webfont.woff │ │ ├── Roboto-Regular-webfont.woff │ │ └── README.txt │ ├── img │ │ ├── tooltag-arrowright.svg │ │ ├── README.txt │ │ ├── icon-addlink.svg │ │ ├── tooltag-add.svg │ │ ├── icon-changelink.svg │ │ ├── icon-deletelink.svg │ │ ├── icon-yes.svg │ │ ├── search.svg │ │ ├── icon-alert.svg │ │ ├── icon-no.svg │ │ ├── inline-delete.svg │ │ ├── icon-viewlink.svg │ │ ├── icon-unknown.svg │ │ ├── icon-unknown-alt.svg │ │ ├── icon-clock.svg │ │ ├── gis │ │ │ ├── move_vertex_on.svg │ │ │ └── move_vertex_off.svg │ │ ├── icon-calendar.svg │ │ ├── calendar-icons.svg │ │ ├── LICENSE │ │ ├── sorting-icons.svg │ │ └── selector-icons.svg │ ├── js │ │ ├── jquery.init.js │ │ ├── prepopulate_init.js │ │ ├── popup_response.js │ │ ├── vendor │ │ │ ├── select2 │ │ │ │ ├── i18n │ │ │ │ │ ├── zh-TW.js │ │ │ │ │ ├── zh-CN.js │ │ │ │ │ ├── ja.js │ │ │ │ │ ├── az.js │ │ │ │ │ ├── ko.js │ │ │ │ │ ├── vi.js │ │ │ │ │ ├── tk.js │ │ │ │ │ ├── id.js │ │ │ │ │ ├── tr.js │ │ │ │ │ ├── ar.js │ │ │ │ │ ├── th.js │ │ │ │ │ ├── nb.js │ │ │ │ │ ├── km.js │ │ │ │ │ ├── sv.js │ │ │ │ │ ├── fi.js │ │ │ │ │ ├── is.js │ │ │ │ │ ├── et.js │ │ │ │ │ ├── hu.js │ │ │ │ │ ├── ms.js │ │ │ │ │ ├── ka.js │ │ │ │ │ ├── bg.js │ │ │ │ │ ├── da.js │ │ │ │ │ ├── hy.js │ │ │ │ │ ├── fa.js │ │ │ │ │ ├── en.js │ │ │ │ │ ├── hi.js │ │ │ │ │ ├── he.js │ │ │ │ │ ├── hr.js │ │ │ │ │ ├── de.js │ │ │ │ │ ├── af.js │ │ │ │ │ ├── eu.js │ │ │ │ │ ├── mk.js │ │ │ │ │ ├── pt-BR.js │ │ │ │ │ ├── pt.js │ │ │ │ │ ├── bn.js │ │ │ │ │ ├── lv.js │ │ │ │ │ ├── ca.js │ │ │ │ │ ├── ps.js │ │ │ │ │ ├── sq.js │ │ │ │ │ ├── it.js │ │ │ │ │ ├── nl.js │ │ │ │ │ ├── ne.js │ │ │ │ │ ├── fr.js │ │ │ │ │ ├── es.js │ │ │ │ │ ├── gl.js │ │ │ │ │ ├── sl.js │ │ │ │ │ ├── ro.js │ │ │ │ │ ├── lt.js │ │ │ │ │ ├── pl.js │ │ │ │ │ ├── el.js │ │ │ │ │ ├── sr.js │ │ │ │ │ ├── uk.js │ │ │ │ │ ├── bs.js │ │ │ │ │ ├── sr-Cyrl.js │ │ │ │ │ ├── ru.js │ │ │ │ │ ├── hsb.js │ │ │ │ │ ├── dsb.js │ │ │ │ │ ├── cs.js │ │ │ │ │ └── sk.js │ │ │ │ └── LICENSE.md │ │ │ ├── jquery │ │ │ │ └── LICENSE.txt │ │ │ └── xregexp │ │ │ │ └── LICENSE.txt │ │ ├── change_form.js │ │ ├── cancel.js │ │ ├── autocomplete.js │ │ ├── nav_sidebar.js │ │ ├── prepopulate.js │ │ ├── collapse.js │ │ ├── SelectBox.js │ │ └── core.js │ └── css │ │ ├── dashboard.css │ │ ├── fonts.css │ │ ├── login.css │ │ ├── vendor │ │ └── select2 │ │ │ └── LICENSE-SELECT2.md │ │ ├── responsive_rtl.css │ │ ├── nav_sidebar.css │ │ └── rtl.css ├── js │ └── src │ │ ├── zbase.js │ │ ├── playground │ │ ├── notice_board │ │ │ └── zbase.js │ │ ├── game_map │ │ │ └── zbase.js │ │ ├── particle │ │ │ └── zbase.js │ │ ├── ac_game_object │ │ │ └── zbase.js │ │ ├── score_board │ │ │ └── zbase.js │ │ ├── chat_field │ │ │ └── zbase.js │ │ ├── skill │ │ │ └── fireball │ │ │ │ └── zbase.js │ │ ├── zbase.js │ │ └── socket │ │ │ └── multiplayer │ │ │ └── zbase.js │ │ └── menu │ │ └── zbase.js └── css │ └── game.css ├── scripts ├── uwsgi.ini └── compress_game_js.sh ├── manage.py └── README.md /acapp/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/urls/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/views/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/consumers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/urls/menu/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/views/menu/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /match_system/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /match_system/src/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/models/player/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/urls/playground/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/urls/settings/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/views/playground/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/views/settings/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/consumers/multiplayer/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/urls/settings/acwing/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/views/settings/acwing/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/views/settings/acwing/acapp/__init.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /game/views/settings/acwing/web/__init.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /match_system/src/match_server/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/__pycache__ 2 | 3 | db.sqlite3 4 | -------------------------------------------------------------------------------- /game/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /game/urls/menu/index.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | urlpatterns = [ 4 | 5 | ] -------------------------------------------------------------------------------- /game/urls/playground/index.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | urlpatterns = [ 4 | 5 | ] -------------------------------------------------------------------------------- /match_system/src/match_server/match_service/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['ttypes', 'constants', 'Match'] 2 | -------------------------------------------------------------------------------- /static/image/menu/background.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuwenchao99/WebGame-Moba/HEAD/static/image/menu/background.gif -------------------------------------------------------------------------------- /game/static/image/menu/background.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuwenchao99/WebGame-Moba/HEAD/game/static/image/menu/background.gif -------------------------------------------------------------------------------- /static/image/settings/AcWing_Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuwenchao99/WebGame-Moba/HEAD/static/image/settings/AcWing_Logo.png -------------------------------------------------------------------------------- /game/views/index.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | def index(request): 4 | return render(request, "multiends/web.html") 5 | -------------------------------------------------------------------------------- /static/image/menu/background-myimage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuwenchao99/WebGame-Moba/HEAD/static/image/menu/background-myimage.gif -------------------------------------------------------------------------------- /game/static/image/settings/AcWing_Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuwenchao99/WebGame-Moba/HEAD/game/static/image/settings/AcWing_Logo.png -------------------------------------------------------------------------------- /static/admin/fonts/Roboto-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuwenchao99/WebGame-Moba/HEAD/static/admin/fonts/Roboto-Bold-webfont.woff -------------------------------------------------------------------------------- /static/admin/fonts/Roboto-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuwenchao99/WebGame-Moba/HEAD/static/admin/fonts/Roboto-Light-webfont.woff -------------------------------------------------------------------------------- /game/static/image/menu/background-myimage.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuwenchao99/WebGame-Moba/HEAD/game/static/image/menu/background-myimage.gif -------------------------------------------------------------------------------- /static/admin/fonts/Roboto-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuwenchao99/WebGame-Moba/HEAD/static/admin/fonts/Roboto-Regular-webfont.woff -------------------------------------------------------------------------------- /game/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from game.models.player.player import Player 3 | 4 | # Register your models here. 5 | 6 | admin.site.register(Player) 7 | -------------------------------------------------------------------------------- /game/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class GameConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'game' 7 | -------------------------------------------------------------------------------- /match_system/thrift/match.thrift: -------------------------------------------------------------------------------- 1 | namespace py match_service 2 | 3 | service Match { 4 | i32 add_player(1: i32 score, 2: string uuid, 3: string username, 4: string photo, 5: string channel_name), 5 | 6 | } -------------------------------------------------------------------------------- /game/routing.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from game.consumers.multiplayer.index import MultiPlayer 3 | 4 | websocket_urlpatterns = [ 5 | path("wss/multiplayer/", MultiPlayer.as_asgi(), name="wss_multiplayer"), 6 | ] 7 | -------------------------------------------------------------------------------- /scripts/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | socket = 127.0.0.1:8000 3 | chdir = /home/acs/acapp 4 | wsgi-file = acapp/wsgi.py 5 | master = true 6 | processes = 2 7 | threads = 5 8 | vacuum = true -------------------------------------------------------------------------------- /static/admin/fonts/README.txt: -------------------------------------------------------------------------------- 1 | Roboto webfont source: https://www.google.com/fonts/specimen/Roboto 2 | WOFF files extracted using https://github.com/majodev/google-webfonts-helper 3 | Weights used in this project: Light (300), Regular (400), Bold (700) 4 | -------------------------------------------------------------------------------- /scripts/compress_game_js.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | JS_PATH=/home/acs/acapp/game/static/js/ 4 | JS_PATH_DIST=${JS_PATH}dist/ 5 | JS_PATH_SRC=${JS_PATH}src/ 6 | 7 | find $JS_PATH_SRC -type f -name '*.js' | sort | xargs cat | terser -c -m > ${JS_PATH_DIST}game.js 8 | 9 | echo yes | python3 manage.py collectstatic 10 | -------------------------------------------------------------------------------- /static/admin/img/tooltag-arrowright.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /game/urls/index.py: -------------------------------------------------------------------------------- 1 | from django.urls import path, include 2 | from game.views.index import index 3 | 4 | urlpatterns = [ 5 | path("", index, name="index"), 6 | path("menu/", include("game.urls.menu.index")), 7 | path("playground/", include("game.urls.playground.index")), 8 | path("settings/", include("game.urls.settings.index")), 9 | ] -------------------------------------------------------------------------------- /static/admin/img/README.txt: -------------------------------------------------------------------------------- 1 | All icons are taken from Font Awesome (http://fontawesome.io/) project. 2 | The Font Awesome font is licensed under the SIL OFL 1.1: 3 | - https://scripts.sil.org/OFL 4 | 5 | SVG icons source: https://github.com/encharm/Font-Awesome-SVG-PNG 6 | Font-Awesome-SVG-PNG is licensed under the MIT license (see file license 7 | in current folder). 8 | -------------------------------------------------------------------------------- /static/admin/img/icon-addlink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/tooltag-add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /game/views/settings/logout.py: -------------------------------------------------------------------------------- 1 | from django.http import JsonResponse 2 | from django.contrib.auth import logout 3 | 4 | def signout(request): 5 | user = request.user 6 | if not user.is_authenticated: 7 | return JsonResponse({ 8 | 'result': "success", 9 | }) 10 | logout(request) 11 | return JsonResponse({ 12 | 'result': "success", 13 | }) -------------------------------------------------------------------------------- /static/admin/js/jquery.init.js: -------------------------------------------------------------------------------- 1 | /*global jQuery:false*/ 2 | 'use strict'; 3 | /* Puts the included jQuery into our own namespace using noConflict and passing 4 | * it 'true'. This ensures that the included jQuery doesn't pollute the global 5 | * namespace (i.e. this preserves pre-existing values for both window.$ and 6 | * window.jQuery). 7 | */ 8 | window.django = {jQuery: jQuery.noConflict(true)}; 9 | -------------------------------------------------------------------------------- /static/admin/img/icon-changelink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/js/src/zbase.js: -------------------------------------------------------------------------------- 1 | export class AcGame { 2 | constructor(id, AcWingOS) { 3 | this.id = id; 4 | this.AcWingOS = AcWingOS; 5 | this.$ac_game = $('#' + id); 6 | this.settings = new Settings(this); 7 | this.menu = new AcGameMenu(this); 8 | this.playground = new AcGamePlayground(this); 9 | this.start(); 10 | } 11 | 12 | start(){ 13 | } 14 | } -------------------------------------------------------------------------------- /game/static/js/src/zbase.js: -------------------------------------------------------------------------------- 1 | export class AcGame { 2 | constructor(id, AcWingOS) { 3 | this.id = id; 4 | this.AcWingOS = AcWingOS; 5 | this.$ac_game = $('#' + id); 6 | this.settings = new Settings(this); 7 | this.menu = new AcGameMenu(this); 8 | this.playground = new AcGamePlayground(this); 9 | this.start(); 10 | } 11 | 12 | start(){ 13 | } 14 | } -------------------------------------------------------------------------------- /static/admin/img/icon-deletelink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-yes.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /acapp/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for acapp project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'acapp.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /game/models/player/player.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from django.contrib.auth.models import User 3 | 4 | class Player(models.Model): 5 | user = models.OneToOneField(User, on_delete=models.CASCADE) 6 | photo = models.URLField(max_length=256, blank=True) 7 | openid = models.CharField(default="", max_length=50, blank=True, null=True) 8 | score = models.IntegerField(default=1500) 9 | 10 | def __str__(self): 11 | return str(self.user) -------------------------------------------------------------------------------- /match_system/src/match_server/match_service/constants.py: -------------------------------------------------------------------------------- 1 | # 2 | # Autogenerated by Thrift Compiler (0.16.0) 3 | # 4 | # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 5 | # 6 | # options string: py 7 | # 8 | 9 | from thrift.Thrift import TType, TMessageType, TFrozenDict, TException, TApplicationException 10 | from thrift.protocol.TProtocol import TProtocolException 11 | from thrift.TRecursive import fix_spec 12 | 13 | import sys 14 | from .ttypes import * 15 | -------------------------------------------------------------------------------- /static/admin/img/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /game/migrations/0003_player_score.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.8 on 2022-01-08 15:32 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('game', '0002_player_openid'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='player', 15 | name='score', 16 | field=models.IntegerField(default=1500), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /game/migrations/0002_player_openid.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.8 on 2021-12-04 05:18 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('game', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='player', 15 | name='openid', 16 | field=models.CharField(blank=True, default='', max_length=50, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /static/admin/css/dashboard.css: -------------------------------------------------------------------------------- 1 | /* DASHBOARD */ 2 | 3 | .dashboard .module table th { 4 | width: 100%; 5 | } 6 | 7 | .dashboard .module table td { 8 | white-space: nowrap; 9 | } 10 | 11 | .dashboard .module table td a { 12 | display: block; 13 | padding-right: .6em; 14 | } 15 | 16 | /* RECENT ACTIONS MODULE */ 17 | 18 | .module ul.actionlist { 19 | margin-left: 0; 20 | } 21 | 22 | ul.actionlist li { 23 | list-style-type: none; 24 | overflow: hidden; 25 | text-overflow: ellipsis; 26 | } 27 | -------------------------------------------------------------------------------- /static/admin/img/icon-alert.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /game/views/settings/login.py: -------------------------------------------------------------------------------- 1 | from django.http import JsonResponse 2 | from django.contrib.auth import authenticate, login 3 | 4 | def signin(request): 5 | data = request.GET 6 | username = data.get('username') 7 | password = data.get('password') 8 | user = authenticate(username=username, password=password) 9 | if not user: 10 | return JsonResponse({ 11 | 'result': "用户名或密码不存在" 12 | }) 13 | login(request, user) 14 | return JsonResponse({ 15 | 'result': "success" 16 | }) -------------------------------------------------------------------------------- /static/admin/css/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Roboto'; 3 | src: url('../fonts/Roboto-Bold-webfont.woff'); 4 | font-weight: 700; 5 | font-style: normal; 6 | } 7 | 8 | @font-face { 9 | font-family: 'Roboto'; 10 | src: url('../fonts/Roboto-Regular-webfont.woff'); 11 | font-weight: 400; 12 | font-style: normal; 13 | } 14 | 15 | @font-face { 16 | font-family: 'Roboto'; 17 | src: url('../fonts/Roboto-Light-webfont.woff'); 18 | font-weight: 300; 19 | font-style: normal; 20 | } 21 | -------------------------------------------------------------------------------- /static/admin/js/prepopulate_init.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | { 3 | const $ = django.jQuery; 4 | const fields = $('#django-admin-prepopulated-fields-constants').data('prepopulatedFields'); 5 | $.each(fields, function(index, field) { 6 | $('.empty-form .form-row .field-' + field.name + ', .empty-form.form-row .field-' + field.name).addClass('prepopulated_field'); 7 | $(field.id).data('dependency_list', field.dependency_list).prepopulate( 8 | field.dependency_ids, field.maxLength, field.allowUnicode 9 | ); 10 | }); 11 | } 12 | -------------------------------------------------------------------------------- /match_system/src/match_server/match_service/ttypes.py: -------------------------------------------------------------------------------- 1 | # 2 | # Autogenerated by Thrift Compiler (0.16.0) 3 | # 4 | # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 5 | # 6 | # options string: py 7 | # 8 | 9 | from thrift.Thrift import TType, TMessageType, TFrozenDict, TException, TApplicationException 10 | from thrift.protocol.TProtocol import TProtocolException 11 | from thrift.TRecursive import fix_spec 12 | 13 | import sys 14 | 15 | from thrift.transport import TTransport 16 | all_structs = [] 17 | fix_spec(all_structs) 18 | del all_structs 19 | -------------------------------------------------------------------------------- /static/admin/img/icon-no.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/inline-delete.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-viewlink.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /game/urls/settings/index.py: -------------------------------------------------------------------------------- 1 | from functools import singledispatch 2 | from django.urls import path, include 3 | from game.views.settings.getinfo import getinfo 4 | from game.views.settings.login import signin 5 | from game.views.settings.logout import signout 6 | from game.views.settings.register import register 7 | 8 | urlpatterns = [ 9 | path("getinfo/", getinfo, name="settings_getinfo"), 10 | path("login/", signin, name="settings_login"), 11 | path("logout/", signout, name="settings_logout"), 12 | path("register/", register, name="settings_register"), 13 | path("acwing/", include("game.urls.settings.acwing.index")), 14 | ] -------------------------------------------------------------------------------- /static/admin/js/popup_response.js: -------------------------------------------------------------------------------- 1 | /*global opener */ 2 | 'use strict'; 3 | { 4 | const initData = JSON.parse(document.getElementById('django-admin-popup-response-constants').dataset.popupResponse); 5 | switch(initData.action) { 6 | case 'change': 7 | opener.dismissChangeRelatedObjectPopup(window, initData.value, initData.obj, initData.new_value); 8 | break; 9 | case 'delete': 10 | opener.dismissDeleteRelatedObjectPopup(window, initData.value); 11 | break; 12 | default: 13 | opener.dismissAddRelatedObjectPopup(window, initData.value, initData.obj); 14 | break; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/zh-TW.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(n){return"請刪掉"+(n.input.length-n.maximum)+"個字元"},inputTooShort:function(n){return"請再輸入"+(n.minimum-n.input.length)+"個字元"},loadingMore:function(){return"載入中…"},maximumSelected:function(n){return"你只能選擇最多"+n.maximum+"項"},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"},removeAllItems:function(){return"刪除所有項目"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/js/src/playground/notice_board/zbase.js: -------------------------------------------------------------------------------- 1 | class NoticeBoard extends AcGameObject { 2 | constructor(playground) { 3 | super(); 4 | this.playground = playground; 5 | this.ctx = this.playground.game_map.ctx; 6 | this.text = "已就绪:0人"; 7 | 8 | } 9 | start() { 10 | 11 | } 12 | write(text) { 13 | this.text = text; 14 | } 15 | update() { 16 | this.render(); 17 | } 18 | render() { 19 | this.ctx.font = "20px serif"; 20 | this.ctx.fillStyle = "white"; 21 | this.ctx.textAlign = "center"; 22 | this.ctx.fillText(this.text, this.playground.width / 2, 20); 23 | } 24 | } -------------------------------------------------------------------------------- /game/static/js/src/playground/notice_board/zbase.js: -------------------------------------------------------------------------------- 1 | class NoticeBoard extends AcGameObject { 2 | constructor(playground) { 3 | super(); 4 | this.playground = playground; 5 | this.ctx = this.playground.game_map.ctx; 6 | this.text = "已就绪:0人"; 7 | 8 | } 9 | start() { 10 | 11 | } 12 | write(text) { 13 | this.text = text; 14 | } 15 | update() { 16 | this.render(); 17 | } 18 | render() { 19 | this.ctx.font = "20px serif"; 20 | this.ctx.fillStyle = "white"; 21 | this.ctx.textAlign = "center"; 22 | this.ctx.fillText(this.text, this.playground.width / 2, 20); 23 | } 24 | } -------------------------------------------------------------------------------- /static/admin/img/icon-unknown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/img/icon-unknown-alt.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/admin/js/change_form.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | { 3 | const inputTags = ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA']; 4 | const modelName = document.getElementById('django-admin-form-add-constants').dataset.modelName; 5 | if (modelName) { 6 | const form = document.getElementById(modelName + '_form'); 7 | for (const element of form.elements) { 8 | // HTMLElement.offsetParent returns null when the element is not 9 | // rendered. 10 | if (inputTags.includes(element.tagName) && !element.disabled && element.offsetParent) { 11 | element.focus(); 12 | break; 13 | } 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/zh-CN.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(n){return"请删除"+(n.input.length-n.maximum)+"个字符"},inputTooShort:function(n){return"请再输入至少"+(n.minimum-n.input.length)+"个字符"},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(n){return"最多只能选择"+n.maximum+"个项目"},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"},removeAllItems:function(){return"删除所有项目"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ja.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ja",[],function(){return{errorLoading:function(){return"結果が読み込まれませんでした"},inputTooLong:function(n){return n.input.length-n.maximum+" 文字を削除してください"},inputTooShort:function(n){return"少なくとも "+(n.minimum-n.input.length)+" 文字を入力してください"},loadingMore:function(){return"読み込み中…"},maximumSelected:function(n){return n.maximum+" 件しか選択できません"},noResults:function(){return"対象が見つかりません"},searching:function(){return"検索しています…"},removeAllItems:function(){return"すべてのアイテムを削除"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/az.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/az",[],function(){return{inputTooLong:function(n){return n.input.length-n.maximum+" simvol silin"},inputTooShort:function(n){return n.minimum-n.input.length+" simvol daxil edin"},loadingMore:function(){return"Daha çox nəticə yüklənir…"},maximumSelected:function(n){return"Sadəcə "+n.maximum+" element seçə bilərsiniz"},noResults:function(){return"Nəticə tapılmadı"},searching:function(){return"Axtarılır…"},removeAllItems:function(){return"Bütün elementləri sil"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/img/icon-clock.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ko.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(n){return"너무 깁니다. "+(n.input.length-n.maximum)+" 글자 지워주세요."},inputTooShort:function(n){return"너무 짧습니다. "+(n.minimum-n.input.length)+" 글자 더 입력해주세요."},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(n){return"최대 "+n.maximum+"개까지만 선택 가능합니다."},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"},removeAllItems:function(){return"모든 항목 삭제"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'acapp.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/vi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/vi",[],function(){return{inputTooLong:function(n){return"Vui lòng xóa bớt "+(n.input.length-n.maximum)+" ký tự"},inputTooShort:function(n){return"Vui lòng nhập thêm từ "+(n.minimum-n.input.length)+" ký tự trở lên"},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(n){return"Chỉ có thể chọn được "+n.maximum+" lựa chọn"},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"},removeAllItems:function(){return"Xóa tất cả các mục"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /game/templates/multiends/web.html: -------------------------------------------------------------------------------- 1 | {% load static %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 18 | 19 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/tk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/tk",[],function(){return{errorLoading:function(){return"Netije ýüklenmedi."},inputTooLong:function(e){return e.input.length-e.maximum+" harp bozuň."},inputTooShort:function(e){return"Ýene-de iň az "+(e.minimum-e.input.length)+" harp ýazyň."},loadingMore:function(){return"Köpräk netije görkezilýär…"},maximumSelected:function(e){return"Diňe "+e.maximum+" sanysyny saýlaň."},noResults:function(){return"Netije tapylmady."},searching:function(){return"Gözlenýär…"},removeAllItems:function(){return"Remove all items"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/id.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/id",[],function(){return{errorLoading:function(){return"Data tidak boleh diambil."},inputTooLong:function(n){return"Hapuskan "+(n.input.length-n.maximum)+" huruf"},inputTooShort:function(n){return"Masukkan "+(n.minimum-n.input.length)+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(n){return"Anda hanya dapat memilih "+n.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"},removeAllItems:function(){return"Hapus semua item"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/tr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/tr",[],function(){return{errorLoading:function(){return"Sonuç yüklenemedi"},inputTooLong:function(n){return n.input.length-n.maximum+" karakter daha girmelisiniz"},inputTooShort:function(n){return"En az "+(n.minimum-n.input.length)+" karakter daha girmelisiniz"},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(n){return"Sadece "+n.maximum+" seçim yapabilirsiniz"},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"},removeAllItems:function(){return"Tüm öğeleri kaldır"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ar.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ar",[],function(){return{errorLoading:function(){return"لا يمكن تحميل النتائج"},inputTooLong:function(n){return"الرجاء حذف "+(n.input.length-n.maximum)+" عناصر"},inputTooShort:function(n){return"الرجاء إضافة "+(n.minimum-n.input.length)+" عناصر"},loadingMore:function(){return"جاري تحميل نتائج إضافية..."},maximumSelected:function(n){return"تستطيع إختيار "+n.maximum+" بنود فقط"},noResults:function(){return"لم يتم العثور على أي نتائج"},searching:function(){return"جاري البحث…"},removeAllItems:function(){return"قم بإزالة كل العناصر"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/th.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/th",[],function(){return{errorLoading:function(){return"ไม่สามารถค้นข้อมูลได้"},inputTooLong:function(n){return"โปรดลบออก "+(n.input.length-n.maximum)+" ตัวอักษร"},inputTooShort:function(n){return"โปรดพิมพ์เพิ่มอีก "+(n.minimum-n.input.length)+" ตัวอักษร"},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(n){return"คุณสามารถเลือกได้ไม่เกิน "+n.maximum+" รายการ"},noResults:function(){return"ไม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"},removeAllItems:function(){return"ลบรายการทั้งหมด"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/nb.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/nb",[],function(){return{errorLoading:function(){return"Kunne ikke hente resultater."},inputTooLong:function(e){return"Vennligst fjern "+(e.input.length-e.maximum)+" tegn"},inputTooShort:function(e){return"Vennligst skriv inn "+(e.minimum-e.input.length)+" tegn til"},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"},removeAllItems:function(){return"Fjern alle elementer"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/km.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/km",[],function(){return{errorLoading:function(){return"មិនអាចទាញយកទិន្នន័យ"},inputTooLong:function(n){return"សូមលុបចេញ "+(n.input.length-n.maximum)+" អក្សរ"},inputTooShort:function(n){return"សូមបញ្ចូល"+(n.minimum-n.input.length)+" អក្សរ រឺ ច្រើនជាងនេះ"},loadingMore:function(){return"កំពុងទាញយកទិន្នន័យបន្ថែម..."},maximumSelected:function(n){return"អ្នកអាចជ្រើសរើសបានតែ "+n.maximum+" ជម្រើសប៉ុណ្ណោះ"},noResults:function(){return"មិនមានលទ្ធផល"},searching:function(){return"កំពុងស្វែងរក..."},removeAllItems:function(){return"លុបធាតុទាំងអស់"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(n){return"Vänligen sudda ut "+(n.input.length-n.maximum)+" tecken"},inputTooShort:function(n){return"Vänligen skriv in "+(n.minimum-n.input.length)+" eller fler tecken"},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(n){return"Du kan max välja "+n.maximum+" element"},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"},removeAllItems:function(){return"Ta bort alla objekt"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/fi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/fi",[],function(){return{errorLoading:function(){return"Tuloksia ei saatu ladattua."},inputTooLong:function(n){return"Ole hyvä ja anna "+(n.input.length-n.maximum)+" merkkiä vähemmän"},inputTooShort:function(n){return"Ole hyvä ja anna "+(n.minimum-n.input.length)+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(n){return"Voit valita ainoastaan "+n.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){return"Haetaan…"},removeAllItems:function(){return"Poista kaikki kohteet"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/is.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/is",[],function(){return{inputTooLong:function(n){var t=n.input.length-n.maximum,e="Vinsamlegast styttið texta um "+t+" staf";return t<=1?e:e+"i"},inputTooShort:function(n){var t=n.minimum-n.input.length,e="Vinsamlegast skrifið "+t+" staf";return t>1&&(e+="i"),e+=" í viðbót"},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(n){return"Þú getur aðeins valið "+n.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"},removeAllItems:function(){return"Fjarlægðu öll atriði"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/et.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var n=e.input.length-e.maximum,t="Sisesta "+n+" täht";return 1!=n&&(t+="e"),t+=" vähem"},inputTooShort:function(e){var n=e.minimum-e.input.length,t="Sisesta "+n+" täht";return 1!=n&&(t+="e"),t+=" rohkem"},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var n="Saad vaid "+e.maximum+" tulemus";return 1==e.maximum?n+="e":n+="t",n+=" valida"},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"},removeAllItems:function(){return"Eemalda kõik esemed"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /game/urls/settings/acwing/index.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from game.views.settings.acwing.web.apply_code import apply_code as web_apply_code 3 | from game.views.settings.acwing.web.receive_code import receive_code as web_receive_code 4 | from game.views.settings.acwing.acapp.apply_code import apply_code as acapp_apply_code 5 | from game.views.settings.acwing.acapp.receive_code import receive_code as acapp_receive_code 6 | 7 | urlpatterns = [ 8 | path("web/apply_code/", web_apply_code, name="settings_acwing_web_apply_code"), 9 | path("web/receive_code/", web_receive_code, name="settings_acwing_web_receive_code"), 10 | path("acapp/apply_code/", acapp_apply_code, name="settings_acwing_acapp_apply_code"), 11 | path("acapp/receive_code/", acapp_receive_code, name="settings_acwing_acapp_receive_code"), 12 | ] -------------------------------------------------------------------------------- /game/views/settings/acwing/acapp/apply_code.py: -------------------------------------------------------------------------------- 1 | from django.http import JsonResponse 2 | from urllib.parse import quote 3 | from random import randint 4 | from django.core.cache import cache 5 | from django.shortcuts import redirect 6 | 7 | def get_state(): 8 | res = "" 9 | for i in range(8): 10 | res += str(randint(0, 9)) 11 | return res 12 | 13 | def apply_code(request): 14 | appid = "652" 15 | redirect_uri = quote("https://app652.acapp.acwing.com.cn/settings/acwing/acapp/receive_code") 16 | scope = "userinfo" 17 | state = get_state() 18 | 19 | cache.set(state, True, 7200) # 有效期2小时 20 | 21 | return JsonResponse({ 22 | 'result': "success", 23 | 'appid': appid, 24 | 'redirect_uri': redirect_uri, 25 | 'scope': scope, 26 | 'state': state, 27 | }) -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/hu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/hu",[],function(){return{errorLoading:function(){return"Az eredmények betöltése nem sikerült."},inputTooLong:function(e){return"Túl hosszú. "+(e.input.length-e.maximum)+" karakterrel több, mint kellene."},inputTooShort:function(e){return"Túl rövid. Még "+(e.minimum-e.input.length)+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"},removeAllItems:function(){return"Távolítson el minden elemet"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ms.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ms",[],function(){return{errorLoading:function(){return"Keputusan tidak berjaya dimuatkan."},inputTooLong:function(n){return"Sila hapuskan "+(n.input.length-n.maximum)+" aksara"},inputTooShort:function(n){return"Sila masukkan "+(n.minimum-n.input.length)+" atau lebih aksara"},loadingMore:function(){return"Sedang memuatkan keputusan…"},maximumSelected:function(n){return"Anda hanya boleh memilih "+n.maximum+" pilihan"},noResults:function(){return"Tiada padanan yang ditemui"},searching:function(){return"Mencari…"},removeAllItems:function(){return"Keluarkan semua item"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ka.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ka",[],function(){return{errorLoading:function(){return"მონაცემების ჩატვირთვა შეუძლებელია."},inputTooLong:function(n){return"გთხოვთ აკრიფეთ "+(n.input.length-n.maximum)+" სიმბოლოთი ნაკლები"},inputTooShort:function(n){return"გთხოვთ აკრიფეთ "+(n.minimum-n.input.length)+" სიმბოლო ან მეტი"},loadingMore:function(){return"მონაცემების ჩატვირთვა…"},maximumSelected:function(n){return"თქვენ შეგიძლიათ აირჩიოთ არაუმეტეს "+n.maximum+" ელემენტი"},noResults:function(){return"რეზულტატი არ მოიძებნა"},searching:function(){return"ძიება…"},removeAllItems:function(){return"ამოიღე ყველა ელემენტი"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/bg.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/bg",[],function(){return{inputTooLong:function(n){var e=n.input.length-n.maximum,u="Моля въведете с "+e+" по-малко символ";return e>1&&(u+="a"),u},inputTooShort:function(n){var e=n.minimum-n.input.length,u="Моля въведете още "+e+" символ";return e>1&&(u+="a"),u},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(n){var e="Можете да направите до "+n.maximum+" ";return n.maximum>1?e+="избора":e+="избор",e},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"},removeAllItems:function(){return"Премахнете всички елементи"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/da.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"Resultaterne kunne ikke indlæses."},inputTooLong:function(e){return"Angiv venligst "+(e.input.length-e.maximum)+" tegn mindre"},inputTooShort:function(e){return"Angiv venligst "+(e.minimum-e.input.length)+" tegn mere"},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var n="Du kan kun vælge "+e.maximum+" emne";return 1!=e.maximum&&(n+="r"),n},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"},removeAllItems:function(){return"Fjern alle elementer"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/hy.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hy",[],function(){return{errorLoading:function(){return"Արդյունքները հնարավոր չէ բեռնել։"},inputTooLong:function(n){return"Խնդրում ենք հեռացնել "+(n.input.length-n.maximum)+" նշան"},inputTooShort:function(n){return"Խնդրում ենք մուտքագրել "+(n.minimum-n.input.length)+" կամ ավել նշաններ"},loadingMore:function(){return"Բեռնվում են նոր արդյունքներ․․․"},maximumSelected:function(n){return"Դուք կարող եք ընտրել առավելագույնը "+n.maximum+" կետ"},noResults:function(){return"Արդյունքներ չեն գտնվել"},searching:function(){return"Որոնում․․․"},removeAllItems:function(){return"Հեռացնել բոլոր տարրերը"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/fa.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(n){return"لطفاً "+(n.input.length-n.maximum)+" کاراکتر را حذف نمایید"},inputTooShort:function(n){return"لطفاً تعداد "+(n.minimum-n.input.length)+" کاراکتر یا بیشتر وارد نمایید"},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(n){return"شما تنها می‌توانید "+n.maximum+" آیتم را انتخاب نمایید"},noResults:function(){return"هیچ نتیجه‌ای یافت نشد"},searching:function(){return"در حال جستجو..."},removeAllItems:function(){return"همه موارد را حذف کنید"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/en.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Please delete "+n+" character";return 1!=n&&(r+="s"),r},inputTooShort:function(e){return"Please enter "+(e.minimum-e.input.length)+" or more characters"},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var n="You can only select "+e.maximum+" item";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No results found"},searching:function(){return"Searching…"},removeAllItems:function(){return"Remove all items"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/hi.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(n){var e=n.input.length-n.maximum,r=e+" अक्षर को हटा दें";return e>1&&(r=e+" अक्षरों को हटा दें "),r},inputTooShort:function(n){return"कृपया "+(n.minimum-n.input.length)+" या अधिक अक्षर दर्ज करें"},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(n){return"आप केवल "+n.maximum+" आइटम का चयन कर सकते हैं"},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."},removeAllItems:function(){return"सभी वस्तुओं को हटा दें"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/he.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"שגיאה בטעינת התוצאות"},inputTooLong:function(n){var e=n.input.length-n.maximum,r="נא למחוק ";return r+=1===e?"תו אחד":e+" תווים"},inputTooShort:function(n){var e=n.minimum-n.input.length,r="נא להכניס ";return r+=1===e?"תו אחד":e+" תווים",r+=" או יותר"},loadingMore:function(){return"טוען תוצאות נוספות…"},maximumSelected:function(n){var e="באפשרותך לבחור עד ";return 1===n.maximum?e+="פריט אחד":e+=n.maximum+" פריטים",e},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"},removeAllItems:function(){return"הסר את כל הפריטים"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/hr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hr",[],function(){function n(n){var e=" "+n+" znak";return n%10<5&&n%10>0&&(n%100<5||n%100>19)?n%10>1&&(e+="a"):e+="ova",e}return{errorLoading:function(){return"Preuzimanje nije uspjelo."},inputTooLong:function(e){return"Unesite "+n(e.input.length-e.maximum)},inputTooShort:function(e){return"Unesite još "+n(e.minimum-e.input.length)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(n){return"Maksimalan broj odabranih stavki je "+n.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Ukloni sve stavke"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /acapp/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for acapp project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | import django 13 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'acapp.settings') 14 | django.setup() 15 | 16 | from channels.auth import AuthMiddlewareStack 17 | from channels.routing import ProtocolTypeRouter, URLRouter 18 | from django.core.asgi import get_asgi_application 19 | from game.routing import websocket_urlpatterns 20 | 21 | from channels.layers import get_channel_layer 22 | channel_layer = get_channel_layer() 23 | 24 | application = ProtocolTypeRouter({ 25 | "http": get_asgi_application(), 26 | "websocket": AuthMiddlewareStack(URLRouter(websocket_urlpatterns)) 27 | }) 28 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/de.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/de",[],function(){return{errorLoading:function(){return"Die Ergebnisse konnten nicht geladen werden."},inputTooLong:function(e){return"Bitte "+(e.input.length-e.maximum)+" Zeichen weniger eingeben"},inputTooShort:function(e){return"Bitte "+(e.minimum-e.input.length)+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var n="Sie können nur "+e.maximum+" Element";return 1!=e.maximum&&(n+="e"),n+=" auswählen"},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"},removeAllItems:function(){return"Entferne alle Elemente"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /game/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 3.2.8 on 2021-11-27 14:30 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import django.db.models.deletion 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='Player', 19 | fields=[ 20 | ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('photo', models.URLField(blank=True, max_length=256)), 22 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), 23 | ], 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/af.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/af",[],function(){return{errorLoading:function(){return"Die resultate kon nie gelaai word nie."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Verwyders asseblief "+n+" character";return 1!=n&&(r+="s"),r},inputTooShort:function(e){return"Voer asseblief "+(e.minimum-e.input.length)+" of meer karakters"},loadingMore:function(){return"Meer resultate word gelaai…"},maximumSelected:function(e){var n="Kies asseblief net "+e.maximum+" item";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"Geen resultate gevind"},searching:function(){return"Besig…"},removeAllItems:function(){return"Verwyder alle items"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/eu.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return n+=1==t?"karaktere bat":t+" karaktere",n+=" gutxiago"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return n+=1==t?"karaktere bat":t+" karaktere",n+=" gehiago"},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return 1===e.maximum?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"},removeAllItems:function(){return"Kendu elementu guztiak"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /acapp/urls.py: -------------------------------------------------------------------------------- 1 | """acapp URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.2/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path, include 18 | 19 | urlpatterns = [ 20 | path('', include('game.urls.index')), 21 | path('admin/', admin.site.urls), 22 | ] 23 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/mk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/mk",[],function(){return{inputTooLong:function(n){var e=(n.input.length,n.maximum,"Ве молиме внесете "+n.maximum+" помалку карактер");return 1!==n.maximum&&(e+="и"),e},inputTooShort:function(n){var e=(n.minimum,n.input.length,"Ве молиме внесете уште "+n.maximum+" карактер");return 1!==n.maximum&&(e+="и"),e},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(n){var e="Можете да изберете само "+n.maximum+" ставк";return 1===n.maximum?e+="а":e+="и",e},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"},removeAllItems:function(){return"Отстрани ги сите предмети"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/pt-BR.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Apague "+n+" caracter";return 1!=n&&(r+="es"),r},inputTooShort:function(e){return"Digite "+(e.minimum-e.input.length)+" ou mais caracteres"},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var n="Você só pode selecionar "+e.maximum+" ite";return 1==e.maximum?n+="m":n+="ns",n},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Remover todos os itens"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/pt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var r=e.input.length-e.maximum,n="Por favor apague "+r+" ";return n+=1!=r?"caracteres":"caractere"},inputTooShort:function(e){return"Introduza "+(e.minimum-e.input.length)+" ou mais caracteres"},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var r="Apenas pode seleccionar "+e.maximum+" ";return r+=1!=e.maximum?"itens":"item"},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"},removeAllItems:function(){return"Remover todos os itens"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/bn.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/bn",[],function(){return{errorLoading:function(){return"ফলাফলগুলি লোড করা যায়নি।"},inputTooLong:function(n){var e=n.input.length-n.maximum,u="অনুগ্রহ করে "+e+" টি অক্ষর মুছে দিন।";return 1!=e&&(u="অনুগ্রহ করে "+e+" টি অক্ষর মুছে দিন।"),u},inputTooShort:function(n){return n.minimum-n.input.length+" টি অক্ষর অথবা অধিক অক্ষর লিখুন।"},loadingMore:function(){return"আরো ফলাফল লোড হচ্ছে ..."},maximumSelected:function(n){var e=n.maximum+" টি আইটেম নির্বাচন করতে পারবেন।";return 1!=n.maximum&&(e=n.maximum+" টি আইটেম নির্বাচন করতে পারবেন।"),e},noResults:function(){return"কোন ফলাফল পাওয়া যায়নি।"},searching:function(){return"অনুসন্ধান করা হচ্ছে ..."}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/lv.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/lv",[],function(){function e(e,n,u,i){return 11===e?n:e%10==1?u:i}return{inputTooLong:function(n){var u=n.input.length-n.maximum,i="Lūdzu ievadiet par "+u;return(i+=" simbol"+e(u,"iem","u","iem"))+" mazāk"},inputTooShort:function(n){var u=n.minimum-n.input.length,i="Lūdzu ievadiet vēl "+u;return i+=" simbol"+e(u,"us","u","us")},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(n){var u="Jūs varat izvēlēties ne vairāk kā "+n.maximum;return u+=" element"+e(n.maximum,"us","u","us")},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"},removeAllItems:function(){return"Noņemt visus vienumus"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ca.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Si us plau, elimina "+n+" car";return r+=1==n?"àcter":"àcters"},inputTooShort:function(e){var n=e.minimum-e.input.length,r="Si us plau, introdueix "+n+" car";return r+=1==n?"àcter":"àcters"},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var n="Només es pot seleccionar "+e.maximum+" element";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"},removeAllItems:function(){return"Treu tots els elements"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ps.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ps",[],function(){return{errorLoading:function(){return"پايلي نه سي ترلاسه کېدای"},inputTooLong:function(n){var e=n.input.length-n.maximum,r="د مهربانۍ لمخي "+e+" توری ړنګ کړئ";return 1!=e&&(r=r.replace("توری","توري")),r},inputTooShort:function(n){return"لږ تر لږه "+(n.minimum-n.input.length)+" يا ډېر توري وليکئ"},loadingMore:function(){return"نوري پايلي ترلاسه کيږي..."},maximumSelected:function(n){var e="تاسو يوازي "+n.maximum+" قلم په نښه کولای سی";return 1!=n.maximum&&(e=e.replace("قلم","قلمونه")),e},noResults:function(){return"پايلي و نه موندل سوې"},searching:function(){return"لټول کيږي..."},removeAllItems:function(){return"ټول توکي لرې کړئ"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sq.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sq",[],function(){return{errorLoading:function(){return"Rezultatet nuk mund të ngarkoheshin."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Të lutem fshi "+n+" karakter";return 1!=n&&(t+="e"),t},inputTooShort:function(e){return"Të lutem shkruaj "+(e.minimum-e.input.length)+" ose më shumë karaktere"},loadingMore:function(){return"Duke ngarkuar më shumë rezultate…"},maximumSelected:function(e){var n="Mund të zgjedhësh vetëm "+e.maximum+" element";return 1!=e.maximum&&(n+="e"),n},noResults:function(){return"Nuk u gjet asnjë rezultat"},searching:function(){return"Duke kërkuar…"},removeAllItems:function(){return"Hiq të gjitha sendet"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/it.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Per favore cancella "+n+" caratter";return t+=1!==n?"i":"e"},inputTooShort:function(e){return"Per favore inserisci "+(e.minimum-e.input.length)+" o più caratteri"},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var n="Puoi selezionare solo "+e.maximum+" element";return 1!==e.maximum?n+="i":n+="o",n},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"},removeAllItems:function(){return"Rimuovi tutti gli oggetti"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /game/views/settings/acwing/web/apply_code.py: -------------------------------------------------------------------------------- 1 | from django.http import JsonResponse 2 | from urllib.parse import quote 3 | from random import randint 4 | from django.core.cache import cache 5 | from django.shortcuts import redirect 6 | 7 | def get_state(): 8 | res = "" 9 | for i in range(8): 10 | res += str(randint(0, 9)) 11 | return res 12 | 13 | def apply_code(request): 14 | appid = "652" 15 | redirect_uri = quote("https://app652.acapp.acwing.com.cn/settings/acwing/web/receive_code") 16 | scope = "userinfo" 17 | state = get_state() 18 | 19 | cache.set(state, True, 7200) # 有效期2小时 20 | 21 | apply_code_url = "https://www.acwing.com/third_party/api/oauth2/web/authorize/" 22 | return JsonResponse({ 23 | 'result': "success", 24 | 'apply_code_url': apply_code_url + "?appid=%s&redirect_uri=%s&scope=%s&state=%s" % (appid, redirect_uri, scope, state), 25 | }) -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/nl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){return"Gelieve "+(e.input.length-e.maximum)+" karakters te verwijderen"},inputTooShort:function(e){return"Gelieve "+(e.minimum-e.input.length)+" of meer karakters in te voeren"},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var n=1==e.maximum?"kan":"kunnen",r="Er "+n+" maar "+e.maximum+" item";return 1!=e.maximum&&(r+="s"),r+=" worden geselecteerd"},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"},removeAllItems:function(){return"Verwijder alle items"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ne.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ne",[],function(){return{errorLoading:function(){return"नतिजाहरु देखाउन सकिएन।"},inputTooLong:function(n){var e=n.input.length-n.maximum,u="कृपया "+e+" अक्षर मेटाउनुहोस्।";return 1!=e&&(u+="कृपया "+e+" अक्षरहरु मेटाउनुहोस्।"),u},inputTooShort:function(n){return"कृपया बाँकी रहेका "+(n.minimum-n.input.length)+" वा अरु धेरै अक्षरहरु भर्नुहोस्।"},loadingMore:function(){return"अरु नतिजाहरु भरिँदैछन् …"},maximumSelected:function(n){var e="तँपाई "+n.maximum+" वस्तु मात्र छान्न पाउँनुहुन्छ।";return 1!=n.maximum&&(e="तँपाई "+n.maximum+" वस्तुहरु मात्र छान्न पाउँनुहुन्छ।"),e},noResults:function(){return"कुनै पनि नतिजा भेटिएन।"},searching:function(){return"खोजि हुँदैछ…"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/fr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/fr",[],function(){return{errorLoading:function(){return"Les résultats ne peuvent pas être chargés."},inputTooLong:function(e){var n=e.input.length-e.maximum;return"Supprimez "+n+" caractère"+(n>1?"s":"")},inputTooShort:function(e){var n=e.minimum-e.input.length;return"Saisissez au moins "+n+" caractère"+(n>1?"s":"")},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){return"Vous pouvez seulement sélectionner "+e.maximum+" élément"+(e.maximum>1?"s":"")},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"},removeAllItems:function(){return"Supprimer tous les éléments"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/es.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"No se pudieron cargar los resultados"},inputTooLong:function(e){var n=e.input.length-e.maximum,r="Por favor, elimine "+n+" car";return r+=1==n?"ácter":"acteres"},inputTooShort:function(e){var n=e.minimum-e.input.length,r="Por favor, introduzca "+n+" car";return r+=1==n?"ácter":"acteres"},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var n="Sólo puede seleccionar "+e.maximum+" elemento";return 1!=e.maximum&&(n+="s"),n},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Eliminar todos los elementos"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/gl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/gl",[],function(){return{errorLoading:function(){return"Non foi posíbel cargar os resultados."},inputTooLong:function(e){var n=e.input.length-e.maximum;return 1===n?"Elimine un carácter":"Elimine "+n+" caracteres"},inputTooShort:function(e){var n=e.minimum-e.input.length;return 1===n?"Engada un carácter":"Engada "+n+" caracteres"},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){return 1===e.maximum?"Só pode seleccionar un elemento":"Só pode seleccionar "+e.maximum+" elementos"},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"},removeAllItems:function(){return"Elimina todos os elementos"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sl",[],function(){return{errorLoading:function(){return"Zadetkov iskanja ni bilo mogoče naložiti."},inputTooLong:function(e){var n=e.input.length-e.maximum,t="Prosim zbrišite "+n+" znak";return 2==n?t+="a":1!=n&&(t+="e"),t},inputTooShort:function(e){var n=e.minimum-e.input.length,t="Prosim vpišite še "+n+" znak";return 2==n?t+="a":1!=n&&(t+="e"),t},loadingMore:function(){return"Nalagam več zadetkov…"},maximumSelected:function(e){var n="Označite lahko največ "+e.maximum+" predmet";return 2==e.maximum?n+="a":1!=e.maximum&&(n+="e"),n},noResults:function(){return"Ni zadetkov."},searching:function(){return"Iščem…"},removeAllItems:function(){return"Odstranite vse elemente"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ro.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/ro",[],function(){return{errorLoading:function(){return"Rezultatele nu au putut fi incărcate."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să ștergeți"+t+" caracter";return 1!==t&&(n+="e"),n},inputTooShort:function(e){return"Vă rugăm să introduceți "+(e.minimum-e.input.length)+" sau mai multe caractere"},loadingMore:function(){return"Se încarcă mai multe rezultate…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",1!==e.maximum&&(t+="e"),t},noResults:function(){return"Nu au fost găsite rezultate"},searching:function(){return"Căutare…"},removeAllItems:function(){return"Eliminați toate elementele"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/lt.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/lt",[],function(){function n(n,e,i,t){return n%10==1&&(n%100<11||n%100>19)?e:n%10>=2&&n%10<=9&&(n%100<11||n%100>19)?i:t}return{inputTooLong:function(e){var i=e.input.length-e.maximum,t="Pašalinkite "+i+" simbol";return t+=n(i,"į","ius","ių")},inputTooShort:function(e){var i=e.minimum-e.input.length,t="Įrašykite dar "+i+" simbol";return t+=n(i,"į","ius","ių")},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(e){var i="Jūs galite pasirinkti tik "+e.maximum+" element";return i+=n(e.maximum,"ą","us","ų")},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"},removeAllItems:function(){return"Pašalinti visus elementus"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/pl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/pl",[],function(){var n=["znak","znaki","znaków"],e=["element","elementy","elementów"],r=function(n,e){return 1===n?e[0]:n>1&&n<=4?e[1]:n>=5?e[2]:void 0};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Usuń "+t+" "+r(t,n)},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Podaj przynajmniej "+t+" "+r(t,n)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(n){return"Możesz zaznaczyć tylko "+n.maximum+" "+r(n.maximum,e)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"},removeAllItems:function(){return"Usuń wszystkie przedmioty"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/el.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/el",[],function(){return{errorLoading:function(){return"Τα αποτελέσματα δεν μπόρεσαν να φορτώσουν."},inputTooLong:function(n){var e=n.input.length-n.maximum,u="Παρακαλώ διαγράψτε "+e+" χαρακτήρ";return 1==e&&(u+="α"),1!=e&&(u+="ες"),u},inputTooShort:function(n){return"Παρακαλώ συμπληρώστε "+(n.minimum-n.input.length)+" ή περισσότερους χαρακτήρες"},loadingMore:function(){return"Φόρτωση περισσότερων αποτελεσμάτων…"},maximumSelected:function(n){var e="Μπορείτε να επιλέξετε μόνο "+n.maximum+" επιλογ";return 1==n.maximum&&(e+="ή"),1!=n.maximum&&(e+="ές"),e},noResults:function(){return"Δεν βρέθηκαν αποτελέσματα"},searching:function(){return"Αναζήτηση…"},removeAllItems:function(){return"Καταργήστε όλα τα στοιχεία"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sr.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sr",[],function(){function n(n,e,r,t){return n%10==1&&n%100!=11?e:n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?r:t}return{errorLoading:function(){return"Preuzimanje nije uspelo."},inputTooLong:function(e){var r=e.input.length-e.maximum,t="Obrišite "+r+" simbol";return t+=n(r,"","a","a")},inputTooShort:function(e){var r=e.minimum-e.input.length,t="Ukucajte bar još "+r+" simbol";return t+=n(r,"","a","a")},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(e){var r="Možete izabrati samo "+e.maximum+" stavk";return r+=n(e.maximum,"u","e","i")},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Уклоните све ставке"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/uk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/uk",[],function(){function n(n,e,u,r){return n%100>10&&n%100<15?r:n%10==1?e:n%10>1&&n%10<5?u:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(e){return"Будь ласка, видаліть "+(e.input.length-e.maximum)+" "+n(e.maximum,"літеру","літери","літер")},inputTooShort:function(n){return"Будь ласка, введіть "+(n.minimum-n.input.length)+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(e){return"Ви можете вибрати лише "+e.maximum+" "+n(e.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"},removeAllItems:function(){return"Видалити всі елементи"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/bs.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/bs",[],function(){function e(e,n,r,t){return e%10==1&&e%100!=11?n:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?r:t}return{errorLoading:function(){return"Preuzimanje nije uspijelo."},inputTooLong:function(n){var r=n.input.length-n.maximum,t="Obrišite "+r+" simbol";return t+=e(r,"","a","a")},inputTooShort:function(n){var r=n.minimum-n.input.length,t="Ukucajte bar još "+r+" simbol";return t+=e(r,"","a","a")},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(n){var r="Možete izabrati samo "+n.maximum+" stavk";return r+=e(n.maximum,"u","e","i")},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"},removeAllItems:function(){return"Uklonite sve stavke"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sr-Cyrl.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/sr-Cyrl",[],function(){function n(n,e,r,u){return n%10==1&&n%100!=11?e:n%10>=2&&n%10<=4&&(n%100<12||n%100>14)?r:u}return{errorLoading:function(){return"Преузимање није успело."},inputTooLong:function(e){var r=e.input.length-e.maximum,u="Обришите "+r+" симбол";return u+=n(r,"","а","а")},inputTooShort:function(e){var r=e.minimum-e.input.length,u="Укуцајте бар још "+r+" симбол";return u+=n(r,"","а","а")},loadingMore:function(){return"Преузимање још резултата…"},maximumSelected:function(e){var r="Можете изабрати само "+e.maximum+" ставк";return r+=n(e.maximum,"у","е","и")},noResults:function(){return"Ништа није пронађено"},searching:function(){return"Претрага…"},removeAllItems:function(){return"Уклоните све ставке"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/ru.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/ru",[],function(){function n(n,e,r,u){return n%10<5&&n%10>0&&n%100<5||n%100>20?n%10>1?r:e:u}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(e){var r=e.input.length-e.maximum,u="Пожалуйста, введите на "+r+" символ";return u+=n(r,"","a","ов"),u+=" меньше"},inputTooShort:function(e){var r=e.minimum-e.input.length,u="Пожалуйста, введите ещё хотя бы "+r+" символ";return u+=n(r,"","a","ов")},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(e){var r="Вы можете выбрать не более "+e.maximum+" элемент";return r+=n(e.maximum,"","a","ов")},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"},removeAllItems:function(){return"Удалить все элементы"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /game/views/settings/getinfo.py: -------------------------------------------------------------------------------- 1 | from django.http import JsonResponse 2 | from game.models.player.player import Player 3 | 4 | def getinfo_acapp(request): 5 | player = Player.objects.all()[0] 6 | return JsonResponse({ 7 | 'result': "success", 8 | 'username': player.user.username, 9 | 'photo': player.photo, 10 | }) 11 | 12 | 13 | def getinfo_web(request): 14 | user = request.user 15 | if not user.is_authenticated: 16 | return JsonResponse({ 17 | 'result': "未登录" 18 | }) 19 | else: 20 | player = Player.objects.get(user=user) 21 | return JsonResponse({ 22 | 'result': "success", 23 | 'username': player.user.username, 24 | 'photo': player.photo, 25 | }) 26 | 27 | def getinfo(request): 28 | plateform = request.GET.get('platform') 29 | if plateform == "ACAPP": 30 | return getinfo_acapp(request) 31 | elif plateform == "WEB": 32 | return getinfo_web(request) -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/hsb.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/hsb",[],function(){var n=["znamješko","znamješce","znamješka","znamješkow"],e=["zapisk","zapiskaj","zapiski","zapiskow"],u=function(n,e){return 1===n?e[0]:2===n?e[1]:n>2&&n<=4?e[2]:n>=5?e[3]:void 0};return{errorLoading:function(){return"Wuslědki njedachu so začitać."},inputTooLong:function(e){var a=e.input.length-e.maximum;return"Prošu zhašej "+a+" "+u(a,n)},inputTooShort:function(e){var a=e.minimum-e.input.length;return"Prošu zapodaj znajmjeńša "+a+" "+u(a,n)},loadingMore:function(){return"Dalše wuslědki so začitaja…"},maximumSelected:function(n){return"Móžeš jenož "+n.maximum+" "+u(n.maximum,e)+"wubrać"},noResults:function(){return"Žane wuslědki namakane"},searching:function(){return"Pyta so…"},removeAllItems:function(){return"Remove all items"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/dsb.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/dsb",[],function(){var n=["znamuško","znamušce","znamuška","znamuškow"],e=["zapisk","zapiska","zapiski","zapiskow"],u=function(n,e){return 1===n?e[0]:2===n?e[1]:n>2&&n<=4?e[2]:n>=5?e[3]:void 0};return{errorLoading:function(){return"Wuslědki njejsu se dali zacytaś."},inputTooLong:function(e){var a=e.input.length-e.maximum;return"Pšosym lašuj "+a+" "+u(a,n)},inputTooShort:function(e){var a=e.minimum-e.input.length;return"Pšosym zapódaj nanejmjenjej "+a+" "+u(a,n)},loadingMore:function(){return"Dalšne wuslědki se zacytaju…"},maximumSelected:function(n){return"Móžoš jano "+n.maximum+" "+u(n.maximum,e)+"wubraś."},noResults:function(){return"Žedne wuslědki namakane"},searching:function(){return"Pyta se…"},removeAllItems:function(){return"Remove all items"}}}),n.define,n.require}(); -------------------------------------------------------------------------------- /static/admin/js/cancel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | { 3 | // Call function fn when the DOM is loaded and ready. If it is already 4 | // loaded, call the function now. 5 | // http://youmightnotneedjquery.com/#ready 6 | function ready(fn) { 7 | if (document.readyState !== 'loading') { 8 | fn(); 9 | } else { 10 | document.addEventListener('DOMContentLoaded', fn); 11 | } 12 | } 13 | 14 | ready(function() { 15 | function handleClick(event) { 16 | event.preventDefault(); 17 | const params = new URLSearchParams(window.location.search); 18 | if (params.has('_popup')) { 19 | window.close(); // Close the popup. 20 | } else { 21 | window.history.back(); // Otherwise, go back. 22 | } 23 | } 24 | 25 | document.querySelectorAll('.cancel-link').forEach(function(el) { 26 | el.addEventListener('click', handleClick); 27 | }); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /static/js/src/playground/game_map/zbase.js: -------------------------------------------------------------------------------- 1 | class GameMap extends AcGameObject { 2 | constructor(playground) { 3 | super(); 4 | this.playground = playground; 5 | this.$canvas = $(``); 6 | this.ctx = this.$canvas[0].getContext('2d'); 7 | this.ctx.canvas.width = this.playground.width; 8 | this.ctx.canvas.height = this.playground.height; 9 | this.playground.$playground.append(this.$canvas); 10 | } 11 | start() { 12 | this.$canvas.focus(); 13 | } 14 | 15 | resize() { 16 | this.ctx.canvas.width = this.playground.width; 17 | this.ctx.canvas.height = this.playground.height; 18 | this.ctx.fillStyle = "rgba(0, 0, 0, 1)"; 19 | this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); 20 | } 21 | 22 | update() { 23 | this.render(); 24 | } 25 | render() { 26 | this.ctx.fillStyle = "rgba(0, 0, 0, 0.2)"; 27 | this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /game/static/js/src/playground/game_map/zbase.js: -------------------------------------------------------------------------------- 1 | class GameMap extends AcGameObject { 2 | constructor(playground) { 3 | super(); 4 | this.playground = playground; 5 | this.$canvas = $(``); 6 | this.ctx = this.$canvas[0].getContext('2d'); 7 | this.ctx.canvas.width = this.playground.width; 8 | this.ctx.canvas.height = this.playground.height; 9 | this.playground.$playground.append(this.$canvas); 10 | } 11 | start() { 12 | this.$canvas.focus(); 13 | } 14 | 15 | resize() { 16 | this.ctx.canvas.width = this.playground.width; 17 | this.ctx.canvas.height = this.playground.height; 18 | this.ctx.fillStyle = "rgba(0, 0, 0, 1)"; 19 | this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); 20 | } 21 | 22 | update() { 23 | this.render(); 24 | } 25 | render() { 26 | this.ctx.fillStyle = "rgba(0, 0, 0, 0.2)"; 27 | this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /static/admin/img/gis/move_vertex_on.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/admin/img/icon-calendar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static/admin/img/gis/move_vertex_off.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/admin/img/calendar-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /static/admin/img/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Code Charm Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /static/admin/img/sorting-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /static/admin/js/vendor/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors, https://js.foundation/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /static/admin/js/vendor/xregexp/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2007-2017 Steven Levithan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /static/admin/css/login.css: -------------------------------------------------------------------------------- 1 | /* LOGIN FORM */ 2 | 3 | .login { 4 | background: var(--darkened-bg); 5 | height: auto; 6 | } 7 | 8 | .login #header { 9 | height: auto; 10 | padding: 15px 16px; 11 | justify-content: center; 12 | } 13 | 14 | .login #header h1 { 15 | font-size: 18px; 16 | } 17 | 18 | .login #header h1 a { 19 | color: var(--header-link-color); 20 | } 21 | 22 | .login #content { 23 | padding: 20px 20px 0; 24 | } 25 | 26 | .login #container { 27 | background: var(--body-bg); 28 | border: 1px solid var(--hairline-color); 29 | border-radius: 4px; 30 | overflow: hidden; 31 | width: 28em; 32 | min-width: 300px; 33 | margin: 100px auto; 34 | height: auto; 35 | } 36 | 37 | .login .form-row { 38 | padding: 4px 0; 39 | } 40 | 41 | .login .form-row label { 42 | display: block; 43 | line-height: 2em; 44 | } 45 | 46 | .login .form-row #id_username, .login .form-row #id_password { 47 | padding: 8px; 48 | width: 100%; 49 | box-sizing: border-box; 50 | } 51 | 52 | .login .submit-row { 53 | padding: 1em 0 0 0; 54 | margin: 0; 55 | text-align: center; 56 | } 57 | 58 | .login .password-reset-link { 59 | text-align: center; 60 | } 61 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/cs.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/cs",[],function(){function e(e,n){switch(e){case 2:return n?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(n){var t=n.input.length-n.maximum;return 1==t?"Prosím, zadejte o jeden znak méně.":t<=4?"Prosím, zadejte o "+e(t,!0)+" znaky méně.":"Prosím, zadejte o "+t+" znaků méně."},inputTooShort:function(n){var t=n.minimum-n.input.length;return 1==t?"Prosím, zadejte ještě jeden znak.":t<=4?"Prosím, zadejte ještě další "+e(t,!0)+" znaky.":"Prosím, zadejte ještě dalších "+t+" znaků."},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(n){var t=n.maximum;return 1==t?"Můžete zvolit jen jednu položku.":t<=4?"Můžete zvolit maximálně "+e(t,!1)+" položky.":"Můžete zvolit maximálně "+t+" položek."},noResults:function(){return"Nenalezeny žádné položky."},searching:function(){return"Vyhledávání…"},removeAllItems:function(){return"Odstraňte všechny položky"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /static/admin/css/vendor/select2/LICENSE-SELECT2.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /static/admin/js/vendor/select2/i18n/sk.js: -------------------------------------------------------------------------------- 1 | /*! Select2 4.0.13 | https://github.com/select2/select2/blob/master/LICENSE.md */ 2 | 3 | !function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{errorLoading:function(){return"Výsledky sa nepodarilo načítať."},inputTooLong:function(n){var t=n.input.length-n.maximum;return 1==t?"Prosím, zadajte o jeden znak menej":t>=2&&t<=4?"Prosím, zadajte o "+e[t](!0)+" znaky menej":"Prosím, zadajte o "+t+" znakov menej"},inputTooShort:function(n){var t=n.minimum-n.input.length;return 1==t?"Prosím, zadajte ešte jeden znak":t<=4?"Prosím, zadajte ešte ďalšie "+e[t](!0)+" znaky":"Prosím, zadajte ešte ďalších "+t+" znakov"},loadingMore:function(){return"Načítanie ďalších výsledkov…"},maximumSelected:function(n){return 1==n.maximum?"Môžete zvoliť len jednu položku":n.maximum>=2&&n.maximum<=4?"Môžete zvoliť najviac "+e[n.maximum](!1)+" položky":"Môžete zvoliť najviac "+n.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"},removeAllItems:function(){return"Odstráňte všetky položky"}}}),e.define,e.require}(); -------------------------------------------------------------------------------- /game/views/settings/register.py: -------------------------------------------------------------------------------- 1 | from django.http import JsonResponse 2 | from django.contrib.auth import login 3 | from django.contrib.auth.models import User 4 | from game.models.player.player import Player 5 | 6 | def register(request): 7 | data = request.GET 8 | username = data.get("username", "").strip() 9 | password = data.get("password", "").strip() 10 | password_confirm = data.get("password_confirm", "").strip() 11 | if not username or not password: 12 | return JsonResponse({ 13 | 'result': "用户名和密码不能为空", 14 | }) 15 | if password != password_confirm: 16 | return JsonResponse({ 17 | 'result': "两个密码不一致", 18 | }) 19 | if User.objects.filter(username=username).exists(): 20 | return JsonResponse({ 21 | 'result': "用户名已存在", 22 | }) 23 | user = User(username=username) 24 | user.set_password(password) 25 | user.save() 26 | Player.objects.create(user=user, photo="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fitem%2F201801%2F26%2F20180126111132_ecshg.thumb.1000_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1640705534&t=5b5cf598d") 27 | login(request, user) 28 | return JsonResponse({ 29 | 'result': "success", 30 | }) -------------------------------------------------------------------------------- /static/js/src/playground/particle/zbase.js: -------------------------------------------------------------------------------- 1 | class Particle extends AcGameObject { 2 | constructor(playground, x, y, radius, vx, vy, color, speed, move_length) { 3 | super(); 4 | this.playground = playground; 5 | this.ctx = this.playground.game_map.ctx; 6 | this.x = x; 7 | this.y = y; 8 | this.radius = radius; 9 | this.vx = vx; 10 | this.vy = vy; 11 | this.color = color; 12 | this.speed = speed; 13 | this.move_length = move_length; 14 | this.friction = 0.9; 15 | this.eps = 0.01; 16 | } 17 | 18 | start() { 19 | } 20 | 21 | update() { 22 | if (this.move_length < this.eps || this.speed < this.eps) { 23 | this.destroy(); 24 | return false; 25 | } 26 | 27 | let moved = Math.min(this.move_length, this.speed * this.timedelta / 1000); 28 | this.x += this.vx * moved; 29 | this.y += this.vy * moved; 30 | this.speed *= this.friction; 31 | this.move_length -= moved; 32 | this.render(); 33 | } 34 | 35 | render() { 36 | let scale = this.playground.scale; 37 | 38 | this.ctx.beginPath(); 39 | this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false); 40 | this.ctx.fillStyle = this.color; 41 | this.ctx.fill(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /game/static/js/src/playground/particle/zbase.js: -------------------------------------------------------------------------------- 1 | class Particle extends AcGameObject { 2 | constructor(playground, x, y, radius, vx, vy, color, speed, move_length) { 3 | super(); 4 | this.playground = playground; 5 | this.ctx = this.playground.game_map.ctx; 6 | this.x = x; 7 | this.y = y; 8 | this.radius = radius; 9 | this.vx = vx; 10 | this.vy = vy; 11 | this.color = color; 12 | this.speed = speed; 13 | this.move_length = move_length; 14 | this.friction = 0.9; 15 | this.eps = 0.01; 16 | } 17 | 18 | start() { 19 | } 20 | 21 | update() { 22 | if (this.move_length < this.eps || this.speed < this.eps) { 23 | this.destroy(); 24 | return false; 25 | } 26 | 27 | let moved = Math.min(this.move_length, this.speed * this.timedelta / 1000); 28 | this.x += this.vx * moved; 29 | this.y += this.vy * moved; 30 | this.speed *= this.friction; 31 | this.move_length -= moved; 32 | this.render(); 33 | } 34 | 35 | render() { 36 | let scale = this.playground.scale; 37 | 38 | this.ctx.beginPath(); 39 | this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false); 40 | this.ctx.fillStyle = this.color; 41 | this.ctx.fill(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /static/admin/js/autocomplete.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | { 3 | const $ = django.jQuery; 4 | const init = function($element, options) { 5 | const settings = $.extend({ 6 | ajax: { 7 | data: function(params) { 8 | return { 9 | term: params.term, 10 | page: params.page, 11 | app_label: $element.data('app-label'), 12 | model_name: $element.data('model-name'), 13 | field_name: $element.data('field-name') 14 | }; 15 | } 16 | } 17 | }, options); 18 | $element.select2(settings); 19 | }; 20 | 21 | $.fn.djangoAdminSelect2 = function(options) { 22 | const settings = $.extend({}, options); 23 | $.each(this, function(i, element) { 24 | const $element = $(element); 25 | init($element, settings); 26 | }); 27 | return this; 28 | }; 29 | 30 | $(function() { 31 | // Initialize all autocomplete widgets except the one in the template 32 | // form used when a new formset is added. 33 | $('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2(); 34 | }); 35 | 36 | $(document).on('formset:added', (function() { 37 | return function(event, $newFormset) { 38 | return $newFormset.find('.admin-autocomplete').djangoAdminSelect2(); 39 | }; 40 | })(this)); 41 | } 42 | -------------------------------------------------------------------------------- /static/admin/js/nav_sidebar.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | { 3 | const toggleNavSidebar = document.getElementById('toggle-nav-sidebar'); 4 | if (toggleNavSidebar !== null) { 5 | const navLinks = document.querySelectorAll('#nav-sidebar a'); 6 | function disableNavLinkTabbing() { 7 | for (const navLink of navLinks) { 8 | navLink.tabIndex = -1; 9 | } 10 | } 11 | function enableNavLinkTabbing() { 12 | for (const navLink of navLinks) { 13 | navLink.tabIndex = 0; 14 | } 15 | } 16 | 17 | const main = document.getElementById('main'); 18 | let navSidebarIsOpen = localStorage.getItem('django.admin.navSidebarIsOpen'); 19 | if (navSidebarIsOpen === null) { 20 | navSidebarIsOpen = 'true'; 21 | } 22 | if (navSidebarIsOpen === 'false') { 23 | disableNavLinkTabbing(); 24 | } 25 | main.classList.toggle('shifted', navSidebarIsOpen === 'true'); 26 | 27 | toggleNavSidebar.addEventListener('click', function() { 28 | if (navSidebarIsOpen === 'true') { 29 | navSidebarIsOpen = 'false'; 30 | disableNavLinkTabbing(); 31 | } else { 32 | navSidebarIsOpen = 'true'; 33 | enableNavLinkTabbing(); 34 | } 35 | localStorage.setItem('django.admin.navSidebarIsOpen', navSidebarIsOpen); 36 | main.classList.toggle('shifted'); 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /static/admin/js/prepopulate.js: -------------------------------------------------------------------------------- 1 | /*global URLify*/ 2 | 'use strict'; 3 | { 4 | const $ = django.jQuery; 5 | $.fn.prepopulate = function(dependencies, maxLength, allowUnicode) { 6 | /* 7 | Depends on urlify.js 8 | Populates a selected field with the values of the dependent fields, 9 | URLifies and shortens the string. 10 | dependencies - array of dependent fields ids 11 | maxLength - maximum length of the URLify'd string 12 | allowUnicode - Unicode support of the URLify'd string 13 | */ 14 | return this.each(function() { 15 | const prepopulatedField = $(this); 16 | 17 | const populate = function() { 18 | // Bail if the field's value has been changed by the user 19 | if (prepopulatedField.data('_changed')) { 20 | return; 21 | } 22 | 23 | const values = []; 24 | $.each(dependencies, function(i, field) { 25 | field = $(field); 26 | if (field.val().length > 0) { 27 | values.push(field.val()); 28 | } 29 | }); 30 | prepopulatedField.val(URLify(values.join(' '), maxLength, allowUnicode)); 31 | }; 32 | 33 | prepopulatedField.data('_changed', false); 34 | prepopulatedField.on('change', function() { 35 | prepopulatedField.data('_changed', true); 36 | }); 37 | 38 | if (!prepopulatedField.val()) { 39 | $(dependencies.join(',')).on('keyup change focus', populate); 40 | } 41 | }); 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /game/views/settings/acwing/web/receive_code.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import redirect 2 | from django.core.cache import cache 3 | import requests 4 | from django.contrib.auth.models import User 5 | from django.contrib.auth import login 6 | from game.models.player.player import Player 7 | from random import randint 8 | 9 | def receive_code(request): 10 | data = request.GET 11 | code = data.get('code') 12 | state = data.get('state') 13 | 14 | if not cache.has_key(state): 15 | return redirect("index") 16 | 17 | apply_access_token_url = "https://www.acwing.com/third_party/api/oauth2/access_token/" 18 | params = { 19 | 'appid': "652", 20 | 'secret': "76976c2a16c641dab5273c8f84fe15a0", 21 | 'code': code 22 | } 23 | 24 | access_token_res = requests.get(apply_access_token_url, params).json() 25 | 26 | access_token = access_token_res['access_token'] 27 | openid = access_token_res['openid'] 28 | 29 | players = Player.objects.filter(openid=openid) 30 | if players.exists(): 31 | login(request, players[0].user) 32 | return redirect("index") 33 | 34 | get_userinfo_url = "https://www.acwing.com/third_party/api/meta/identity/getinfo/" 35 | params = { 36 | "access_token": access_token, 37 | "openid": openid 38 | } 39 | 40 | userinfo_res = requests.get(get_userinfo_url, params=params).json() 41 | username = userinfo_res['username'] 42 | photo = userinfo_res['photo'] 43 | 44 | while User.objects.filter(username=username).exists(): 45 | username += str(randint(0, 9)) 46 | 47 | user = User.objects.create(username=username) 48 | player = Player.objects.create(user=user, photo=photo, openid=openid) 49 | 50 | login(request, user) 51 | 52 | return redirect("index") -------------------------------------------------------------------------------- /static/js/src/playground/ac_game_object/zbase.js: -------------------------------------------------------------------------------- 1 | let AC_GAME_OBJECTS = []; 2 | 3 | class AcGameObject { 4 | constructor() { 5 | AC_GAME_OBJECTS.push(this); 6 | 7 | this.has_called_start = false; // 是否执行过start函数 8 | this.timedelta = 0; // 当前帧距离上一帧的时间间隔 9 | this.uuid = this.create_uuid(); 10 | } 11 | 12 | create_uuid() { 13 | let res = ""; 14 | for (let i = 0; i < 8; i++) { 15 | let x = parseInt(Math.floor(Math.random() * 10)); // 返回[0,1)之间的数 16 | res += x; 17 | } 18 | return res; 19 | } 20 | 21 | start() { // 只会在第一帧执行一次 22 | 23 | } 24 | 25 | update() { // 每一帧均会执行一次 26 | 27 | } 28 | 29 | late_update() { // 在每一帧的最后执行一次 30 | 31 | } 32 | 33 | on_destroy() { // 在被销毁前执行一次 34 | 35 | } 36 | 37 | destroy() { // 删除该物体 38 | this.on_destroy(); 39 | for (let i = 0; i < AC_GAME_OBJECTS.length; i++) { 40 | if (AC_GAME_OBJECTS[i] === this) { 41 | AC_GAME_OBJECTS.splice(i, 1); 42 | break; 43 | } 44 | } 45 | } 46 | } 47 | 48 | let last_timestamp; 49 | let AC_GAME_ANIMATION = function(timestamp) { 50 | for (let i = 0; i < AC_GAME_OBJECTS.length; i++) { 51 | let obj = AC_GAME_OBJECTS[i]; 52 | if (!obj.has_called_start) { 53 | obj.start(); 54 | obj.has_called_start = true; 55 | } 56 | else { 57 | obj.timedelta = timestamp - last_timestamp; 58 | obj.update(); 59 | } 60 | } 61 | 62 | for (let i = 0; i < AC_GAME_OBJECTS.length; i++) { 63 | let obj = AC_GAME_OBJECTS[i]; 64 | obj.late_update(); 65 | } 66 | 67 | last_timestamp = timestamp; 68 | requestAnimationFrame(AC_GAME_ANIMATION); 69 | } 70 | 71 | requestAnimationFrame(AC_GAME_ANIMATION); 72 | -------------------------------------------------------------------------------- /game/static/js/src/playground/ac_game_object/zbase.js: -------------------------------------------------------------------------------- 1 | let AC_GAME_OBJECTS = []; 2 | 3 | class AcGameObject { 4 | constructor() { 5 | AC_GAME_OBJECTS.push(this); 6 | 7 | this.has_called_start = false; // 是否执行过start函数 8 | this.timedelta = 0; // 当前帧距离上一帧的时间间隔 9 | this.uuid = this.create_uuid(); 10 | } 11 | 12 | create_uuid() { 13 | let res = ""; 14 | for (let i = 0; i < 8; i++) { 15 | let x = parseInt(Math.floor(Math.random() * 10)); // 返回[0,1)之间的数 16 | res += x; 17 | } 18 | return res; 19 | } 20 | 21 | start() { // 只会在第一帧执行一次 22 | 23 | } 24 | 25 | update() { // 每一帧均会执行一次 26 | 27 | } 28 | 29 | late_update() { // 在每一帧的最后执行一次 30 | 31 | } 32 | 33 | on_destroy() { // 在被销毁前执行一次 34 | 35 | } 36 | 37 | destroy() { // 删除该物体 38 | this.on_destroy(); 39 | for (let i = 0; i < AC_GAME_OBJECTS.length; i++) { 40 | if (AC_GAME_OBJECTS[i] === this) { 41 | AC_GAME_OBJECTS.splice(i, 1); 42 | break; 43 | } 44 | } 45 | } 46 | } 47 | 48 | let last_timestamp; 49 | let AC_GAME_ANIMATION = function(timestamp) { 50 | for (let i = 0; i < AC_GAME_OBJECTS.length; i++) { 51 | let obj = AC_GAME_OBJECTS[i]; 52 | if (!obj.has_called_start) { 53 | obj.start(); 54 | obj.has_called_start = true; 55 | } 56 | else { 57 | obj.timedelta = timestamp - last_timestamp; 58 | obj.update(); 59 | } 60 | } 61 | 62 | for (let i = 0; i < AC_GAME_OBJECTS.length; i++) { 63 | let obj = AC_GAME_OBJECTS[i]; 64 | obj.late_update(); 65 | } 66 | 67 | last_timestamp = timestamp; 68 | requestAnimationFrame(AC_GAME_ANIMATION); 69 | } 70 | 71 | requestAnimationFrame(AC_GAME_ANIMATION); 72 | -------------------------------------------------------------------------------- /static/js/src/playground/score_board/zbase.js: -------------------------------------------------------------------------------- 1 | class ScoreBoard extends AcGameObject { 2 | constructor(playground) { 3 | super(); 4 | this.playground = playground; 5 | this.ctx = this.playground.game_map.ctx; 6 | 7 | this.state = null; // win: 胜利,lose: 失败 8 | 9 | this.win_img = new Image(); 10 | this.win_img.src = "https://cdn.acwing.com/media/article/image/2021/12/17/1_8f58341a5e-win.png"; 11 | 12 | this.lose_img = new Image(); 13 | this.lose_img.src = "https://cdn.acwing.com/media/article/image/2021/12/17/1_9254b5f95e-lose.png"; 14 | 15 | this.start(); 16 | } 17 | 18 | start() { 19 | } 20 | add_listening_events() { 21 | let outer = this; 22 | let $canvas = this.playground.game_map.$canvas; 23 | 24 | $canvas.on('click', function() { 25 | outer.playground.hide(); 26 | outer.playground.root.menu.show(); 27 | }); 28 | } 29 | win() { 30 | this.state = "win"; 31 | 32 | let outer = this; 33 | setTimeout(function() { 34 | outer.add_listening_events(); 35 | }, 1000); 36 | } 37 | lose() { 38 | this.state = "lose"; 39 | let outer = this; 40 | setTimeout(function() { 41 | outer.add_listening_events(); 42 | }, 1000); 43 | } 44 | late_update() { 45 | this.render(); 46 | } 47 | render() { 48 | let len = this.playground.height / 2; 49 | if (this.state === "win") { 50 | this.ctx.drawImage(this.win_img, this.playground.width / 2 - len / 2, this.playground.height / 2 - len / 2, len, len); 51 | } 52 | else if (this.state === "lose") { 53 | this.ctx.drawImage(this.lose_img, this.playground.width / 2 - len / 2, this.playground.height / 2 - len / 2, len, len); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /game/static/js/src/playground/score_board/zbase.js: -------------------------------------------------------------------------------- 1 | class ScoreBoard extends AcGameObject { 2 | constructor(playground) { 3 | super(); 4 | this.playground = playground; 5 | this.ctx = this.playground.game_map.ctx; 6 | 7 | this.state = null; // win: 胜利,lose: 失败 8 | 9 | this.win_img = new Image(); 10 | this.win_img.src = "https://cdn.acwing.com/media/article/image/2021/12/17/1_8f58341a5e-win.png"; 11 | 12 | this.lose_img = new Image(); 13 | this.lose_img.src = "https://cdn.acwing.com/media/article/image/2021/12/17/1_9254b5f95e-lose.png"; 14 | 15 | this.start(); 16 | } 17 | 18 | start() { 19 | } 20 | add_listening_events() { 21 | let outer = this; 22 | let $canvas = this.playground.game_map.$canvas; 23 | 24 | $canvas.on('click', function() { 25 | outer.playground.hide(); 26 | outer.playground.root.menu.show(); 27 | }); 28 | } 29 | win() { 30 | this.state = "win"; 31 | 32 | let outer = this; 33 | setTimeout(function() { 34 | outer.add_listening_events(); 35 | }, 1000); 36 | } 37 | lose() { 38 | this.state = "lose"; 39 | let outer = this; 40 | setTimeout(function() { 41 | outer.add_listening_events(); 42 | }, 1000); 43 | } 44 | late_update() { 45 | this.render(); 46 | } 47 | render() { 48 | let len = this.playground.height / 2; 49 | if (this.state === "win") { 50 | this.ctx.drawImage(this.win_img, this.playground.width / 2 - len / 2, this.playground.height / 2 - len / 2, len, len); 51 | } 52 | else if (this.state === "lose") { 53 | this.ctx.drawImage(this.lose_img, this.playground.width / 2 - len / 2, this.playground.height / 2 - len / 2, len, len); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /static/js/src/menu/zbase.js: -------------------------------------------------------------------------------- 1 | class AcGameMenu { 2 | constructor(root) { 3 | this.root = root; 4 | this.$menu = $(` 5 |
6 |
7 |
8 | 单人模式 9 |
10 |
11 |
12 | 多人模式 13 |
14 |
15 |
16 | 退出 17 |
18 |
19 |
20 | `); 21 | this.$menu.hide(); 22 | this.root.$ac_game.append(this.$menu); 23 | this.$single_mode = this.$menu.find('.ac-game-menu-field-item-single-mode'); 24 | this.$multi_mode = this.$menu.find('.ac-game-menu-field-item-multi-mode'); 25 | this.$setting = this.$menu.find('.ac-game-menu-field-item-setting'); 26 | 27 | this.start(); 28 | } 29 | start() { 30 | this.add_listening_events(); 31 | } 32 | add_listening_events() { // 监听事件 33 | let outer = this; 34 | this.$single_mode.click(function() { 35 | outer.hide(); 36 | outer.root.playground.show("single mode"); 37 | }); 38 | this.$multi_mode.click(function() { 39 | outer.hide(); 40 | outer.root.playground.show("multi mode"); 41 | }); 42 | this.$setting.click(function() { 43 | outer.root.settings.logout_on_remote(); 44 | }); 45 | } 46 | show() { // 显示menu界面 47 | this.$menu.show(); 48 | } 49 | hide() { // 关闭menu界面 50 | this.$menu.hide(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /game/static/js/src/menu/zbase.js: -------------------------------------------------------------------------------- 1 | class AcGameMenu { 2 | constructor(root) { 3 | this.root = root; 4 | this.$menu = $(` 5 |
6 |
7 |
8 | 单人模式 9 |
10 |
11 |
12 | 多人模式 13 |
14 |
15 |
16 | 退出 17 |
18 |
19 |
20 | `); 21 | this.$menu.hide(); 22 | this.root.$ac_game.append(this.$menu); 23 | this.$single_mode = this.$menu.find('.ac-game-menu-field-item-single-mode'); 24 | this.$multi_mode = this.$menu.find('.ac-game-menu-field-item-multi-mode'); 25 | this.$setting = this.$menu.find('.ac-game-menu-field-item-setting'); 26 | 27 | this.start(); 28 | } 29 | start() { 30 | this.add_listening_events(); 31 | } 32 | add_listening_events() { // 监听事件 33 | let outer = this; 34 | this.$single_mode.click(function() { 35 | outer.hide(); 36 | outer.root.playground.show("single mode"); 37 | }); 38 | this.$multi_mode.click(function() { 39 | outer.hide(); 40 | outer.root.playground.show("multi mode"); 41 | }); 42 | this.$setting.click(function() { 43 | outer.root.settings.logout_on_remote(); 44 | }); 45 | } 46 | show() { // 显示menu界面 47 | this.$menu.show(); 48 | } 49 | hide() { // 关闭menu界面 50 | this.$menu.hide(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /static/admin/js/collapse.js: -------------------------------------------------------------------------------- 1 | /*global gettext*/ 2 | 'use strict'; 3 | { 4 | window.addEventListener('load', function() { 5 | // Add anchor tag for Show/Hide link 6 | const fieldsets = document.querySelectorAll('fieldset.collapse'); 7 | for (const [i, elem] of fieldsets.entries()) { 8 | // Don't hide if fields in this fieldset have errors 9 | if (elem.querySelectorAll('div.errors, ul.errorlist').length === 0) { 10 | elem.classList.add('collapsed'); 11 | const h2 = elem.querySelector('h2'); 12 | const link = document.createElement('a'); 13 | link.id = 'fieldsetcollapser' + i; 14 | link.className = 'collapse-toggle'; 15 | link.href = '#'; 16 | link.textContent = gettext('Show'); 17 | h2.appendChild(document.createTextNode(' (')); 18 | h2.appendChild(link); 19 | h2.appendChild(document.createTextNode(')')); 20 | } 21 | } 22 | // Add toggle to hide/show anchor tag 23 | const toggleFunc = function(ev) { 24 | if (ev.target.matches('.collapse-toggle')) { 25 | ev.preventDefault(); 26 | ev.stopPropagation(); 27 | const fieldset = ev.target.closest('fieldset'); 28 | if (fieldset.classList.contains('collapsed')) { 29 | // Show 30 | ev.target.textContent = gettext('Hide'); 31 | fieldset.classList.remove('collapsed'); 32 | } else { 33 | // Hide 34 | ev.target.textContent = gettext('Show'); 35 | fieldset.classList.add('collapsed'); 36 | } 37 | } 38 | }; 39 | document.querySelectorAll('fieldset.module').forEach(function(el) { 40 | el.addEventListener('click', toggleFunc); 41 | }); 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /static/admin/css/responsive_rtl.css: -------------------------------------------------------------------------------- 1 | /* TABLETS */ 2 | 3 | @media (max-width: 1024px) { 4 | [dir="rtl"] .colMS { 5 | margin-right: 0; 6 | } 7 | 8 | [dir="rtl"] #user-tools { 9 | text-align: right; 10 | } 11 | 12 | [dir="rtl"] #changelist .actions label { 13 | padding-left: 10px; 14 | padding-right: 0; 15 | } 16 | 17 | [dir="rtl"] #changelist .actions select { 18 | margin-left: 0; 19 | margin-right: 15px; 20 | } 21 | 22 | [dir="rtl"] .change-list .filtered .results, 23 | [dir="rtl"] .change-list .filtered .paginator, 24 | [dir="rtl"] .filtered #toolbar, 25 | [dir="rtl"] .filtered div.xfull, 26 | [dir="rtl"] .filtered .actions, 27 | [dir="rtl"] #changelist-filter { 28 | margin-left: 0; 29 | } 30 | 31 | [dir="rtl"] .inline-group ul.tools a.add, 32 | [dir="rtl"] .inline-group div.add-row a, 33 | [dir="rtl"] .inline-group .tabular tr.add-row td a { 34 | padding: 8px 26px 8px 10px; 35 | background-position: calc(100% - 8px) 9px; 36 | } 37 | 38 | [dir="rtl"] .related-widget-wrapper-link + .selector { 39 | margin-right: 0; 40 | margin-left: 15px; 41 | } 42 | 43 | [dir="rtl"] .selector .selector-filter label { 44 | margin-right: 0; 45 | margin-left: 8px; 46 | } 47 | 48 | [dir="rtl"] .object-tools li { 49 | float: right; 50 | } 51 | 52 | [dir="rtl"] .object-tools li + li { 53 | margin-left: 0; 54 | margin-right: 15px; 55 | } 56 | 57 | [dir="rtl"] .dashboard .module table td a { 58 | padding-left: 0; 59 | padding-right: 16px; 60 | } 61 | } 62 | 63 | /* MOBILE */ 64 | 65 | @media (max-width: 767px) { 66 | [dir="rtl"] .aligned .related-lookup, 67 | [dir="rtl"] .aligned .datetimeshortcuts { 68 | margin-left: 0; 69 | margin-right: 15px; 70 | } 71 | 72 | [dir="rtl"] .aligned ul { 73 | margin-right: 0; 74 | } 75 | 76 | [dir="rtl"] #changelist-filter { 77 | margin-left: 0; 78 | margin-right: 0; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /game/views/settings/acwing/acapp/receive_code.py: -------------------------------------------------------------------------------- 1 | from django.http import JsonResponse 2 | from django.core.cache import cache 3 | import requests 4 | from django.contrib.auth.models import User 5 | from game.models.player.player import Player 6 | from random import randint 7 | 8 | def receive_code(request): 9 | data = request.GET 10 | 11 | if "errcode" in data: # 用户拒绝 12 | return JsonResponse({ 13 | 'result': "apply failed", 14 | 'errcode': data['errcode'], 15 | 'errmsg': data['errmsg'], 16 | }) 17 | 18 | code = data.get('code') 19 | state = data.get('state') 20 | 21 | if not cache.has_key(state): 22 | return JsonResponse({ 23 | 'result': "state not exist", 24 | }) 25 | 26 | apply_access_token_url = "https://www.acwing.com/third_party/api/oauth2/access_token/" 27 | params = { 28 | 'appid': "652", 29 | 'secret': "76976c2a16c641dab5273c8f84fe15a0", 30 | 'code': code 31 | } 32 | 33 | access_token_res = requests.get(apply_access_token_url, params).json() 34 | 35 | access_token = access_token_res['access_token'] 36 | openid = access_token_res['openid'] 37 | 38 | players = Player.objects.filter(openid=openid) 39 | if players.exists(): 40 | player = players[0] 41 | return JsonResponse({ 42 | 'result': "success", 43 | 'username': player.user.username, 44 | 'photo': player.photo, 45 | }) 46 | 47 | get_userinfo_url = "https://www.acwing.com/third_party/api/meta/identity/getinfo/" 48 | params = { 49 | "access_token": access_token, 50 | "openid": openid 51 | } 52 | 53 | userinfo_res = requests.get(get_userinfo_url, params=params).json() 54 | username = userinfo_res['username'] 55 | photo = userinfo_res['photo'] 56 | 57 | while User.objects.filter(username=username).exists(): 58 | username += str(randint(0, 9)) 59 | 60 | user = User.objects.create(username=username) 61 | player = Player.objects.create(user=user, photo=photo, openid=openid) 62 | 63 | return JsonResponse({ 64 | 'result': "success", 65 | 'username': player.user.username, 66 | 'photo': player.photo, 67 | }) -------------------------------------------------------------------------------- /static/js/src/playground/chat_field/zbase.js: -------------------------------------------------------------------------------- 1 | class ChatField { 2 | constructor(playground) { 3 | this.playground = playground; 4 | 5 | this.$history = $(`
历史记录
`); 6 | this.$input = $(``); 7 | 8 | this.$history.hide(); 9 | this.$input.hide(); 10 | 11 | this.func_id = null; 12 | 13 | this.playground.$playground.append(this.$history); 14 | this.playground.$playground.append(this.$input); 15 | 16 | this.start(); 17 | } 18 | start() { 19 | this.add_listening_events(); 20 | } 21 | add_listening_events() { 22 | let outer = this; 23 | this.$input.keydown(function(e) { 24 | if (e.which === 27) { 25 | outer.hide_input(); 26 | return false; 27 | } 28 | else if (e.which === 13) { 29 | let username = outer.playground.root.settings.username; 30 | let text = outer.$input.val(); 31 | if (text) { 32 | outer.$input.val(""); 33 | outer.add_message(username, text); 34 | outer.playground.mps.send_message(username, text); 35 | } 36 | return false; 37 | } 38 | }); 39 | } 40 | render_message(message) { 41 | return $(`
${message}
`); 42 | } 43 | add_message(username, text) { 44 | this.show_history(); 45 | let message = `[${username}]${text}`; 46 | this.$history.append(this.render_message(message)); 47 | this.$history.scrollTop(this.$history[0].scrollHeight); 48 | } 49 | show_history() { 50 | let outer = this; 51 | this.$history.fadeIn(); 52 | 53 | if (this.func_id) clearTimeout(this.func_id); 54 | 55 | this.func_id = setTimeout(function() { 56 | outer.$history.fadeOut(); 57 | outer.func_id = null; 58 | }, 5000); 59 | } 60 | show_input() { 61 | this.show_history(); 62 | this.$input.show(); 63 | this.$input.focus(); 64 | } 65 | hide_input() { 66 | this.$input.hide(); 67 | this.playground.game_map.$canvas.focus(); 68 | } 69 | } -------------------------------------------------------------------------------- /game/static/js/src/playground/chat_field/zbase.js: -------------------------------------------------------------------------------- 1 | class ChatField { 2 | constructor(playground) { 3 | this.playground = playground; 4 | 5 | this.$history = $(`
历史记录
`); 6 | this.$input = $(``); 7 | 8 | this.$history.hide(); 9 | this.$input.hide(); 10 | 11 | this.func_id = null; 12 | 13 | this.playground.$playground.append(this.$history); 14 | this.playground.$playground.append(this.$input); 15 | 16 | this.start(); 17 | } 18 | start() { 19 | this.add_listening_events(); 20 | } 21 | add_listening_events() { 22 | let outer = this; 23 | this.$input.keydown(function(e) { 24 | if (e.which === 27) { 25 | outer.hide_input(); 26 | return false; 27 | } 28 | else if (e.which === 13) { 29 | let username = outer.playground.root.settings.username; 30 | let text = outer.$input.val(); 31 | if (text) { 32 | outer.$input.val(""); 33 | outer.add_message(username, text); 34 | outer.playground.mps.send_message(username, text); 35 | } 36 | return false; 37 | } 38 | }); 39 | } 40 | render_message(message) { 41 | return $(`
${message}
`); 42 | } 43 | add_message(username, text) { 44 | this.show_history(); 45 | let message = `[${username}]${text}`; 46 | this.$history.append(this.render_message(message)); 47 | this.$history.scrollTop(this.$history[0].scrollHeight); 48 | } 49 | show_history() { 50 | let outer = this; 51 | this.$history.fadeIn(); 52 | 53 | if (this.func_id) clearTimeout(this.func_id); 54 | 55 | this.func_id = setTimeout(function() { 56 | outer.$history.fadeOut(); 57 | outer.func_id = null; 58 | }, 5000); 59 | } 60 | show_input() { 61 | this.show_history(); 62 | this.$input.show(); 63 | this.$input.focus(); 64 | } 65 | hide_input() { 66 | this.$input.hide(); 67 | this.playground.game_map.$canvas.focus(); 68 | } 69 | } -------------------------------------------------------------------------------- /static/admin/css/nav_sidebar.css: -------------------------------------------------------------------------------- 1 | .sticky { 2 | position: sticky; 3 | top: 0; 4 | max-height: 100vh; 5 | } 6 | 7 | .toggle-nav-sidebar { 8 | z-index: 20; 9 | left: 0; 10 | display: flex; 11 | align-items: center; 12 | justify-content: center; 13 | flex: 0 0 23px; 14 | width: 23px; 15 | border: 0; 16 | border-right: 1px solid var(--hairline-color); 17 | background-color: var(--body-bg); 18 | cursor: pointer; 19 | font-size: 20px; 20 | color: var(--link-fg); 21 | padding: 0; 22 | } 23 | 24 | [dir="rtl"] .toggle-nav-sidebar { 25 | border-left: 1px solid var(--hairline-color); 26 | border-right: 0; 27 | } 28 | 29 | .toggle-nav-sidebar:hover, 30 | .toggle-nav-sidebar:focus { 31 | background-color: var(--darkened-bg); 32 | } 33 | 34 | #nav-sidebar { 35 | z-index: 15; 36 | flex: 0 0 275px; 37 | left: -276px; 38 | margin-left: -276px; 39 | border-top: 1px solid transparent; 40 | border-right: 1px solid var(--hairline-color); 41 | background-color: var(--body-bg); 42 | overflow: auto; 43 | } 44 | 45 | [dir="rtl"] #nav-sidebar { 46 | border-left: 1px solid var(--hairline-color); 47 | border-right: 0; 48 | left: 0; 49 | margin-left: 0; 50 | right: -276px; 51 | margin-right: -276px; 52 | } 53 | 54 | .toggle-nav-sidebar::before { 55 | content: '\00BB'; 56 | } 57 | 58 | .main.shifted .toggle-nav-sidebar::before { 59 | content: '\00AB'; 60 | } 61 | 62 | .main.shifted > #nav-sidebar { 63 | left: 24px; 64 | margin-left: 0; 65 | } 66 | 67 | [dir="rtl"] .main.shifted > #nav-sidebar { 68 | left: 0; 69 | right: 24px; 70 | margin-right: 0; 71 | } 72 | 73 | #nav-sidebar .module th { 74 | width: 100%; 75 | overflow-wrap: anywhere; 76 | } 77 | 78 | #nav-sidebar .module th, 79 | #nav-sidebar .module caption { 80 | padding-left: 16px; 81 | } 82 | 83 | #nav-sidebar .module td { 84 | white-space: nowrap; 85 | } 86 | 87 | [dir="rtl"] #nav-sidebar .module th, 88 | [dir="rtl"] #nav-sidebar .module caption { 89 | padding-left: 8px; 90 | padding-right: 16px; 91 | } 92 | 93 | #nav-sidebar .current-app .section:link, 94 | #nav-sidebar .current-app .section:visited { 95 | color: var(--header-color); 96 | font-weight: bold; 97 | } 98 | 99 | #nav-sidebar .current-model { 100 | background: var(--selected-row); 101 | } 102 | 103 | .main > #nav-sidebar + .content { 104 | max-width: calc(100% - 23px); 105 | } 106 | 107 | .main.shifted > #nav-sidebar + .content { 108 | max-width: calc(100% - 299px); 109 | } 110 | 111 | @media (max-width: 767px) { 112 | #nav-sidebar, #toggle-nav-sidebar { 113 | display: none; 114 | } 115 | 116 | .main > #nav-sidebar + .content, 117 | .main.shifted > #nav-sidebar + .content { 118 | max-width: 100%; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /static/js/src/playground/skill/fireball/zbase.js: -------------------------------------------------------------------------------- 1 | class FireBall extends AcGameObject { 2 | constructor(playground, player, x, y, radius, vx, vy, color, speed, move_length, damage) { 3 | super(); 4 | this.playground = playground; 5 | this.player = player; 6 | this.ctx = this.playground.game_map.ctx; 7 | this.x = x; 8 | this.y = y; 9 | this.vx = vx; 10 | this.vy = vy; 11 | this.radius = radius; 12 | this.color = color; 13 | this.speed = speed; 14 | this.move_length = move_length; 15 | this.damage = damage; 16 | this.eps = 0.01; 17 | } 18 | 19 | start() { 20 | } 21 | 22 | update() { 23 | if (this.move_length < this.eps) { 24 | this.destroy(); 25 | return false; 26 | } 27 | this.update_move(); 28 | 29 | if (this.player.character !== "enemy") { 30 | this.update_attack(); 31 | } 32 | this.render(); 33 | } 34 | 35 | update_move() { 36 | let moved = Math.min(this.move_length, this.speed * this.timedelta / 1000); 37 | this.x += this.vx * moved; 38 | this.y += this.vy * moved; 39 | this.move_length -= moved; 40 | } 41 | 42 | update_attack() { 43 | for (let i = 0; i < this.playground.players.length; i ++ ) { 44 | let player = this.playground.players[i]; 45 | if (this.player !== player && this.is_collision(player)) { 46 | this.attack(player); 47 | break; 48 | } 49 | } 50 | } 51 | 52 | get_dist(x1, y1, x2, y2) { 53 | let dx = x1 - x2; 54 | let dy = y1 - y2; 55 | return Math.sqrt(dx * dx + dy * dy); 56 | } 57 | 58 | is_collision(player) { 59 | let distance = this.get_dist(this.x, this.y, player.x, player.y); 60 | if (distance < this.radius + player.radius) 61 | return true; 62 | return false; 63 | } 64 | 65 | attack(player) { 66 | let angle = Math.atan2(player.y - this.y, player.x - this.x); 67 | player.is_attacked(angle, this.damage); 68 | 69 | if (this.playground.mode === "multi mode") { 70 | this.playground.mps.send_attack(player.uuid, player.x, player.y, angle, this.damage, this.uuid); 71 | } 72 | 73 | this.destroy(); 74 | } 75 | 76 | render() { 77 | let scale = this.playground.scale; 78 | this.ctx.beginPath(); 79 | this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false); 80 | this.ctx.fillStyle = this.color; 81 | this.ctx.fill(); 82 | } 83 | on_destroy() { 84 | let fireballs = this.player.fireballs; 85 | for (let i = 0; i < fireballs.length; i++) { 86 | if (fireballs[i] === this) { 87 | fireballs.splice(i, 1); 88 | break; 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /game/static/js/src/playground/skill/fireball/zbase.js: -------------------------------------------------------------------------------- 1 | class FireBall extends AcGameObject { 2 | constructor(playground, player, x, y, radius, vx, vy, color, speed, move_length, damage) { 3 | super(); 4 | this.playground = playground; 5 | this.player = player; 6 | this.ctx = this.playground.game_map.ctx; 7 | this.x = x; 8 | this.y = y; 9 | this.vx = vx; 10 | this.vy = vy; 11 | this.radius = radius; 12 | this.color = color; 13 | this.speed = speed; 14 | this.move_length = move_length; 15 | this.damage = damage; 16 | this.eps = 0.01; 17 | } 18 | 19 | start() { 20 | } 21 | 22 | update() { 23 | if (this.move_length < this.eps) { 24 | this.destroy(); 25 | return false; 26 | } 27 | this.update_move(); 28 | 29 | if (this.player.character !== "enemy") { 30 | this.update_attack(); 31 | } 32 | this.render(); 33 | } 34 | 35 | update_move() { 36 | let moved = Math.min(this.move_length, this.speed * this.timedelta / 1000); 37 | this.x += this.vx * moved; 38 | this.y += this.vy * moved; 39 | this.move_length -= moved; 40 | } 41 | 42 | update_attack() { 43 | for (let i = 0; i < this.playground.players.length; i ++ ) { 44 | let player = this.playground.players[i]; 45 | if (this.player !== player && this.is_collision(player)) { 46 | this.attack(player); 47 | break; 48 | } 49 | } 50 | } 51 | 52 | get_dist(x1, y1, x2, y2) { 53 | let dx = x1 - x2; 54 | let dy = y1 - y2; 55 | return Math.sqrt(dx * dx + dy * dy); 56 | } 57 | 58 | is_collision(player) { 59 | let distance = this.get_dist(this.x, this.y, player.x, player.y); 60 | if (distance < this.radius + player.radius) 61 | return true; 62 | return false; 63 | } 64 | 65 | attack(player) { 66 | let angle = Math.atan2(player.y - this.y, player.x - this.x); 67 | player.is_attacked(angle, this.damage); 68 | 69 | if (this.playground.mode === "multi mode") { 70 | this.playground.mps.send_attack(player.uuid, player.x, player.y, angle, this.damage, this.uuid); 71 | } 72 | 73 | this.destroy(); 74 | } 75 | 76 | render() { 77 | let scale = this.playground.scale; 78 | this.ctx.beginPath(); 79 | this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false); 80 | this.ctx.fillStyle = this.color; 81 | this.ctx.fill(); 82 | } 83 | on_destroy() { 84 | let fireballs = this.player.fireballs; 85 | for (let i = 0; i < fireballs.length; i++) { 86 | if (fireballs[i] === this) { 87 | fireballs.splice(i, 1); 88 | break; 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebGame-Moba 2 | 3 | 这是基于AcWing的《Django 框架课》制作而成的。项目采用前后端分离的形式,前端纯js实现,并交给客户端进行渲染,而后端则采用Django框架和thrift去实现。最终目的是实现一个简化版的MOBA类游戏。 4 | 5 | 6 | 7 | ## 功能 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
界面功能模块所用技术
登录界面登录功能
注册功能
AcWing Web端一键授权登录Oauth2
AcWing App端一键授权登录Oauth2
菜单界面单人模式
联机对战多人同屏(websocket)
聊天功能(websocket)
计分功能(websocket、Redis)
匹配系统(thrift、Redis)
退出
游戏界面地图渲染JavaScript
人物控制JavaScript
交互模式JavaScript
57 | 58 | 59 | 60 | ## 展示界面 61 | 登录界面: 62 | 63 | ![登录界面](https://raw.githubusercontent.com/Fool-coder/PicGo/master/AcWing%20WebGame/%E7%99%BB%E5%BD%95%E7%95%8C%E9%9D%A2.png) 64 | 65 | 66 | 注册界面: 67 | 68 | ![注册界面](https://raw.githubusercontent.com/Fool-coder/PicGo/master/AcWing%20WebGame/%E6%B3%A8%E5%86%8C%E7%95%8C%E9%9D%A2.png) 69 | 70 | AcWing一键授权登录: 71 | 72 | ![AcWing一键登录功能](https://raw.githubusercontent.com/Fool-coder/PicGo/master/AcWing%20WebGame/AcWing%E4%B8%80%E9%94%AE%E6%8E%88%E6%9D%83%E7%99%BB%E5%BD%95.png) 73 | 74 | 菜单界面: 75 | 76 | ![菜单界面](https://raw.githubusercontent.com/Fool-coder/PicGo/master/AcWing%20WebGame/%E8%8F%9C%E5%8D%95%E7%95%8C%E9%9D%A2.png) 77 | 78 | 单人模式: 79 | 80 | ![单人模式](https://raw.githubusercontent.com/Fool-coder/PicGo/master/AcWing%20WebGame/%E5%8D%95%E4%BA%BA%E6%A8%A1%E5%BC%8F.png) 81 | 82 | 多人模式: 83 | 84 | ![多人模式](https://raw.githubusercontent.com/Fool-coder/PicGo/master/AcWing%20WebGame/%E5%A4%9A%E4%BA%BA%E6%A8%A1%E5%BC%8F.PNG) 85 | 86 | 87 | ## 启动项目 88 | 89 | ### 环境配置 90 | 91 | 启动`nginx`、`thrift`与`redis`服务: 92 | 93 | ```bash 94 | sudo /etc/init.d/nginx start 95 | ``` 96 | 97 | ```bash 98 | cd match_system/src/ 99 | chmod +x main.py 100 | ./main.py 101 | ``` 102 | 103 | ```bash 104 | sudo redis-server /etc/redis/redis.conf 105 | ``` 106 | ### 服务启动 107 | 108 | 启动`uwsgi`与`django_channels`服务: 109 | 110 | ```bash 111 | uwsgi --ini scripts/uwsgi.ini 112 | ``` 113 | 114 | ```bash 115 | daphne -b 0.0.0.0 -p 5015 acapp.asgi:application 116 | ``` 117 | 118 | 启动项目前请确保服务器的`43`、`80`与`启动项目`端口开放 119 | 120 | 启动项目: 121 | 122 | ```bash 123 | python3 manage.py runserver 0.0.0.0:端口号 124 | ``` 125 | -------------------------------------------------------------------------------- /static/admin/img/selector-icons.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /match_system/src/match_server/match_service/Match-remote: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Autogenerated by Thrift Compiler (0.16.0) 4 | # 5 | # DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING 6 | # 7 | # options string: py 8 | # 9 | 10 | import sys 11 | import pprint 12 | if sys.version_info[0] > 2: 13 | from urllib.parse import urlparse 14 | else: 15 | from urlparse import urlparse 16 | from thrift.transport import TTransport, TSocket, TSSLSocket, THttpClient 17 | from thrift.protocol.TBinaryProtocol import TBinaryProtocol 18 | 19 | from match_service import Match 20 | from match_service.ttypes import * 21 | 22 | if len(sys.argv) <= 1 or sys.argv[1] == '--help': 23 | print('') 24 | 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...]]') 25 | print('') 26 | print('Functions:') 27 | print(' i32 add_player(i32 score, string uuid, string username, string photo, string channel_name)') 28 | print('') 29 | sys.exit(0) 30 | 31 | pp = pprint.PrettyPrinter(indent=2) 32 | host = 'localhost' 33 | port = 9090 34 | uri = '' 35 | framed = False 36 | ssl = False 37 | validate = True 38 | ca_certs = None 39 | keyfile = None 40 | certfile = None 41 | http = False 42 | argi = 1 43 | 44 | if sys.argv[argi] == '-h': 45 | parts = sys.argv[argi + 1].split(':') 46 | host = parts[0] 47 | if len(parts) > 1: 48 | port = int(parts[1]) 49 | argi += 2 50 | 51 | if sys.argv[argi] == '-u': 52 | url = urlparse(sys.argv[argi + 1]) 53 | parts = url[1].split(':') 54 | host = parts[0] 55 | if len(parts) > 1: 56 | port = int(parts[1]) 57 | else: 58 | port = 80 59 | uri = url[2] 60 | if url[4]: 61 | uri += '?%s' % url[4] 62 | http = True 63 | argi += 2 64 | 65 | if sys.argv[argi] == '-f' or sys.argv[argi] == '-framed': 66 | framed = True 67 | argi += 1 68 | 69 | if sys.argv[argi] == '-s' or sys.argv[argi] == '-ssl': 70 | ssl = True 71 | argi += 1 72 | 73 | if sys.argv[argi] == '-novalidate': 74 | validate = False 75 | argi += 1 76 | 77 | if sys.argv[argi] == '-ca_certs': 78 | ca_certs = sys.argv[argi+1] 79 | argi += 2 80 | 81 | if sys.argv[argi] == '-keyfile': 82 | keyfile = sys.argv[argi+1] 83 | argi += 2 84 | 85 | if sys.argv[argi] == '-certfile': 86 | certfile = sys.argv[argi+1] 87 | argi += 2 88 | 89 | cmd = sys.argv[argi] 90 | args = sys.argv[argi + 1:] 91 | 92 | if http: 93 | transport = THttpClient.THttpClient(host, port, uri) 94 | else: 95 | if ssl: 96 | socket = TSSLSocket.TSSLSocket(host, port, validate=validate, ca_certs=ca_certs, keyfile=keyfile, certfile=certfile) 97 | else: 98 | socket = TSocket.TSocket(host, port) 99 | if framed: 100 | transport = TTransport.TFramedTransport(socket) 101 | else: 102 | transport = TTransport.TBufferedTransport(socket) 103 | protocol = TBinaryProtocol(transport) 104 | client = Match.Client(protocol) 105 | transport.open() 106 | 107 | if cmd == 'add_player': 108 | if len(args) != 5: 109 | print('add_player requires 5 args') 110 | sys.exit(1) 111 | pp.pprint(client.add_player(eval(args[0]), args[1], args[2], args[3], args[4],)) 112 | 113 | else: 114 | print('Unrecognized method %s' % cmd) 115 | sys.exit(1) 116 | 117 | transport.close() 118 | -------------------------------------------------------------------------------- /static/js/src/playground/zbase.js: -------------------------------------------------------------------------------- 1 | class AcGamePlayground { 2 | constructor(root) { 3 | this.root = root; 4 | this.$playground = $(`
`); 5 | this.hide(); 6 | this.root.$ac_game.append(this.$playground); 7 | 8 | this.start(); 9 | } 10 | get_random_color() { 11 | let colors = ["blue", "red", "pink", "grey", "green"]; 12 | return colors[Math.floor(Math.random() * 5)]; 13 | } 14 | 15 | create_uuid() { 16 | let res = ""; 17 | for (let i = 0; i < 8; i++) { 18 | let x = parseInt(Math.floor(Math.random() * 10)); // 返回[0,1)之间的数 19 | res += x; 20 | } 21 | return res; 22 | } 23 | 24 | start() { 25 | let outer = this; 26 | let uuid = this.create_uuid(); 27 | $(window).on(`resize.${uuid}`, function() { 28 | outer.resize(); 29 | }) 30 | if (this.root.AcWingOS) { 31 | this.root.AcWingOS.api.window.on_close(function() { 32 | $(window).off(`resize.${uuid}`); 33 | }); 34 | } 35 | } 36 | 37 | resize() { 38 | this.width = this.$playground.width(); 39 | this.height = this.$playground.height(); 40 | let unit = Math.min(this.width / 16, this.height / 9); 41 | this.width = unit * 16; 42 | this.height = unit * 9; 43 | this.scale = this.height; 44 | 45 | if (this.game_map) this.game_map.resize(); 46 | } 47 | 48 | show(mode) { // 打开playground界面 49 | let outer = this; 50 | this.$playground.show(); 51 | this.width = this.$playground.width(); 52 | this.height = this.$playground.height(); 53 | this.game_map = new GameMap(this); 54 | 55 | this.resize(); 56 | 57 | this.mode = mode; 58 | this.state = "waiting"; // waiting -> fighting -> over 59 | this.notice_board = new NoticeBoard(this); 60 | this.score_board = new ScoreBoard(this); 61 | this.player_count = 0; 62 | 63 | this.players = []; 64 | 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)); 65 | 66 | if (mode === "single mode") { 67 | for (let i = 0; i < 5; i++) { 68 | this.players.push(new Player(this, this.width / 2 / this.scale, 0.5, 0.05, this.get_random_color(), 0.15, "robot")); 69 | } 70 | } 71 | else if(mode === "multi mode") { 72 | this.chat_field = new ChatField(this); 73 | this.mps = new MultiPlayerSocket(this); 74 | 75 | this.mps.uuid = this.players[0].uuid; 76 | 77 | this.mps.ws.onopen = function() { 78 | outer.mps.send_create_player(outer.root.settings.username, outer.root.settings.photo); 79 | } 80 | } 81 | } 82 | 83 | hide() { // 关闭playground界面 84 | while (this.players && this.players.length > 0) { 85 | this.players[0].destroy(); 86 | } 87 | if (this.game_map) { 88 | this.game_map.destroy(); 89 | this.game_map = null; 90 | } 91 | if (this.notice_board) { 92 | this.notice_board.destroy(); 93 | this.notice_board = null; 94 | } 95 | if (this.score_board) { 96 | this.score_board.destroy(); 97 | this.score_board = null; 98 | } 99 | 100 | this.$playground.empty(); 101 | 102 | this.$playground.hide(); 103 | } 104 | } -------------------------------------------------------------------------------- /game/static/js/src/playground/zbase.js: -------------------------------------------------------------------------------- 1 | class AcGamePlayground { 2 | constructor(root) { 3 | this.root = root; 4 | this.$playground = $(`
`); 5 | this.hide(); 6 | this.root.$ac_game.append(this.$playground); 7 | 8 | this.start(); 9 | } 10 | get_random_color() { 11 | let colors = ["blue", "red", "pink", "grey", "green"]; 12 | return colors[Math.floor(Math.random() * 5)]; 13 | } 14 | 15 | create_uuid() { 16 | let res = ""; 17 | for (let i = 0; i < 8; i++) { 18 | let x = parseInt(Math.floor(Math.random() * 10)); // 返回[0,1)之间的数 19 | res += x; 20 | } 21 | return res; 22 | } 23 | 24 | start() { 25 | let outer = this; 26 | let uuid = this.create_uuid(); 27 | $(window).on(`resize.${uuid}`, function() { 28 | outer.resize(); 29 | }) 30 | if (this.root.AcWingOS) { 31 | this.root.AcWingOS.api.window.on_close(function() { 32 | $(window).off(`resize.${uuid}`); 33 | }); 34 | } 35 | } 36 | 37 | resize() { 38 | this.width = this.$playground.width(); 39 | this.height = this.$playground.height(); 40 | let unit = Math.min(this.width / 16, this.height / 9); 41 | this.width = unit * 16; 42 | this.height = unit * 9; 43 | this.scale = this.height; 44 | 45 | if (this.game_map) this.game_map.resize(); 46 | } 47 | 48 | show(mode) { // 打开playground界面 49 | let outer = this; 50 | this.$playground.show(); 51 | this.width = this.$playground.width(); 52 | this.height = this.$playground.height(); 53 | this.game_map = new GameMap(this); 54 | 55 | this.resize(); 56 | 57 | this.mode = mode; 58 | this.state = "waiting"; // waiting -> fighting -> over 59 | this.notice_board = new NoticeBoard(this); 60 | this.score_board = new ScoreBoard(this); 61 | this.player_count = 0; 62 | 63 | this.players = []; 64 | 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)); 65 | 66 | if (mode === "single mode") { 67 | for (let i = 0; i < 5; i++) { 68 | this.players.push(new Player(this, this.width / 2 / this.scale, 0.5, 0.05, this.get_random_color(), 0.15, "robot")); 69 | } 70 | } 71 | else if(mode === "multi mode") { 72 | this.chat_field = new ChatField(this); 73 | this.mps = new MultiPlayerSocket(this); 74 | 75 | this.mps.uuid = this.players[0].uuid; 76 | 77 | this.mps.ws.onopen = function() { 78 | outer.mps.send_create_player(outer.root.settings.username, outer.root.settings.photo); 79 | } 80 | } 81 | } 82 | 83 | hide() { // 关闭playground界面 84 | while (this.players && this.players.length > 0) { 85 | this.players[0].destroy(); 86 | } 87 | if (this.game_map) { 88 | this.game_map.destroy(); 89 | this.game_map = null; 90 | } 91 | if (this.notice_board) { 92 | this.notice_board.destroy(); 93 | this.notice_board = null; 94 | } 95 | if (this.score_board) { 96 | this.score_board.destroy(); 97 | this.score_board = null; 98 | } 99 | 100 | this.$playground.empty(); 101 | 102 | this.$playground.hide(); 103 | } 104 | } -------------------------------------------------------------------------------- /static/admin/css/rtl.css: -------------------------------------------------------------------------------- 1 | /* GLOBAL */ 2 | 3 | th { 4 | text-align: right; 5 | } 6 | 7 | .module h2, .module caption { 8 | text-align: right; 9 | } 10 | 11 | .module ul, .module ol { 12 | margin-left: 0; 13 | margin-right: 1.5em; 14 | } 15 | 16 | .viewlink, .addlink, .changelink { 17 | padding-left: 0; 18 | padding-right: 16px; 19 | background-position: 100% 1px; 20 | } 21 | 22 | .deletelink { 23 | padding-left: 0; 24 | padding-right: 16px; 25 | background-position: 100% 1px; 26 | } 27 | 28 | .object-tools { 29 | float: left; 30 | } 31 | 32 | thead th:first-child, 33 | tfoot td:first-child { 34 | border-left: none; 35 | } 36 | 37 | /* LAYOUT */ 38 | 39 | #user-tools { 40 | right: auto; 41 | left: 0; 42 | text-align: left; 43 | } 44 | 45 | div.breadcrumbs { 46 | text-align: right; 47 | } 48 | 49 | #content-main { 50 | float: right; 51 | } 52 | 53 | #content-related { 54 | float: left; 55 | margin-left: -300px; 56 | margin-right: auto; 57 | } 58 | 59 | .colMS { 60 | margin-left: 300px; 61 | margin-right: 0; 62 | } 63 | 64 | /* SORTABLE TABLES */ 65 | 66 | table thead th.sorted .sortoptions { 67 | float: left; 68 | } 69 | 70 | thead th.sorted .text { 71 | padding-right: 0; 72 | padding-left: 42px; 73 | } 74 | 75 | /* dashboard styles */ 76 | 77 | .dashboard .module table td a { 78 | padding-left: .6em; 79 | padding-right: 16px; 80 | } 81 | 82 | /* changelists styles */ 83 | 84 | .change-list .filtered table { 85 | border-left: none; 86 | border-right: 0px none; 87 | } 88 | 89 | #changelist-filter { 90 | border-left: none; 91 | border-right: none; 92 | margin-left: 0; 93 | margin-right: 30px; 94 | } 95 | 96 | #changelist-filter li.selected { 97 | border-left: none; 98 | padding-left: 10px; 99 | margin-left: 0; 100 | border-right: 5px solid var(--hairline-color); 101 | padding-right: 10px; 102 | margin-right: -15px; 103 | } 104 | 105 | #changelist table tbody td:first-child, #changelist table tbody th:first-child { 106 | border-right: none; 107 | border-left: none; 108 | } 109 | 110 | /* FORMS */ 111 | 112 | .aligned label { 113 | padding: 0 0 3px 1em; 114 | float: right; 115 | } 116 | 117 | .submit-row { 118 | text-align: left 119 | } 120 | 121 | .submit-row p.deletelink-box { 122 | float: right; 123 | } 124 | 125 | .submit-row input.default { 126 | margin-left: 0; 127 | } 128 | 129 | .vDateField, .vTimeField { 130 | margin-left: 2px; 131 | } 132 | 133 | .aligned .form-row input { 134 | margin-left: 5px; 135 | } 136 | 137 | form .aligned p.help, form .aligned div.help { 138 | clear: right; 139 | } 140 | 141 | form .aligned ul { 142 | margin-right: 163px; 143 | margin-left: 0; 144 | } 145 | 146 | form ul.inline li { 147 | float: right; 148 | padding-right: 0; 149 | padding-left: 7px; 150 | } 151 | 152 | input[type=submit].default, .submit-row input.default { 153 | float: left; 154 | } 155 | 156 | fieldset .fieldBox { 157 | float: right; 158 | margin-left: 20px; 159 | margin-right: 0; 160 | } 161 | 162 | .errorlist li { 163 | background-position: 100% 12px; 164 | padding: 0; 165 | } 166 | 167 | .errornote { 168 | background-position: 100% 12px; 169 | padding: 10px 12px; 170 | } 171 | 172 | /* WIDGETS */ 173 | 174 | .calendarnav-previous { 175 | top: 0; 176 | left: auto; 177 | right: 10px; 178 | } 179 | 180 | .calendarnav-next { 181 | top: 0; 182 | right: auto; 183 | left: 10px; 184 | } 185 | 186 | .calendar caption, .calendarbox h2 { 187 | text-align: center; 188 | } 189 | 190 | .selector { 191 | float: right; 192 | } 193 | 194 | .selector .selector-filter { 195 | text-align: right; 196 | } 197 | 198 | .inline-deletelink { 199 | float: left; 200 | } 201 | 202 | form .form-row p.datetime { 203 | overflow: hidden; 204 | } 205 | 206 | .related-widget-wrapper { 207 | float: right; 208 | } 209 | 210 | /* MISC */ 211 | 212 | .inline-related h2, .inline-group h2 { 213 | text-align: right 214 | } 215 | 216 | .inline-related h3 span.delete { 217 | padding-right: 20px; 218 | padding-left: inherit; 219 | left: 10px; 220 | right: inherit; 221 | float:left; 222 | } 223 | 224 | .inline-related h3 span.delete label { 225 | margin-left: inherit; 226 | margin-right: 2px; 227 | } 228 | -------------------------------------------------------------------------------- /static/css/game.css: -------------------------------------------------------------------------------- 1 | .ac-game-menu { 2 | width: 100%; 3 | height: 100%; 4 | background-image: url("/static/image/menu/background-myimage.gif"); 5 | background-size: 100% 100%; 6 | user-select: none; 7 | } 8 | 9 | .ac-game-menu-field { 10 | width: 20vw; 11 | position: relative; 12 | top: 40%; 13 | left: 20%; 14 | } 15 | 16 | .ac-game-menu-field-item { 17 | color: white; 18 | height: 6vh; 19 | width: 18vw; 20 | font-size: 4vh; 21 | font-style: italic; 22 | text-align: center; 23 | background-color: rgba(39, 21, 28, 0.6); 24 | border-radius: 10px; 25 | letter-spacing: 0.5vw; 26 | cursor: pointer; 27 | } 28 | 29 | .ac-game-menu-field-item:hover { 30 | transform: scale(1.2); 31 | transition: 100ms; 32 | } 33 | 34 | .ac-game-playground { 35 | width: 100%; 36 | height: 100%; 37 | user-select: none; 38 | background-color: gray; 39 | } 40 | 41 | .ac-game-playground > canvas { 42 | position: relative; 43 | top: 50%; 44 | left: 50%; 45 | transform: translate(-50%, -50%); 46 | } 47 | 48 | .ac-game-settings { 49 | width: 100%; 50 | height: 100%; 51 | background-image: url("/static/image/menu/background-myimage.gif"); 52 | background-size: 100% 100%; 53 | user-select: none; 54 | } 55 | 56 | .ac-game-settings-login { 57 | height: 41vh; 58 | width: 20vw; 59 | position: relative; 60 | top: 50%; 61 | left: 50%; 62 | transform: translate(-50%, -50%); 63 | background-color: rgba(0, 0, 0, 0.7); 64 | border-radius: 5px; 65 | 66 | } 67 | 68 | .ac-game-settings-title { 69 | color: white; 70 | font-size: 3vh; 71 | text-align: center; 72 | padding-top: 2vh; 73 | margin-bottom: 2vh; 74 | } 75 | 76 | .ac-game-settings-username { 77 | display: block; 78 | height: 7vh; 79 | } 80 | 81 | .ac-game-settings-password { 82 | display: block; 83 | height: 7vh; 84 | } 85 | 86 | .ac-game-settings-submit { 87 | display: block; 88 | height: 7vh; 89 | } 90 | 91 | .ac-game-settings-acwing { 92 | display: block; 93 | height: 7vh; 94 | } 95 | 96 | .ac-game-settings-item { 97 | width: 100%; 98 | height: 100%; 99 | } 100 | 101 | .ac-game-settings-item > input { 102 | width: 90%; 103 | line-height: 3vh; 104 | position: relative; 105 | top: 50%; 106 | left: 50%; 107 | transform: translate(-50%, -50%); 108 | } 109 | 110 | .ac-game-settings-item > button { 111 | color: white; 112 | width: 90%; 113 | line-height: 3vh; 114 | position: relative; 115 | top: 50%; 116 | left: 50%; 117 | transform: translate(-50%, -50%); 118 | background-color: #4caf50; 119 | border-radius: 5px; 120 | } 121 | 122 | .ac-game-settings-error-message { 123 | color: red; 124 | font-size: 0.8vh; 125 | display: inline; 126 | float: left; 127 | padding-left: 1vw; 128 | } 129 | 130 | .ac-game-settings-option { 131 | color: white; 132 | font-size: 2vh; 133 | display: inline; 134 | float: right; 135 | padding-right: 1vw; 136 | cursor: pointer; 137 | } 138 | 139 | .ac-game-settings-acwing > img { 140 | position: relative; 141 | top: 50%; 142 | left: 50%; 143 | transform: translate(-50%, -50%); 144 | cursor: pointer; 145 | display: block; 146 | } 147 | 148 | .ac-game-settings-acwing > div { 149 | color: white; 150 | font-size: 1.5vh; 151 | text-align: center; 152 | display: block; 153 | } 154 | 155 | .ac-game-settings-register { 156 | height: 49vh; 157 | width: 20vw; 158 | position: relative; 159 | top: 50%; 160 | left: 50%; 161 | transform: translate(-50%, -50%); 162 | background-color: rgba(0, 0, 0, 0.7); 163 | border-radius: 5px; 164 | } 165 | 166 | .ac-game-chat-field-history { 167 | position: absolute; 168 | top: 66%; 169 | left: 20%; 170 | 171 | transform: translate(-50%, -50%); 172 | 173 | width: 20%; 174 | height: 32%; 175 | 176 | color: white; 177 | font-size: 2vh; 178 | 179 | padding: 5px; 180 | overflow: auto; 181 | } 182 | 183 | .ac-game-chat-field-history::-webkit-scrollbar { 184 | width: 0; 185 | } 186 | 187 | .ac-game-chat-field-input { 188 | position: absolute; 189 | top: 86%; 190 | left: 20%; 191 | transform: translate(-50%, -50%); 192 | 193 | width: 20%; 194 | height: 3vh; 195 | 196 | color: white; 197 | font-size: 2vh; 198 | 199 | background-color: rgba(222,225,230, 0.2); 200 | } 201 | -------------------------------------------------------------------------------- /game/static/css/game.css: -------------------------------------------------------------------------------- 1 | .ac-game-menu { 2 | width: 100%; 3 | height: 100%; 4 | background-image: url("/static/image/menu/background-myimage.gif"); 5 | background-size: 100% 100%; 6 | user-select: none; 7 | } 8 | 9 | .ac-game-menu-field { 10 | width: 20vw; 11 | position: relative; 12 | top: 40%; 13 | left: 20%; 14 | } 15 | 16 | .ac-game-menu-field-item { 17 | color: white; 18 | height: 6vh; 19 | width: 18vw; 20 | font-size: 4vh; 21 | font-style: italic; 22 | text-align: center; 23 | background-color: rgba(39, 21, 28, 0.6); 24 | border-radius: 10px; 25 | letter-spacing: 0.5vw; 26 | cursor: pointer; 27 | } 28 | 29 | .ac-game-menu-field-item:hover { 30 | transform: scale(1.2); 31 | transition: 100ms; 32 | } 33 | 34 | .ac-game-playground { 35 | width: 100%; 36 | height: 100%; 37 | user-select: none; 38 | background-color: gray; 39 | } 40 | 41 | .ac-game-playground > canvas { 42 | position: relative; 43 | top: 50%; 44 | left: 50%; 45 | transform: translate(-50%, -50%); 46 | } 47 | 48 | .ac-game-settings { 49 | width: 100%; 50 | height: 100%; 51 | background-image: url("/static/image/menu/background-myimage.gif"); 52 | background-size: 100% 100%; 53 | user-select: none; 54 | } 55 | 56 | .ac-game-settings-login { 57 | height: 41vh; 58 | width: 20vw; 59 | position: relative; 60 | top: 50%; 61 | left: 50%; 62 | transform: translate(-50%, -50%); 63 | background-color: rgba(0, 0, 0, 0.7); 64 | border-radius: 5px; 65 | 66 | } 67 | 68 | .ac-game-settings-title { 69 | color: white; 70 | font-size: 3vh; 71 | text-align: center; 72 | padding-top: 2vh; 73 | margin-bottom: 2vh; 74 | } 75 | 76 | .ac-game-settings-username { 77 | display: block; 78 | height: 7vh; 79 | } 80 | 81 | .ac-game-settings-password { 82 | display: block; 83 | height: 7vh; 84 | } 85 | 86 | .ac-game-settings-submit { 87 | display: block; 88 | height: 7vh; 89 | } 90 | 91 | .ac-game-settings-acwing { 92 | display: block; 93 | height: 7vh; 94 | } 95 | 96 | .ac-game-settings-item { 97 | width: 100%; 98 | height: 100%; 99 | } 100 | 101 | .ac-game-settings-item > input { 102 | width: 90%; 103 | line-height: 3vh; 104 | position: relative; 105 | top: 50%; 106 | left: 50%; 107 | transform: translate(-50%, -50%); 108 | } 109 | 110 | .ac-game-settings-item > button { 111 | color: white; 112 | width: 90%; 113 | line-height: 3vh; 114 | position: relative; 115 | top: 50%; 116 | left: 50%; 117 | transform: translate(-50%, -50%); 118 | background-color: #4caf50; 119 | border-radius: 5px; 120 | } 121 | 122 | .ac-game-settings-error-message { 123 | color: red; 124 | font-size: 0.8vh; 125 | display: inline; 126 | float: left; 127 | padding-left: 1vw; 128 | } 129 | 130 | .ac-game-settings-option { 131 | color: white; 132 | font-size: 2vh; 133 | display: inline; 134 | float: right; 135 | padding-right: 1vw; 136 | cursor: pointer; 137 | } 138 | 139 | .ac-game-settings-acwing > img { 140 | position: relative; 141 | top: 50%; 142 | left: 50%; 143 | transform: translate(-50%, -50%); 144 | cursor: pointer; 145 | display: block; 146 | } 147 | 148 | .ac-game-settings-acwing > div { 149 | color: white; 150 | font-size: 1.5vh; 151 | text-align: center; 152 | display: block; 153 | } 154 | 155 | .ac-game-settings-register { 156 | height: 49vh; 157 | width: 20vw; 158 | position: relative; 159 | top: 50%; 160 | left: 50%; 161 | transform: translate(-50%, -50%); 162 | background-color: rgba(0, 0, 0, 0.7); 163 | border-radius: 5px; 164 | } 165 | 166 | .ac-game-chat-field-history { 167 | position: absolute; 168 | top: 66%; 169 | left: 20%; 170 | 171 | transform: translate(-50%, -50%); 172 | 173 | width: 20%; 174 | height: 32%; 175 | 176 | color: white; 177 | font-size: 2vh; 178 | 179 | padding: 5px; 180 | overflow: auto; 181 | } 182 | 183 | .ac-game-chat-field-history::-webkit-scrollbar { 184 | width: 0; 185 | } 186 | 187 | .ac-game-chat-field-input { 188 | position: absolute; 189 | top: 86%; 190 | left: 20%; 191 | transform: translate(-50%, -50%); 192 | 193 | width: 20%; 194 | height: 3vh; 195 | 196 | color: white; 197 | font-size: 2vh; 198 | 199 | background-color: rgba(222,225,230, 0.2); 200 | } 201 | -------------------------------------------------------------------------------- /match_system/src/main.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | 3 | import glob 4 | import sys 5 | sys.path.insert(0, glob.glob('../../')[0]) 6 | 7 | from match_server.match_service import Match 8 | 9 | from thrift.transport import TSocket 10 | from thrift.transport import TTransport 11 | from thrift.protocol import TBinaryProtocol 12 | from thrift.server import TServer 13 | 14 | from queue import Queue 15 | from time import sleep 16 | from threading import Thread 17 | 18 | from acapp.asgi import channel_layer 19 | from asgiref.sync import async_to_sync 20 | from django.core.cache import cache 21 | 22 | queue = Queue() # 消息队列,同步 23 | 24 | class Player: 25 | def __init__(self, score, uuid, username, photo, channel_name): # 构造函数 26 | self.score = score 27 | self.uuid = uuid 28 | self.username = username 29 | self.photo = photo 30 | self.channel_name = channel_name 31 | self.waiting_time = 0 # 等待时间 32 | 33 | class Pool: 34 | def __init__(self): 35 | self.players = [] 36 | 37 | def add_player(self, player): 38 | self.players.append(player) 39 | 40 | def check_match(self, a, b): 41 | # if a.username == b.username: 42 | # return False 43 | dt = abs(a.score - b.score) 44 | a_max_dif = a.waiting_time * 50 45 | b_max_dif = b.waiting_time * 50 46 | return dt <= a_max_dif and dt <= b_max_dif 47 | 48 | def match_success(self, ps): 49 | print("Match Success:%s %s %s" % (ps[0].username, ps[1].username, ps[2].username)) 50 | room_name = "room-%s-%s-%s" % (ps[0].uuid, ps[1].uuid, ps[2].uuid) 51 | players = [] 52 | for p in ps: 53 | async_to_sync(channel_layer.group_add)(room_name, p.channel_name) 54 | players.append({ 55 | 'uuid': p.uuid, 56 | 'username': p.username, 57 | 'photo': p.photo, 58 | 'hp': 100, 59 | }) 60 | cache.set(room_name, players, 3600) # 有效时间1小时 61 | for p in ps: 62 | async_to_sync(channel_layer.group_send) ( # 实现进程间通信 63 | room_name, 64 | { 65 | 'type': "group_send_event", 66 | 'event': "create_player", 67 | 'uuid': p.uuid, 68 | 'username': p.username, 69 | 'photo': p.photo, 70 | } 71 | ) 72 | 73 | 74 | def increase_waiting_time(self): 75 | for player in self.players: 76 | player.waiting_time += 1 77 | 78 | def match(self): 79 | while len(self.players) >= 3: 80 | self.players = sorted(self.players, key=lambda p: p.score) 81 | flag = False 82 | for i in range(len(self.players) - 2): 83 | a, b, c = self.players[i], self.players[i + 1], self.players[i + 2] 84 | if self.check_match(a, b) and self.check_match(b, c) and self.check_match(a, c): 85 | self.match_success([a, b, c]) 86 | self.players = self.players[:i] + self.players[i + 3:] 87 | flag = True 88 | break 89 | if not flag: 90 | break 91 | self.increase_waiting_time() 92 | 93 | class MatchHandler: 94 | def add_player(self, score, uuid, username, photo, channel_name): 95 | print("Add Player: %s %d" % (username, score)) 96 | player = Player(score, uuid, username, photo, channel_name) 97 | queue.put(player) 98 | return 0 99 | 100 | def get_player_from_queue(): 101 | try: 102 | return queue.get_nowait() 103 | except: 104 | return None 105 | 106 | def worker(): 107 | pool = Pool() 108 | while True: 109 | player = get_player_from_queue() 110 | if player: 111 | pool.add_player(player) 112 | else: 113 | pool.match() 114 | sleep(1) # 防止cpu被拉满 115 | 116 | if __name__ == '__main__': 117 | handler = MatchHandler() 118 | processor = Match.Processor(handler) 119 | transport = TSocket.TServerSocket(host='127.0.0.1', port=9090) 120 | tfactory = TTransport.TBufferedTransportFactory() 121 | pfactory = TBinaryProtocol.TBinaryProtocolFactory() 122 | 123 | 124 | server = TServer.TThreadedServer( 125 | processor, transport, tfactory, pfactory) 126 | 127 | Thread(target=worker, daemon=True).start() # 开了一个守护线程 128 | 129 | print('Starting the server...') 130 | server.serve() # 主线程 131 | print('done.') -------------------------------------------------------------------------------- /acapp/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for acapp project. 3 | 4 | Generated by 'django-admin startproject' using Django 3.2.8. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/3.2/ref/settings/ 11 | """ 12 | 13 | import os 14 | from pathlib import Path 15 | 16 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 17 | BASE_DIR = Path(__file__).resolve().parent.parent 18 | 19 | 20 | # Quick-start development settings - unsuitable for production 21 | # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ 22 | 23 | # SECURITY WARNING: keep the secret key used in production secret! 24 | SECRET_KEY = 'django-insecure-lxdk6sjj=ka5f4lw+67x+$x9ra%-0fnls&71o7s87*o+up%4**' 25 | 26 | # SECURITY WARNING: don't run with debug turned on in production! 27 | DEBUG = True 28 | 29 | ALLOWED_HOSTS = ["39.107.115.120", "app652.acapp.acwing.com.cn"] 30 | 31 | 32 | # Application definition 33 | 34 | INSTALLED_APPS = [ 35 | 'channels', 36 | 'game.apps.GameConfig', 37 | 'django.contrib.admin', 38 | 'django.contrib.auth', 39 | 'django.contrib.contenttypes', 40 | 'django.contrib.sessions', 41 | 'django.contrib.messages', 42 | 'django.contrib.staticfiles', 43 | ] 44 | 45 | MIDDLEWARE = [ 46 | 'django.middleware.security.SecurityMiddleware', 47 | 'django.contrib.sessions.middleware.SessionMiddleware', 48 | 'django.middleware.common.CommonMiddleware', 49 | 'django.middleware.csrf.CsrfViewMiddleware', 50 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 51 | 'django.contrib.messages.middleware.MessageMiddleware', 52 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 53 | ] 54 | 55 | ROOT_URLCONF = 'acapp.urls' 56 | 57 | TEMPLATES = [ 58 | { 59 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 60 | 'DIRS': [], 61 | 'APP_DIRS': True, 62 | 'OPTIONS': { 63 | 'context_processors': [ 64 | 'django.template.context_processors.debug', 65 | 'django.template.context_processors.request', 66 | 'django.contrib.auth.context_processors.auth', 67 | 'django.contrib.messages.context_processors.messages', 68 | ], 69 | }, 70 | }, 71 | ] 72 | 73 | WSGI_APPLICATION = 'acapp.wsgi.application' 74 | 75 | CACHES = { 76 | 'default': { 77 | 'BACKEND': 'django_redis.cache.RedisCache', 78 | 'LOCATION': 'redis://127.0.0.1:6379/1', 79 | "OPTIONS": { 80 | "CLIENT_CLASS": "django_redis.client.DefaultClient", 81 | }, 82 | }, 83 | } 84 | USER_AGENTS_CACHE = 'default' 85 | 86 | # Database 87 | # https://docs.djangoproject.com/en/3.2/ref/settings/#databases 88 | 89 | DATABASES = { 90 | 'default': { 91 | 'ENGINE': 'django.db.backends.sqlite3', 92 | 'NAME': BASE_DIR / 'db.sqlite3', 93 | } 94 | } 95 | 96 | 97 | # Password validation 98 | # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators 99 | 100 | AUTH_PASSWORD_VALIDATORS = [ 101 | { 102 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 103 | }, 104 | { 105 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 106 | }, 107 | { 108 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 109 | }, 110 | { 111 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 112 | }, 113 | ] 114 | 115 | 116 | # Internationalization 117 | # https://docs.djangoproject.com/en/3.2/topics/i18n/ 118 | 119 | LANGUAGE_CODE = 'en-us' 120 | 121 | TIME_ZONE = 'Asia/Shanghai' 122 | 123 | USE_I18N = True 124 | 125 | USE_L10N = True 126 | 127 | USE_TZ = True 128 | 129 | 130 | # Static files (CSS, JavaScript, Images) 131 | # https://docs.djangoproject.com/en/3.2/howto/static-files/ 132 | 133 | STATIC_ROOT = os.path.join(BASE_DIR, 'static') 134 | STATIC_URL = '/static/' 135 | 136 | MEDIA_ROOT = os.path.join(BASE_DIR, 'media') 137 | MEDIA_URL = '/media/' 138 | 139 | # Default primary key field type 140 | # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field 141 | 142 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' 143 | 144 | ASGI_APPLICATION = 'acapp.asgi.application' 145 | CHANNEL_LAYERS = { 146 | "default": { 147 | "BACKEND": "channels_redis.core.RedisChannelLayer", 148 | "CONFIG": { 149 | "hosts": [("127.0.0.1", 6379)], 150 | }, 151 | }, 152 | } 153 | 154 | ROOM_CAPACITY = 3 -------------------------------------------------------------------------------- /static/admin/js/SelectBox.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | { 3 | const SelectBox = { 4 | cache: {}, 5 | init: function(id) { 6 | const box = document.getElementById(id); 7 | SelectBox.cache[id] = []; 8 | const cache = SelectBox.cache[id]; 9 | for (const node of box.options) { 10 | cache.push({value: node.value, text: node.text, displayed: 1}); 11 | } 12 | }, 13 | redisplay: function(id) { 14 | // Repopulate HTML select box from cache 15 | const box = document.getElementById(id); 16 | const scroll_value_from_top = box.scrollTop; 17 | box.innerHTML = ''; 18 | for (const node of SelectBox.cache[id]) { 19 | if (node.displayed) { 20 | const new_option = new Option(node.text, node.value, false, false); 21 | // Shows a tooltip when hovering over the option 22 | new_option.title = node.text; 23 | box.appendChild(new_option); 24 | } 25 | } 26 | box.scrollTop = scroll_value_from_top; 27 | }, 28 | filter: function(id, text) { 29 | // Redisplay the HTML select box, displaying only the choices containing ALL 30 | // the words in text. (It's an AND search.) 31 | const tokens = text.toLowerCase().split(/\s+/); 32 | for (const node of SelectBox.cache[id]) { 33 | node.displayed = 1; 34 | const node_text = node.text.toLowerCase(); 35 | for (const token of tokens) { 36 | if (!node_text.includes(token)) { 37 | node.displayed = 0; 38 | break; // Once the first token isn't found we're done 39 | } 40 | } 41 | } 42 | SelectBox.redisplay(id); 43 | }, 44 | delete_from_cache: function(id, value) { 45 | let delete_index = null; 46 | const cache = SelectBox.cache[id]; 47 | for (const [i, node] of cache.entries()) { 48 | if (node.value === value) { 49 | delete_index = i; 50 | break; 51 | } 52 | } 53 | cache.splice(delete_index, 1); 54 | }, 55 | add_to_cache: function(id, option) { 56 | SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1}); 57 | }, 58 | cache_contains: function(id, value) { 59 | // Check if an item is contained in the cache 60 | for (const node of SelectBox.cache[id]) { 61 | if (node.value === value) { 62 | return true; 63 | } 64 | } 65 | return false; 66 | }, 67 | move: function(from, to) { 68 | const from_box = document.getElementById(from); 69 | for (const option of from_box.options) { 70 | const option_value = option.value; 71 | if (option.selected && SelectBox.cache_contains(from, option_value)) { 72 | SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); 73 | SelectBox.delete_from_cache(from, option_value); 74 | } 75 | } 76 | SelectBox.redisplay(from); 77 | SelectBox.redisplay(to); 78 | }, 79 | move_all: function(from, to) { 80 | const from_box = document.getElementById(from); 81 | for (const option of from_box.options) { 82 | const option_value = option.value; 83 | if (SelectBox.cache_contains(from, option_value)) { 84 | SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); 85 | SelectBox.delete_from_cache(from, option_value); 86 | } 87 | } 88 | SelectBox.redisplay(from); 89 | SelectBox.redisplay(to); 90 | }, 91 | sort: function(id) { 92 | SelectBox.cache[id].sort(function(a, b) { 93 | a = a.text.toLowerCase(); 94 | b = b.text.toLowerCase(); 95 | if (a > b) { 96 | return 1; 97 | } 98 | if (a < b) { 99 | return -1; 100 | } 101 | return 0; 102 | } ); 103 | }, 104 | select_all: function(id) { 105 | const box = document.getElementById(id); 106 | for (const option of box.options) { 107 | option.selected = true; 108 | } 109 | } 110 | }; 111 | window.SelectBox = SelectBox; 112 | } 113 | -------------------------------------------------------------------------------- /static/js/src/playground/socket/multiplayer/zbase.js: -------------------------------------------------------------------------------- 1 | class MultiPlayerSocket { 2 | constructor(playground) { 3 | this.playground = playground; 4 | 5 | this.ws = new WebSocket("wss://app652.acapp.acwing.com.cn/wss/multiplayer/"); 6 | 7 | this.start(); 8 | } 9 | start() { 10 | this.receive(); 11 | } 12 | receive() { 13 | let outer = this; 14 | this.ws.onmessage = function(e) { 15 | let data = JSON.parse(e.data); 16 | let uuid = data.uuid; 17 | if (uuid === outer.uuid) return false; 18 | 19 | let event = data.event; 20 | if (event === "create_player") { 21 | outer.receive_create_player(uuid, data.username, data.photo); 22 | } 23 | else if (event === "move_to") { 24 | outer.receive_move_to(uuid, data.tx, data.ty); 25 | } 26 | else if (event === "shoot_fireball") { 27 | outer.receive_shoot_fireball(uuid, data.tx, data.ty, data.ball_uuid); 28 | } 29 | else if (event === "attack") { 30 | outer.receive_attack(uuid, data.attackee_uuid, data.x, data.y, data.angle, data.damage, data.ball_uuid); 31 | } 32 | else if (event === "blink") { 33 | outer.receive_blink(uuid, data.tx, data.ty); 34 | } 35 | else if (event === "message") { 36 | outer.receive_message(uuid, data.username, data.text); 37 | } 38 | } 39 | } 40 | send_create_player(username, photo) { 41 | let outer = this; 42 | this.ws.send(JSON.stringify({ 43 | 'event': "create_player", 44 | 'uuid': outer.uuid, 45 | 'username': username, 46 | 'photo': photo, 47 | })); 48 | } 49 | get_player(uuid) { 50 | let players = this.playground.players; 51 | for (let i = 0; i < players.length; i++) { 52 | let player = players[i]; 53 | if (player.uuid === uuid) { 54 | return player; 55 | } 56 | } 57 | return null; 58 | } 59 | receive_create_player(uuid, username, photo) { 60 | let player = new Player( 61 | this.playground, 62 | this.playground.width / 2 / this.playground.scale, 63 | 0.5, 64 | 0.05, 65 | "white", 66 | 0.15, 67 | "enemy", 68 | username, 69 | photo, 70 | 71 | ); 72 | player.uuid = uuid; 73 | this.playground.players.push(player); 74 | } 75 | send_move_to(tx, ty) { 76 | let outer = this; 77 | this.ws.send(JSON.stringify({ 78 | 'event': "move_to", 79 | 'uuid': outer.uuid, 80 | 'tx': tx, 81 | 'ty': ty, 82 | })); 83 | } 84 | receive_move_to(uuid, tx, ty) { 85 | let player = this.get_player(uuid); 86 | 87 | if (player) { 88 | player.move_to(tx, ty); 89 | } 90 | } 91 | send_shoot_fireball(tx, ty, ball_uuid) { 92 | let outer = this; 93 | this.ws.send(JSON.stringify({ 94 | 'event': "shoot_fireball", 95 | 'uuid': outer.uuid, 96 | 'tx': tx, 97 | 'ty': ty, 98 | 'ball_uuid': ball_uuid, 99 | })); 100 | } 101 | receive_shoot_fireball(uuid, tx, ty, ball_uuid) { 102 | let player = this.get_player(uuid); 103 | if (player) { 104 | let fireball = player.shoot_fireball(tx, ty); 105 | fireball.uuid = ball_uuid; 106 | } 107 | } 108 | send_attack(attackee_uuid, x, y, angle, damage, ball_uuid) { 109 | let outer = this; 110 | this.ws.send(JSON.stringify({ 111 | 'event': "attack", 112 | 'uuid': outer.uuid, 113 | 'attackee_uuid': attackee_uuid, 114 | 'x': x, 115 | 'y': y, 116 | 'angle': angle, 117 | 'damage': damage, 118 | 'ball_uuid': ball_uuid, 119 | })) 120 | } 121 | receive_attack(uuid, attackee_uuid, x, y, angle, damage, ball_uuid) { 122 | let attacker = this.get_player(uuid); 123 | let attackee = this.get_player(attackee_uuid); 124 | if (attacker && attackee) { 125 | attackee.receive_attack(x, y, angle, damage, ball_uuid, attacker); 126 | } 127 | } 128 | send_blink(tx, ty) { 129 | let outer = this; 130 | this.ws.send(JSON.stringify({ 131 | 'event': "blink", 132 | 'uuid': outer.uuid, 133 | 'tx': tx, 134 | 'ty': ty, 135 | })); 136 | } 137 | receive_blink(uuid, tx, ty) { 138 | let player = this.get_player(uuid); 139 | if (player) { 140 | player.blink(tx, ty); 141 | } 142 | } 143 | send_message(username, text) { 144 | let outer = this; 145 | this.ws.send(JSON.stringify({ 146 | 'event': "message", 147 | 'uuid': outer.uuid, 148 | 'username': username, 149 | 'text': text, 150 | })); 151 | } 152 | receive_message(uuid, username, text) { 153 | this.playground.chat_field.add_message(username, text); 154 | } 155 | } -------------------------------------------------------------------------------- /game/static/js/src/playground/socket/multiplayer/zbase.js: -------------------------------------------------------------------------------- 1 | class MultiPlayerSocket { 2 | constructor(playground) { 3 | this.playground = playground; 4 | 5 | this.ws = new WebSocket("wss://app652.acapp.acwing.com.cn/wss/multiplayer/"); 6 | 7 | this.start(); 8 | } 9 | start() { 10 | this.receive(); 11 | } 12 | receive() { 13 | let outer = this; 14 | this.ws.onmessage = function(e) { 15 | let data = JSON.parse(e.data); 16 | let uuid = data.uuid; 17 | if (uuid === outer.uuid) return false; 18 | 19 | let event = data.event; 20 | if (event === "create_player") { 21 | outer.receive_create_player(uuid, data.username, data.photo); 22 | } 23 | else if (event === "move_to") { 24 | outer.receive_move_to(uuid, data.tx, data.ty); 25 | } 26 | else if (event === "shoot_fireball") { 27 | outer.receive_shoot_fireball(uuid, data.tx, data.ty, data.ball_uuid); 28 | } 29 | else if (event === "attack") { 30 | outer.receive_attack(uuid, data.attackee_uuid, data.x, data.y, data.angle, data.damage, data.ball_uuid); 31 | } 32 | else if (event === "blink") { 33 | outer.receive_blink(uuid, data.tx, data.ty); 34 | } 35 | else if (event === "message") { 36 | outer.receive_message(uuid, data.username, data.text); 37 | } 38 | } 39 | } 40 | send_create_player(username, photo) { 41 | let outer = this; 42 | this.ws.send(JSON.stringify({ 43 | 'event': "create_player", 44 | 'uuid': outer.uuid, 45 | 'username': username, 46 | 'photo': photo, 47 | })); 48 | } 49 | get_player(uuid) { 50 | let players = this.playground.players; 51 | for (let i = 0; i < players.length; i++) { 52 | let player = players[i]; 53 | if (player.uuid === uuid) { 54 | return player; 55 | } 56 | } 57 | return null; 58 | } 59 | receive_create_player(uuid, username, photo) { 60 | let player = new Player( 61 | this.playground, 62 | this.playground.width / 2 / this.playground.scale, 63 | 0.5, 64 | 0.05, 65 | "white", 66 | 0.15, 67 | "enemy", 68 | username, 69 | photo, 70 | 71 | ); 72 | player.uuid = uuid; 73 | this.playground.players.push(player); 74 | } 75 | send_move_to(tx, ty) { 76 | let outer = this; 77 | this.ws.send(JSON.stringify({ 78 | 'event': "move_to", 79 | 'uuid': outer.uuid, 80 | 'tx': tx, 81 | 'ty': ty, 82 | })); 83 | } 84 | receive_move_to(uuid, tx, ty) { 85 | let player = this.get_player(uuid); 86 | 87 | if (player) { 88 | player.move_to(tx, ty); 89 | } 90 | } 91 | send_shoot_fireball(tx, ty, ball_uuid) { 92 | let outer = this; 93 | this.ws.send(JSON.stringify({ 94 | 'event': "shoot_fireball", 95 | 'uuid': outer.uuid, 96 | 'tx': tx, 97 | 'ty': ty, 98 | 'ball_uuid': ball_uuid, 99 | })); 100 | } 101 | receive_shoot_fireball(uuid, tx, ty, ball_uuid) { 102 | let player = this.get_player(uuid); 103 | if (player) { 104 | let fireball = player.shoot_fireball(tx, ty); 105 | fireball.uuid = ball_uuid; 106 | } 107 | } 108 | send_attack(attackee_uuid, x, y, angle, damage, ball_uuid) { 109 | let outer = this; 110 | this.ws.send(JSON.stringify({ 111 | 'event': "attack", 112 | 'uuid': outer.uuid, 113 | 'attackee_uuid': attackee_uuid, 114 | 'x': x, 115 | 'y': y, 116 | 'angle': angle, 117 | 'damage': damage, 118 | 'ball_uuid': ball_uuid, 119 | })) 120 | } 121 | receive_attack(uuid, attackee_uuid, x, y, angle, damage, ball_uuid) { 122 | let attacker = this.get_player(uuid); 123 | let attackee = this.get_player(attackee_uuid); 124 | if (attacker && attackee) { 125 | attackee.receive_attack(x, y, angle, damage, ball_uuid, attacker); 126 | } 127 | } 128 | send_blink(tx, ty) { 129 | let outer = this; 130 | this.ws.send(JSON.stringify({ 131 | 'event': "blink", 132 | 'uuid': outer.uuid, 133 | 'tx': tx, 134 | 'ty': ty, 135 | })); 136 | } 137 | receive_blink(uuid, tx, ty) { 138 | let player = this.get_player(uuid); 139 | if (player) { 140 | player.blink(tx, ty); 141 | } 142 | } 143 | send_message(username, text) { 144 | let outer = this; 145 | this.ws.send(JSON.stringify({ 146 | 'event': "message", 147 | 'uuid': outer.uuid, 148 | 'username': username, 149 | 'text': text, 150 | })); 151 | } 152 | receive_message(uuid, username, text) { 153 | this.playground.chat_field.add_message(username, text); 154 | } 155 | } -------------------------------------------------------------------------------- /game/consumers/multiplayer/index.py: -------------------------------------------------------------------------------- 1 | from channels.generic.websocket import AsyncWebsocketConsumer 2 | import json 3 | from django.conf import settings 4 | from django.core.cache import cache 5 | 6 | from thrift import Thrift 7 | from thrift.transport import TSocket 8 | from thrift.transport import TTransport 9 | from thrift.protocol import TBinaryProtocol 10 | from channels.db import database_sync_to_async 11 | from game.models.player.player import Player 12 | 13 | from match_system.src.match_server.match_service import Match 14 | 15 | 16 | class MultiPlayer(AsyncWebsocketConsumer): 17 | async def connect(self): 18 | await self.accept() 19 | 20 | async def disconnect(self, close_code): 21 | if self.room_name: 22 | await self.channel_layer.group_discard(self.room_name, self.channel_name) 23 | 24 | async def create_player(self, data): 25 | self.room_name = None 26 | self.uuid = data['uuid'] 27 | # Make socket 28 | transport = TSocket.TSocket('127.0.0.1', 9090) 29 | 30 | # Buffering is critical. Raw sockets are very slow 31 | transport = TTransport.TBufferedTransport(transport) 32 | 33 | # Wrap in a protocol 34 | protocol = TBinaryProtocol.TBinaryProtocol(transport) 35 | 36 | # Create a client to use the protocol encoder 37 | client = Match.Client(protocol) 38 | 39 | def db_get_player(): 40 | return Player.objects.get(user__username=data['username']) 41 | 42 | player = await database_sync_to_async(db_get_player)() 43 | 44 | # Connect! 45 | transport.open() 46 | 47 | client.add_player(player.score, data['uuid'], data['username'], data['photo'], self.channel_name) 48 | 49 | # Close! 50 | transport.close() 51 | 52 | 53 | 54 | async def group_send_event(self, data): 55 | if not self.room_name: 56 | keys = cache.keys('*%s*' % (self.uuid)) 57 | if keys: 58 | self.room_name = keys[0] 59 | await self.send(text_data=json.dumps(data)) 60 | 61 | async def move_to(self, data): 62 | await self.channel_layer.group_send( 63 | self.room_name, 64 | { 65 | 'type': "group_send_event", 66 | 'event': "move_to", 67 | 'uuid': data['uuid'], 68 | 'tx': data['tx'], 69 | 'ty': data['ty'], 70 | } 71 | ) 72 | async def shoot_fireball(self, data): 73 | await self.channel_layer.group_send( 74 | self.room_name, 75 | { 76 | 'type': "group_send_event", 77 | 'event': "shoot_fireball", 78 | 'uuid': data['uuid'], 79 | 'tx': data['tx'], 80 | 'ty': data['ty'], 81 | 'ball_uuid': data['ball_uuid'], 82 | } 83 | ) 84 | 85 | async def attack(self, data): 86 | if not self.room_name: 87 | return 88 | players = cache.get(self.room_name) 89 | 90 | if not players: 91 | return 92 | 93 | for player in players: 94 | if player['uuid'] == data['attackee_uuid']: 95 | player['hp'] -= 25 96 | 97 | remain_cnt = 0 98 | for player in players: 99 | if player['hp'] > 0: 100 | remain_cnt += 1 101 | 102 | if remain_cnt > 1: 103 | if self.room_name: 104 | cache.set(self.room_name, players, 3600) 105 | else: 106 | def db_update_player_score(username, score): 107 | player = Player.objects.get(user__username=username) 108 | player.score += score 109 | player.save() 110 | for player in players: 111 | if player['hp'] <= 0: 112 | await database_sync_to_async(db_update_player_score)(player['username'], -5) 113 | else: 114 | await database_sync_to_async(db_update_player_score)(player['username'], 10) 115 | 116 | await self.channel_layer.group_send( 117 | self.room_name, 118 | { 119 | 'type': "group_send_event", 120 | 'event': "attack", 121 | 'uuid': data['uuid'], 122 | 'attackee_uuid': data['attackee_uuid'], 123 | 'x': data['x'], 124 | 'y': data['y'], 125 | 'angle': data['angle'], 126 | 'damage': data['damage'], 127 | 'ball_uuid': data['ball_uuid'], 128 | } 129 | ) 130 | 131 | async def blink(self, data): 132 | await self.channel_layer.group_send( 133 | self.room_name, 134 | { 135 | 'type': "group_send_event", 136 | 'event': "blink", 137 | 'uuid': data['uuid'], 138 | 'tx': data['tx'], 139 | 'ty': data['ty'], 140 | } 141 | ) 142 | 143 | async def message(self, data): 144 | await self.channel_layer.group_send( 145 | self.room_name, 146 | { 147 | 'type': "group_send_event", 148 | 'event': "message", 149 | 'uuid': data['uuid'], 150 | 'username': data['username'], 151 | 'text': data['text'], 152 | } 153 | ) 154 | 155 | async def receive(self, text_data): 156 | data = json.loads(text_data) 157 | event = data['event'] 158 | if event == "create_player": 159 | await self.create_player(data) 160 | elif event == "move_to": 161 | await self.move_to(data) 162 | elif event == "shoot_fireball": 163 | await self.shoot_fireball(data) 164 | elif event == "attack": 165 | await self.attack(data) 166 | elif event == "blink": 167 | await self.blink(data) 168 | elif event == "message": 169 | await self.message(data) 170 | -------------------------------------------------------------------------------- /static/admin/js/core.js: -------------------------------------------------------------------------------- 1 | // Core javascript helper functions 2 | 'use strict'; 3 | 4 | // quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]); 5 | function quickElement() { 6 | const obj = document.createElement(arguments[0]); 7 | if (arguments[2]) { 8 | const textNode = document.createTextNode(arguments[2]); 9 | obj.appendChild(textNode); 10 | } 11 | const len = arguments.length; 12 | for (let i = 3; i < len; i += 2) { 13 | obj.setAttribute(arguments[i], arguments[i + 1]); 14 | } 15 | arguments[1].appendChild(obj); 16 | return obj; 17 | } 18 | 19 | // "a" is reference to an object 20 | function removeChildren(a) { 21 | while (a.hasChildNodes()) { 22 | a.removeChild(a.lastChild); 23 | } 24 | } 25 | 26 | // ---------------------------------------------------------------------------- 27 | // Find-position functions by PPK 28 | // See https://www.quirksmode.org/js/findpos.html 29 | // ---------------------------------------------------------------------------- 30 | function findPosX(obj) { 31 | let curleft = 0; 32 | if (obj.offsetParent) { 33 | while (obj.offsetParent) { 34 | curleft += obj.offsetLeft - obj.scrollLeft; 35 | obj = obj.offsetParent; 36 | } 37 | } else if (obj.x) { 38 | curleft += obj.x; 39 | } 40 | return curleft; 41 | } 42 | 43 | function findPosY(obj) { 44 | let curtop = 0; 45 | if (obj.offsetParent) { 46 | while (obj.offsetParent) { 47 | curtop += obj.offsetTop - obj.scrollTop; 48 | obj = obj.offsetParent; 49 | } 50 | } else if (obj.y) { 51 | curtop += obj.y; 52 | } 53 | return curtop; 54 | } 55 | 56 | //----------------------------------------------------------------------------- 57 | // Date object extensions 58 | // ---------------------------------------------------------------------------- 59 | { 60 | Date.prototype.getTwelveHours = function() { 61 | return this.getHours() % 12 || 12; 62 | }; 63 | 64 | Date.prototype.getTwoDigitMonth = function() { 65 | return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1); 66 | }; 67 | 68 | Date.prototype.getTwoDigitDate = function() { 69 | return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate(); 70 | }; 71 | 72 | Date.prototype.getTwoDigitTwelveHour = function() { 73 | return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours(); 74 | }; 75 | 76 | Date.prototype.getTwoDigitHour = function() { 77 | return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours(); 78 | }; 79 | 80 | Date.prototype.getTwoDigitMinute = function() { 81 | return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes(); 82 | }; 83 | 84 | Date.prototype.getTwoDigitSecond = function() { 85 | return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds(); 86 | }; 87 | 88 | Date.prototype.getAbbrevMonthName = function() { 89 | return typeof window.CalendarNamespace === "undefined" 90 | ? this.getTwoDigitMonth() 91 | : window.CalendarNamespace.monthsOfYearAbbrev[this.getMonth()]; 92 | }; 93 | 94 | Date.prototype.getFullMonthName = function() { 95 | return typeof window.CalendarNamespace === "undefined" 96 | ? this.getTwoDigitMonth() 97 | : window.CalendarNamespace.monthsOfYear[this.getMonth()]; 98 | }; 99 | 100 | Date.prototype.strftime = function(format) { 101 | const fields = { 102 | b: this.getAbbrevMonthName(), 103 | B: this.getFullMonthName(), 104 | c: this.toString(), 105 | d: this.getTwoDigitDate(), 106 | H: this.getTwoDigitHour(), 107 | I: this.getTwoDigitTwelveHour(), 108 | m: this.getTwoDigitMonth(), 109 | M: this.getTwoDigitMinute(), 110 | p: (this.getHours() >= 12) ? 'PM' : 'AM', 111 | S: this.getTwoDigitSecond(), 112 | w: '0' + this.getDay(), 113 | x: this.toLocaleDateString(), 114 | X: this.toLocaleTimeString(), 115 | y: ('' + this.getFullYear()).substr(2, 4), 116 | Y: '' + this.getFullYear(), 117 | '%': '%' 118 | }; 119 | let result = '', i = 0; 120 | while (i < format.length) { 121 | if (format.charAt(i) === '%') { 122 | result = result + fields[format.charAt(i + 1)]; 123 | ++i; 124 | } 125 | else { 126 | result = result + format.charAt(i); 127 | } 128 | ++i; 129 | } 130 | return result; 131 | }; 132 | 133 | // ---------------------------------------------------------------------------- 134 | // String object extensions 135 | // ---------------------------------------------------------------------------- 136 | String.prototype.strptime = function(format) { 137 | const split_format = format.split(/[.\-/]/); 138 | const date = this.split(/[.\-/]/); 139 | let i = 0; 140 | let day, month, year; 141 | while (i < split_format.length) { 142 | switch (split_format[i]) { 143 | case "%d": 144 | day = date[i]; 145 | break; 146 | case "%m": 147 | month = date[i] - 1; 148 | break; 149 | case "%Y": 150 | year = date[i]; 151 | break; 152 | case "%y": 153 | // A %y value in the range of [00, 68] is in the current 154 | // century, while [69, 99] is in the previous century, 155 | // according to the Open Group Specification. 156 | if (parseInt(date[i], 10) >= 69) { 157 | year = date[i]; 158 | } else { 159 | year = (new Date(Date.UTC(date[i], 0))).getUTCFullYear() + 100; 160 | } 161 | break; 162 | } 163 | ++i; 164 | } 165 | // Create Date object from UTC since the parsed value is supposed to be 166 | // in UTC, not local time. Also, the calendar uses UTC functions for 167 | // date extraction. 168 | return new Date(Date.UTC(year, month, day)); 169 | }; 170 | } 171 | --------------------------------------------------------------------------------