commit cec0aae8e34666306e7c3a2351fc12963996a3cf
Author: GeekROS <15300555770>
Date: Sun Mar 3 22:59:18 2024 +0800
Initial commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..bf098f9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,17 @@
+.idea
+.DS*
+.git
+.vscode
+.godot
+*.cfg
+*.tmp
+desktop/release
+!desktop/release/appicon.png
+desktop/template/yarn.lock
+desktop/template/yarn-error.log
+desktop/template/node_modules
+desktop/template/dist
+engine/release
+engine/runtime
+!engine/release/.gitkeep
+!engine/runtime/.gitkeep
\ No newline at end of file
diff --git a/desktop/framework/config/config.go b/desktop/framework/config/config.go
new file mode 100644
index 0000000..2e20d66
--- /dev/null
+++ b/desktop/framework/config/config.go
@@ -0,0 +1,34 @@
+/**
+ ******************************************************************************
+ * @file config.go
+ * @author MakerYang
+ ******************************************************************************
+ */
+
+package Config
+
+import (
+ "embed"
+ "encoding/json"
+ "golang.org/x/sync/errgroup"
+)
+
+var Get = &Data{}
+
+type Data struct {
+ Info struct {
+ CompanyName string `json:"companyName"`
+ ProductName string `json:"productName"`
+ ProductVersion string `json:"productVersion"`
+ } `json:"info"`
+ Group errgroup.Group
+}
+
+func Init(version embed.FS) {
+ wails, _ := version.ReadFile("wails.json")
+ var wailsJson Data
+ json.Unmarshal(wails, &wailsJson)
+ Get.Info.ProductVersion = wailsJson.Info.ProductVersion
+ Get.Info.ProductName = wailsJson.Info.ProductName
+ Get.Info.CompanyName = wailsJson.Info.CompanyName
+}
diff --git a/desktop/framework/framework.go b/desktop/framework/framework.go
new file mode 100644
index 0000000..738a3e6
--- /dev/null
+++ b/desktop/framework/framework.go
@@ -0,0 +1,62 @@
+/**
+ ******************************************************************************
+ * @file framework.go
+ * @author MakerYang
+ ******************************************************************************
+ */
+
+package Framework
+
+import (
+ "cnc/framework/config"
+ "cnc/framework/windows/start"
+ "embed"
+ "fmt"
+ "github.com/gookit/color"
+ "github.com/wailsapp/wails/v2"
+ "github.com/wailsapp/wails/v2/pkg/options"
+ "github.com/wailsapp/wails/v2/pkg/options/assetserver"
+ "github.com/wailsapp/wails/v2/pkg/options/linux"
+ "github.com/wailsapp/wails/v2/pkg/options/windows"
+)
+
+func Init(template embed.FS, version embed.FS) {
+
+ Config.Init(version)
+
+ start := StartWindows.Init()
+
+ err := wails.Run(&options.App{
+ Title: "",
+ Width: 1200,
+ Height: 768,
+ MinWidth: 1200,
+ MinHeight: 768,
+ AssetServer: &assetserver.Options{
+ Assets: template,
+ },
+ BackgroundColour: &options.RGBA{R: 255, G: 255, B: 255, A: 1},
+ OnStartup: start.Startup,
+ OnShutdown: start.Shutdown,
+ Bind: []interface{}{
+ start,
+ },
+ WindowStartState: options.Normal,
+ Windows: &windows.Options{
+ WebviewDisableRendererCodeIntegrity: true,
+ DisableWindowIcon: true,
+ },
+ Linux: &linux.Options{
+ Icon: []byte(""),
+ WindowIsTranslucent: false,
+ WebviewGpuPolicy: linux.WebviewGpuPolicyNever,
+ },
+ Debug: options.Debug{
+ OpenInspectorOnStartup: false,
+ },
+ })
+
+ if err != nil {
+ fmt.Println("[desktop][framework]:" + color.Gray.Text(err.Error()))
+ }
+}
diff --git a/desktop/framework/windows/start/index.go b/desktop/framework/windows/start/index.go
new file mode 100644
index 0000000..0dda9b0
--- /dev/null
+++ b/desktop/framework/windows/start/index.go
@@ -0,0 +1,74 @@
+/**
+ ******************************************************************************
+ * @file index.go
+ * @author MakerYang
+ ******************************************************************************
+ */
+
+package StartWindows
+
+import (
+ "cnc/framework/config"
+ "context"
+ "os"
+ "runtime"
+ "strings"
+)
+
+type Api struct {
+ ctx context.Context
+}
+
+type ReturnResponse struct {
+ Code int `json:"code"`
+ Data interface{} `json:"data"`
+ Msg string `json:"msg"`
+}
+
+func Init() *Api {
+ return &Api{}
+}
+
+func (start *Api) Startup(ctx context.Context) {
+ start.ctx = ctx
+}
+
+func (start *Api) Shutdown(ctx context.Context) {
+
+}
+
+func (start *Api) GetPlatform() string {
+ platform := ""
+ switch runtime.GOOS {
+ case "windows":
+ platform = "Windows"
+ case "darwin":
+ platform = "Darwin"
+ case "linux":
+ platform = "Linux"
+ content, err := os.ReadFile("/etc/os-release")
+ if err == nil {
+ lines := strings.Split(string(content), "\n")
+ for _, line := range lines {
+ if strings.HasPrefix(line, "ID=") {
+ switch {
+ case strings.Contains(line, "ubuntu"):
+ platform = "Ubuntu"
+ case strings.Contains(line, "debian"):
+ platform = "Debian"
+ default:
+ platform = "Linux"
+ }
+ }
+ }
+ }
+ default:
+ platform = "-"
+ }
+
+ return platform
+}
+
+func (start *Api) GetVersion() []string {
+ return []string{Config.Get.Info.ProductName, Config.Get.Info.ProductVersion}
+}
diff --git a/desktop/go.mod b/desktop/go.mod
new file mode 100644
index 0000000..a89aa39
--- /dev/null
+++ b/desktop/go.mod
@@ -0,0 +1,43 @@
+module cnc
+
+go 1.18
+
+require (
+ github.com/gookit/color v1.5.2
+ github.com/wailsapp/wails/v2 v2.7.1
+ golang.org/x/sync v0.5.0
+)
+
+require (
+ github.com/bep/debounce v1.2.1 // indirect
+ github.com/go-ole/go-ole v1.2.6 // indirect
+ github.com/godbus/dbus/v5 v5.1.0 // indirect
+ github.com/google/uuid v1.3.0 // indirect
+ github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
+ github.com/labstack/echo/v4 v4.10.2 // indirect
+ github.com/labstack/gommon v0.4.0 // indirect
+ github.com/leaanthony/go-ansi-parser v1.6.0 // indirect
+ github.com/leaanthony/gosod v1.0.3 // indirect
+ github.com/leaanthony/slicer v1.6.0 // indirect
+ github.com/leaanthony/u v1.1.0 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.19 // indirect
+ github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/rivo/uniseg v0.4.4 // indirect
+ github.com/samber/lo v1.38.1 // indirect
+ github.com/stretchr/testify v1.8.3 // indirect
+ github.com/tkrajina/go-reflector v0.5.6 // indirect
+ github.com/valyala/bytebufferpool v1.0.0 // indirect
+ github.com/valyala/fasttemplate v1.2.2 // indirect
+ github.com/wailsapp/go-webview2 v1.0.10 // indirect
+ github.com/wailsapp/mimetype v1.4.1 // indirect
+ github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
+ golang.org/x/crypto v0.14.0 // indirect
+ golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
+ golang.org/x/net v0.17.0 // indirect
+ golang.org/x/sys v0.13.0 // indirect
+ golang.org/x/text v0.13.0 // indirect
+)
+
+// replace github.com/wailsapp/wails/v2 v2.3.1 => C:\Users\admin\go\pkg\mod
diff --git a/desktop/go.sum b/desktop/go.sum
new file mode 100644
index 0000000..310aa18
--- /dev/null
+++ b/desktop/go.sum
@@ -0,0 +1,104 @@
+github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
+github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
+github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI=
+github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg=
+github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
+github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
+github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
+github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
+github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
+github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
+github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
+github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
+github.com/leaanthony/go-ansi-parser v1.6.0 h1:T8TuMhFB6TUMIUm0oRrSbgJudTFw9csT3ZK09w0t4Pg=
+github.com/leaanthony/go-ansi-parser v1.6.0/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
+github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ=
+github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
+github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
+github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js=
+github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=
+github.com/leaanthony/u v1.1.0 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI=
+github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
+github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
+github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
+github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
+github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
+github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE=
+github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
+github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
+github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/wailsapp/go-webview2 v1.0.10 h1:PP5Hug6pnQEAhfRzLCoOh2jJaPdrqeRgJKZhyYyDV/w=
+github.com/wailsapp/go-webview2 v1.0.10/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
+github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
+github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
+github.com/wailsapp/wails/v2 v2.7.1 h1:HAzp2c5ODOzsLC6ZMDVtNOB72ozM7/SJecJPB2Ur+UU=
+github.com/wailsapp/wails/v2 v2.7.1/go.mod h1:oIJVwwso5fdOgprBYWXBBqtx6PaSvxg8/KTQHNGkadc=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
+golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
+golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
+golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
+golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/desktop/main.go b/desktop/main.go
new file mode 100644
index 0000000..0ab2cbd
--- /dev/null
+++ b/desktop/main.go
@@ -0,0 +1,26 @@
+/**
+ ******************************************************************************
+ * @file main.go
+ * @author Makeryang
+ ******************************************************************************
+ */
+
+package main
+
+import (
+ "cnc/framework"
+ "embed"
+ "fmt"
+ "github.com/gookit/color"
+)
+
+//go:embed all:template/dist
+var Template embed.FS
+
+//go:embed all:wails.json
+var VersionInfo embed.FS
+
+func main() {
+ fmt.Println("[desktop][main]:" + color.Gray.Text("starting..."))
+ Framework.Init(Template, VersionInfo)
+}
diff --git a/desktop/template/index.html b/desktop/template/index.html
new file mode 100644
index 0000000..ca27fbe
--- /dev/null
+++ b/desktop/template/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ Index
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/desktop/template/package.json b/desktop/template/package.json
new file mode 100644
index 0000000..ab696a8
--- /dev/null
+++ b/desktop/template/package.json
@@ -0,0 +1,33 @@
+{
+ "name": "frontend",
+ "private": true,
+ "version": "0.0.0",
+ "scripts": {
+ "dev": "vite",
+ "rebuild": "node-gyp rebuild",
+ "build": "vue-tsc --noEmit && vite build",
+ "preview": "vite preview"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "dependencies": {
+ "@element-plus/icons": "^0.0.11",
+ "@element-plus/icons-vue": "^2.0.9",
+ "axios": "^0.27.2",
+ "element-plus": "2.3.7",
+ "uuid": "^9.0.0",
+ "vue": "3.2.37",
+ "vue-router": "4.1.5"
+ },
+ "devDependencies": {
+ "@babel/types": "^7.18.10",
+ "@types/react": "^18.2.56",
+ "@types/node": "^18.11.18",
+ "@vitejs/plugin-vue": "^3.0.3",
+ "@vue/tsconfig": "0.1.3",
+ "typescript": "4.6.4",
+ "vite": "3.0.7",
+ "vue-tsc": "0.39.5"
+ }
+}
diff --git a/desktop/template/package.json.md5 b/desktop/template/package.json.md5
new file mode 100644
index 0000000..b14fe42
--- /dev/null
+++ b/desktop/template/package.json.md5
@@ -0,0 +1 @@
+d24d6b406b5af24715d4d957ed80e892
\ No newline at end of file
diff --git a/desktop/template/public/favicon.ico b/desktop/template/public/favicon.ico
new file mode 100644
index 0000000..2322d31
Binary files /dev/null and b/desktop/template/public/favicon.ico differ
diff --git a/desktop/template/public/static/image/logo.png b/desktop/template/public/static/image/logo.png
new file mode 100644
index 0000000..77103bf
Binary files /dev/null and b/desktop/template/public/static/image/logo.png differ
diff --git a/desktop/template/src/app.vue b/desktop/template/src/app.vue
new file mode 100644
index 0000000..0ab1a1f
--- /dev/null
+++ b/desktop/template/src/app.vue
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
diff --git a/desktop/template/src/assets/css/base.scss b/desktop/template/src/assets/css/base.scss
new file mode 100644
index 0000000..10fede8
--- /dev/null
+++ b/desktop/template/src/assets/css/base.scss
@@ -0,0 +1,55 @@
+@charset "UTF-8";
+
+* {
+ box-sizing: border-box;
+ -webkit-tap-highlight-color: transparent;
+ -webkit-appearance: none;
+ -webkit-touch-callout: none;
+ outline: none;
+ user-select: none;
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ font-family: Inter, sans-serif;
+ font-feature-settings: "tnum";
+ font-variant: tabular-nums;
+ -webkit-font-smoothing: antialiased;
+ font-size: 12px;
+ color: #666666;
+}
+
+ul li, ol li {
+ list-style: none;
+}
+
+::-webkit-scrollbar {
+ width: 3px;
+ height: 3px;
+}
+::-webkit-scrollbar-thumb {
+ border-radius: 0;
+ box-shadow: inset 0 0 3px rgba(68, 68, 71, 1);
+ background: rgba(68, 68, 71, .5);
+}
+::-webkit-scrollbar-track{
+ box-shadow: none;
+ border-radius: 0;
+ background: rgba(68, 68, 71, 0);
+}
+
+*:focus {
+ outline: none !important;
+}
+
+.page-main{
+ width: 100%;
+ height: 100%;
+ position: fixed;
+ z-index: 1;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
\ No newline at end of file
diff --git a/desktop/template/src/main.ts b/desktop/template/src/main.ts
new file mode 100644
index 0000000..6e06cc2
--- /dev/null
+++ b/desktop/template/src/main.ts
@@ -0,0 +1,42 @@
+import {createApp} from "vue";
+import App from "./app.vue";
+import {router} from "./router";
+import ElementPlus from "element-plus";
+import "element-plus/dist/index.css";
+import * as ElIcons from "@element-plus/icons-vue";
+
+const app = createApp(App);
+
+app.use(ElementPlus, {zIndex: 90000});
+
+for (const [key, component] of Object.entries(ElIcons)) {
+ app.component(key, component);
+}
+
+app.use(router);
+
+app.directive("resize", {
+ mounted(el, binding) {
+ let _this: any = this;
+ function debounce(fn: any, delay = 16) {
+ let time: any = null;
+ return function () {
+ if (time) {
+ clearTimeout(time);
+ }
+ const context = _this;
+ const args = arguments
+ time = setTimeout(function () {
+ fn.apply(context, args);
+ }, delay);
+ }
+ }
+ el._resizer = new window.ResizeObserver(debounce(binding.value, Number(binding.arg) || 16));
+ el._resizer.observe(el);
+ },
+ unmounted(el) {
+ el._resizer.disconnect();
+ }
+});
+
+app.mount("#app");
diff --git a/desktop/template/src/package/wailsjs/go/StartWindows/Api.d.ts b/desktop/template/src/package/wailsjs/go/StartWindows/Api.d.ts
new file mode 100644
index 0000000..cd30476
--- /dev/null
+++ b/desktop/template/src/package/wailsjs/go/StartWindows/Api.d.ts
@@ -0,0 +1,6 @@
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+export function GetPlatform():Promise;
+
+export function GetVersion():Promise>;
diff --git a/desktop/template/src/package/wailsjs/go/StartWindows/Api.js b/desktop/template/src/package/wailsjs/go/StartWindows/Api.js
new file mode 100644
index 0000000..bc6f138
--- /dev/null
+++ b/desktop/template/src/package/wailsjs/go/StartWindows/Api.js
@@ -0,0 +1,11 @@
+// @ts-check
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+export function GetPlatform() {
+ return window['go']['StartWindows']['Api']['GetPlatform']();
+}
+
+export function GetVersion() {
+ return window['go']['StartWindows']['Api']['GetVersion']();
+}
diff --git a/desktop/template/src/package/wailsjs/runtime/package.json b/desktop/template/src/package/wailsjs/runtime/package.json
new file mode 100644
index 0000000..1e7c8a5
--- /dev/null
+++ b/desktop/template/src/package/wailsjs/runtime/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "@wailsapp/runtime",
+ "version": "2.0.0",
+ "description": "Wails Javascript runtime library",
+ "main": "runtime.js",
+ "types": "runtime.d.ts",
+ "scripts": {
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/wailsapp/wails.git"
+ },
+ "keywords": [
+ "Wails",
+ "Javascript",
+ "Go"
+ ],
+ "author": "Lea Anthony ",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/wailsapp/wails/issues"
+ },
+ "homepage": "https://github.com/wailsapp/wails#readme"
+}
diff --git a/desktop/template/src/package/wailsjs/runtime/runtime.d.ts b/desktop/template/src/package/wailsjs/runtime/runtime.d.ts
new file mode 100644
index 0000000..a3723f9
--- /dev/null
+++ b/desktop/template/src/package/wailsjs/runtime/runtime.d.ts
@@ -0,0 +1,235 @@
+/*
+ _ __ _ __
+| | / /___ _(_) /____
+| | /| / / __ `/ / / ___/
+| |/ |/ / /_/ / / (__ )
+|__/|__/\__,_/_/_/____/
+The electron alternative for Go
+(c) Lea Anthony 2019-present
+*/
+
+export interface Position {
+ x: number;
+ y: number;
+}
+
+export interface Size {
+ w: number;
+ h: number;
+}
+
+export interface Screen {
+ isCurrent: boolean;
+ isPrimary: boolean;
+ width : number
+ height : number
+}
+
+// Environment information such as platform, buildtype, ...
+export interface EnvironmentInfo {
+ buildType: string;
+ platform: string;
+ arch: string;
+}
+
+// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit)
+// emits the given event. Optional data may be passed with the event.
+// This will trigger any event listeners.
+export function EventsEmit(eventName: string, ...data: any): void;
+
+// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name.
+export function EventsOn(eventName: string, callback: (...data: any) => void): () => void;
+
+// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple)
+// sets up a listener for the given event name, but will only trigger a given number times.
+export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void;
+
+// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce)
+// sets up a listener for the given event name, but will only trigger once.
+export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void;
+
+// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff)
+// unregisters the listener for the given event name.
+export function EventsOff(eventName: string, ...additionalEventNames: string[]): void;
+
+// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall)
+// unregisters all listeners.
+export function EventsOffAll(): void;
+
+// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint)
+// logs the given message as a raw message
+export function LogPrint(message: string): void;
+
+// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace)
+// logs the given message at the `trace` log level.
+export function LogTrace(message: string): void;
+
+// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug)
+// logs the given message at the `debug` log level.
+export function LogDebug(message: string): void;
+
+// [LogError](https://wails.io/docs/reference/runtime/log#logerror)
+// logs the given message at the `error` log level.
+export function LogError(message: string): void;
+
+// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal)
+// logs the given message at the `fatal` log level.
+// The application will quit after calling this method.
+export function LogFatal(message: string): void;
+
+// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo)
+// logs the given message at the `info` log level.
+export function LogInfo(message: string): void;
+
+// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning)
+// logs the given message at the `warning` log level.
+export function LogWarning(message: string): void;
+
+// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload)
+// Forces a reload by the main application as well as connected browsers.
+export function WindowReload(): void;
+
+// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp)
+// Reloads the application frontend.
+export function WindowReloadApp(): void;
+
+// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop)
+// Sets the window AlwaysOnTop or not on top.
+export function WindowSetAlwaysOnTop(b: boolean): void;
+
+// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme)
+// *Windows only*
+// Sets window theme to system default (dark/light).
+export function WindowSetSystemDefaultTheme(): void;
+
+// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme)
+// *Windows only*
+// Sets window to light theme.
+export function WindowSetLightTheme(): void;
+
+// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme)
+// *Windows only*
+// Sets window to dark theme.
+export function WindowSetDarkTheme(): void;
+
+// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter)
+// Centers the window on the monitor the window is currently on.
+export function WindowCenter(): void;
+
+// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle)
+// Sets the text in the window title bar.
+export function WindowSetTitle(title: string): void;
+
+// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen)
+// Makes the window full screen.
+export function WindowFullscreen(): void;
+
+// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen)
+// Restores the previous window dimensions and position prior to full screen.
+export function WindowUnfullscreen(): void;
+
+// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen)
+// Returns the state of the window, i.e. whether the window is in full screen mode or not.
+export function WindowIsFullscreen(): Promise;
+
+// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize)
+// Sets the width and height of the window.
+export function WindowSetSize(width: number, height: number): Promise;
+
+// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize)
+// Gets the width and height of the window.
+export function WindowGetSize(): Promise;
+
+// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize)
+// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions.
+// Setting a size of 0,0 will disable this constraint.
+export function WindowSetMaxSize(width: number, height: number): void;
+
+// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize)
+// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions.
+// Setting a size of 0,0 will disable this constraint.
+export function WindowSetMinSize(width: number, height: number): void;
+
+// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition)
+// Sets the window position relative to the monitor the window is currently on.
+export function WindowSetPosition(x: number, y: number): void;
+
+// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition)
+// Gets the window position relative to the monitor the window is currently on.
+export function WindowGetPosition(): Promise;
+
+// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide)
+// Hides the window.
+export function WindowHide(): void;
+
+// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow)
+// Shows the window, if it is currently hidden.
+export function WindowShow(): void;
+
+// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise)
+// Maximises the window to fill the screen.
+export function WindowMaximise(): void;
+
+// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise)
+// Toggles between Maximised and UnMaximised.
+export function WindowToggleMaximise(): void;
+
+// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise)
+// Restores the window to the dimensions and position prior to maximising.
+export function WindowUnmaximise(): void;
+
+// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised)
+// Returns the state of the window, i.e. whether the window is maximised or not.
+export function WindowIsMaximised(): Promise;
+
+// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise)
+// Minimises the window.
+export function WindowMinimise(): void;
+
+// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise)
+// Restores the window to the dimensions and position prior to minimising.
+export function WindowUnminimise(): void;
+
+// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised)
+// Returns the state of the window, i.e. whether the window is minimised or not.
+export function WindowIsMinimised(): Promise;
+
+// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal)
+// Returns the state of the window, i.e. whether the window is normal or not.
+export function WindowIsNormal(): Promise;
+
+// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour)
+// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels.
+export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void;
+
+// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall)
+// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system.
+export function ScreenGetAll(): Promise;
+
+// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl)
+// Opens the given URL in the system browser.
+export function BrowserOpenURL(url: string): void;
+
+// [Environment](https://wails.io/docs/reference/runtime/intro#environment)
+// Returns information about the environment
+export function Environment(): Promise;
+
+// [Quit](https://wails.io/docs/reference/runtime/intro#quit)
+// Quits the application.
+export function Quit(): void;
+
+// [Hide](https://wails.io/docs/reference/runtime/intro#hide)
+// Hides the application.
+export function Hide(): void;
+
+// [Show](https://wails.io/docs/reference/runtime/intro#show)
+// Shows the application.
+export function Show(): void;
+
+// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext)
+// Returns the current text stored on clipboard
+export function ClipboardGetText(): Promise;
+
+// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext)
+// Sets a text on the clipboard
+export function ClipboardSetText(text: string): Promise;
diff --git a/desktop/template/src/package/wailsjs/runtime/runtime.js b/desktop/template/src/package/wailsjs/runtime/runtime.js
new file mode 100644
index 0000000..bd4f371
--- /dev/null
+++ b/desktop/template/src/package/wailsjs/runtime/runtime.js
@@ -0,0 +1,202 @@
+/*
+ _ __ _ __
+| | / /___ _(_) /____
+| | /| / / __ `/ / / ___/
+| |/ |/ / /_/ / / (__ )
+|__/|__/\__,_/_/_/____/
+The electron alternative for Go
+(c) Lea Anthony 2019-present
+*/
+
+export function LogPrint(message) {
+ window.runtime.LogPrint(message);
+}
+
+export function LogTrace(message) {
+ window.runtime.LogTrace(message);
+}
+
+export function LogDebug(message) {
+ window.runtime.LogDebug(message);
+}
+
+export function LogInfo(message) {
+ window.runtime.LogInfo(message);
+}
+
+export function LogWarning(message) {
+ window.runtime.LogWarning(message);
+}
+
+export function LogError(message) {
+ window.runtime.LogError(message);
+}
+
+export function LogFatal(message) {
+ window.runtime.LogFatal(message);
+}
+
+export function EventsOnMultiple(eventName, callback, maxCallbacks) {
+ return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks);
+}
+
+export function EventsOn(eventName, callback) {
+ return EventsOnMultiple(eventName, callback, -1);
+}
+
+export function EventsOff(eventName, ...additionalEventNames) {
+ return window.runtime.EventsOff(eventName, ...additionalEventNames);
+}
+
+export function EventsOnce(eventName, callback) {
+ return EventsOnMultiple(eventName, callback, 1);
+}
+
+export function EventsEmit(eventName) {
+ let args = [eventName].slice.call(arguments);
+ return window.runtime.EventsEmit.apply(null, args);
+}
+
+export function WindowReload() {
+ window.runtime.WindowReload();
+}
+
+export function WindowReloadApp() {
+ window.runtime.WindowReloadApp();
+}
+
+export function WindowSetAlwaysOnTop(b) {
+ window.runtime.WindowSetAlwaysOnTop(b);
+}
+
+export function WindowSetSystemDefaultTheme() {
+ window.runtime.WindowSetSystemDefaultTheme();
+}
+
+export function WindowSetLightTheme() {
+ window.runtime.WindowSetLightTheme();
+}
+
+export function WindowSetDarkTheme() {
+ window.runtime.WindowSetDarkTheme();
+}
+
+export function WindowCenter() {
+ window.runtime.WindowCenter();
+}
+
+export function WindowSetTitle(title) {
+ window.runtime.WindowSetTitle(title);
+}
+
+export function WindowFullscreen() {
+ window.runtime.WindowFullscreen();
+}
+
+export function WindowUnfullscreen() {
+ window.runtime.WindowUnfullscreen();
+}
+
+export function WindowIsFullscreen() {
+ return window.runtime.WindowIsFullscreen();
+}
+
+export function WindowGetSize() {
+ return window.runtime.WindowGetSize();
+}
+
+export function WindowSetSize(width, height) {
+ window.runtime.WindowSetSize(width, height);
+}
+
+export function WindowSetMaxSize(width, height) {
+ window.runtime.WindowSetMaxSize(width, height);
+}
+
+export function WindowSetMinSize(width, height) {
+ window.runtime.WindowSetMinSize(width, height);
+}
+
+export function WindowSetPosition(x, y) {
+ window.runtime.WindowSetPosition(x, y);
+}
+
+export function WindowGetPosition() {
+ return window.runtime.WindowGetPosition();
+}
+
+export function WindowHide() {
+ window.runtime.WindowHide();
+}
+
+export function WindowShow() {
+ window.runtime.WindowShow();
+}
+
+export function WindowMaximise() {
+ window.runtime.WindowMaximise();
+}
+
+export function WindowToggleMaximise() {
+ window.runtime.WindowToggleMaximise();
+}
+
+export function WindowUnmaximise() {
+ window.runtime.WindowUnmaximise();
+}
+
+export function WindowIsMaximised() {
+ return window.runtime.WindowIsMaximised();
+}
+
+export function WindowMinimise() {
+ window.runtime.WindowMinimise();
+}
+
+export function WindowUnminimise() {
+ window.runtime.WindowUnminimise();
+}
+
+export function WindowSetBackgroundColour(R, G, B, A) {
+ window.runtime.WindowSetBackgroundColour(R, G, B, A);
+}
+
+export function ScreenGetAll() {
+ return window.runtime.ScreenGetAll();
+}
+
+export function WindowIsMinimised() {
+ return window.runtime.WindowIsMinimised();
+}
+
+export function WindowIsNormal() {
+ return window.runtime.WindowIsNormal();
+}
+
+export function BrowserOpenURL(url) {
+ window.runtime.BrowserOpenURL(url);
+}
+
+export function Environment() {
+ return window.runtime.Environment();
+}
+
+export function Quit() {
+ window.runtime.Quit();
+}
+
+export function Hide() {
+ window.runtime.Hide();
+}
+
+export function Show() {
+ window.runtime.Show();
+}
+
+export function ClipboardGetText() {
+ return window.runtime.ClipboardGetText();
+}
+
+export function ClipboardSetText(text) {
+ return window.runtime.ClipboardSetText(text);
+}
\ No newline at end of file
diff --git a/desktop/template/src/router/index.ts b/desktop/template/src/router/index.ts
new file mode 100644
index 0000000..f29cb8e
--- /dev/null
+++ b/desktop/template/src/router/index.ts
@@ -0,0 +1,15 @@
+import { createRouter, createWebHashHistory } from "vue-router";
+import StartPage from "../windows/start.vue";
+
+const routes = [
+ {
+ path: "/",
+ name: "Start",
+ component: StartPage
+ },
+];
+
+export const router = createRouter({
+ history: createWebHashHistory(),
+ routes: routes
+})
\ No newline at end of file
diff --git a/desktop/template/src/vite-env.d.ts b/desktop/template/src/vite-env.d.ts
new file mode 100644
index 0000000..8219b17
--- /dev/null
+++ b/desktop/template/src/vite-env.d.ts
@@ -0,0 +1,7 @@
+///
+
+declare module "*.vue" {
+ import type {DefineComponent} from "vue";
+ const component: DefineComponent<{}, {}, any>;
+ export default component;
+}
\ No newline at end of file
diff --git a/desktop/template/src/windows/start.vue b/desktop/template/src/windows/start.vue
new file mode 100644
index 0000000..3052189
--- /dev/null
+++ b/desktop/template/src/windows/start.vue
@@ -0,0 +1,45 @@
+
+ Hello
+
+
+
+
+
diff --git a/desktop/template/tsconfig.json b/desktop/template/tsconfig.json
new file mode 100644
index 0000000..06dc2cc
--- /dev/null
+++ b/desktop/template/tsconfig.json
@@ -0,0 +1,33 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "useDefineForClassFields": true,
+ "module": "ESNext",
+ "moduleResolution": "node",
+ "strict": true,
+ "jsx": "preserve",
+ "sourceMap": false,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "esModuleInterop": true,
+ "lib": [
+ "ESNext",
+ "DOM"
+ ],
+ "types": [
+ "node"
+ ],
+ "skipLibCheck": true
+ },
+ "include": [
+ "src/**/*.ts",
+ "src/**/*.d.ts",
+ "src/**/*.tsx",
+ "src/**/*.vue"
+ ],
+ "references": [
+ {
+ "path": "./tsconfig.node.json"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/desktop/template/tsconfig.node.json b/desktop/template/tsconfig.node.json
new file mode 100644
index 0000000..fe7a069
--- /dev/null
+++ b/desktop/template/tsconfig.node.json
@@ -0,0 +1,14 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "module": "ESNext",
+ "moduleResolution": "node",
+ "allowSyntheticDefaultImports": true,
+ "types": [
+ "node"
+ ]
+ },
+ "include": [
+ "vite.config.ts"
+ ]
+}
\ No newline at end of file
diff --git a/desktop/template/vite.config.ts b/desktop/template/vite.config.ts
new file mode 100644
index 0000000..4f44920
--- /dev/null
+++ b/desktop/template/vite.config.ts
@@ -0,0 +1,17 @@
+import { defineConfig } from "vite";
+import vue from "@vitejs/plugin-vue";
+
+export default defineConfig({
+ server: {
+ port: 6173
+ },
+ plugins: [
+ vue()
+ ],
+ build: {
+ sourcemap: false
+ },
+ optimizeDeps: {
+ exclude: ["punycode"]
+ },
+})
\ No newline at end of file
diff --git a/desktop/wails.json b/desktop/wails.json
new file mode 100644
index 0000000..f71561d
--- /dev/null
+++ b/desktop/wails.json
@@ -0,0 +1,24 @@
+{
+ "$schema": "https://wails.io/schemas/config.v2.json",
+ "name": "desktop",
+ "outputfilename": "desktop",
+ "build:dir": "release",
+ "wailsjsdir": "template/src/package",
+ "frontend:dir": "template",
+ "frontend:install": "yarn",
+ "frontend:build": "yarn build",
+ "frontend:dev:watcher": "yarn dev",
+ "frontend:dev:serverUrl": "auto",
+ "devServer": "localhost:10090",
+ "author": {
+ "name": "MakerYang",
+ "email": "admin@wileho.com"
+ },
+ "info": {
+ "companyName": "MakerYang",
+ "productName": "Desktop",
+ "productVersion": "1.0.0",
+ "copyright": "Copyright © 2019-2022 MakerYang All Rights Reserved",
+ "comments": "MakerYang (https://www.makeryang.com)"
+ }
+}
\ No newline at end of file
diff --git a/engine/assets/icon.svg b/engine/assets/icon.svg
new file mode 100644
index 0000000..b370ceb
--- /dev/null
+++ b/engine/assets/icon.svg
@@ -0,0 +1 @@
+
diff --git a/engine/assets/icon.svg.import b/engine/assets/icon.svg.import
new file mode 100644
index 0000000..cb8ca71
--- /dev/null
+++ b/engine/assets/icon.svg.import
@@ -0,0 +1,37 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://uxjhy0m5hoin"
+path="res://.godot/imported/icon.svg-56083ea2a1f1a4f1e49773bdc6d7826c.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/icon.svg"
+dest_files=["res://.godot/imported/icon.svg-56083ea2a1f1a4f1e49773bdc6d7826c.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=false
+editor/convert_colors_with_editor_theme=false
diff --git a/engine/assets/launch/background.jpeg b/engine/assets/launch/background.jpeg
new file mode 100644
index 0000000..a6ce98a
Binary files /dev/null and b/engine/assets/launch/background.jpeg differ
diff --git a/engine/assets/launch/background.jpeg.import b/engine/assets/launch/background.jpeg.import
new file mode 100644
index 0000000..7815b06
--- /dev/null
+++ b/engine/assets/launch/background.jpeg.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://d05rp7emahb2e"
+path="res://.godot/imported/background.jpeg-5639b05a789575f90a2f9972dfc49a59.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://assets/launch/background.jpeg"
+dest_files=["res://.godot/imported/background.jpeg-5639b05a789575f90a2f9972dfc49a59.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/engine/project.godot b/engine/project.godot
new file mode 100644
index 0000000..430e241
--- /dev/null
+++ b/engine/project.godot
@@ -0,0 +1,40 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="Mir of Godot"
+config/version="1.0.0"
+run/main_scene="res://scenes/launch/launch.tscn"
+config/features=PackedStringArray("4.2", "Mobile")
+boot_splash/bg_color=Color(0, 0, 0, 1)
+config/icon="res://assets/icon.svg"
+
+[autoload]
+
+Global="*res://scripts/framework/global.gd"
+Server="*res://scripts/framework/server/server.gd"
+Client="*res://scripts/framework/client/client.gd"
+Request="*res://scripts/framework/utils/request.gd"
+
+[display]
+
+window/size/viewport_width=1280
+window/size/viewport_height=720
+window/stretch/scale_mode="integer"
+
+[filesystem]
+
+import/blender/enabled=false
+
+[rendering]
+
+renderer/rendering_method="mobile"
+environment/defaults/default_clear_color=Color(0, 0, 0, 1)
diff --git a/engine/scenes/launch/launch.tscn b/engine/scenes/launch/launch.tscn
new file mode 100644
index 0000000..aa06470
--- /dev/null
+++ b/engine/scenes/launch/launch.tscn
@@ -0,0 +1,22 @@
+[gd_scene load_steps=2 format=3 uid="uid://i6g3y6btijjm"]
+
+[ext_resource type="Texture2D" uid="uid://d05rp7emahb2e" path="res://assets/launch/background.jpeg" id="1_5xji2"]
+
+[node name="Launch" type="Control"]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="Background" type="TextureRect" parent="."]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+texture = ExtResource("1_5xji2")
+expand_mode = 2
+stretch_mode = 6
diff --git a/engine/scripts/framework/client/client.gd b/engine/scripts/framework/client/client.gd
new file mode 100644
index 0000000..749bf96
--- /dev/null
+++ b/engine/scripts/framework/client/client.gd
@@ -0,0 +1,28 @@
+#*****************************************************************************
+# @file client.gd
+# @author MakerYang(https://www.makeryang.com)
+# @statement 免费课程配套开源项目,任何形式收费均为盗版
+#*****************************************************************************
+extends Node
+
+# 初始化自定义数据
+var client_peer:ENetMultiplayerPeer
+
+# 初始化数据结构
+var data = {
+ "client_id": 0
+}
+
+# 创建客户端并返回客户端状态
+func create_client() -> int:
+ client_peer = ENetMultiplayerPeer.new()
+ var error = client_peer.create_client(Global.get_server_address(), Global.get_server_port())
+ if error == OK:
+ multiplayer.multiplayer_peer = client_peer
+ # 更新客户端ID
+ update_client_id(multiplayer.get_unique_id())
+ return error
+
+# 更新客户端ID
+func update_client_id(client_id: int) -> void:
+ data["client_id"] = client_id
diff --git a/engine/scripts/framework/global.gd b/engine/scripts/framework/global.gd
new file mode 100644
index 0000000..876f510
--- /dev/null
+++ b/engine/scripts/framework/global.gd
@@ -0,0 +1,53 @@
+#*****************************************************************************
+# @file global.gd
+# @author MakerYang(https://www.makeryang.com)
+# @statement 免费课程配套开源项目,任何形式收费均为盗版
+#*****************************************************************************
+extends Node
+
+# 初始化数据结构
+var data = {
+ "varsion": "1.0.0",
+ "mode": "",
+ "server": {
+ "port": 7020,
+ "address": "game.makeryang.com"
+ },
+ "account": {
+ "token": ""
+ }
+}
+
+func _ready() -> void:
+ # 服务器模式检测
+ if OS.has_feature("dedicated_server"):
+ print("[服务器模式]")
+ data["mode"] = "server"
+ var error = Server.create_server()
+ if error != OK:
+ printerr("[服务器创建失败]")
+ else:
+ print("[客户端模式]")
+ data["mode"] = "client"
+ var error = Client.create_client()
+ if error != OK:
+ printerr("[服务器连接失败]")
+
+# 是否为服务器模式
+func is_server() -> bool:
+ var server = false
+ if data["mode"] == "server":
+ server = true
+ return server
+
+# 获取服务器端口
+func get_server_port() -> int:
+ return data["server"]["port"]
+
+# 获取服务器端口
+func get_server_address() -> String:
+ return data["server"]["address"]
+
+# 获取用户Token
+func get_account_token() -> String:
+ return data["account"]["token"]
diff --git a/engine/scripts/framework/server/server.gd b/engine/scripts/framework/server/server.gd
new file mode 100644
index 0000000..1669438
--- /dev/null
+++ b/engine/scripts/framework/server/server.gd
@@ -0,0 +1,29 @@
+#*****************************************************************************
+# @file server.gd
+# @author MakerYang(https://www.makeryang.com)
+# @statement 免费课程配套开源项目,任何形式收费均为盗版
+#*****************************************************************************
+extends Node
+
+# 初始化自定义数据
+var server_peer:ENetMultiplayerPeer
+
+# 创建服务器并返回服务器状态
+func create_server() -> int:
+ print("[创建服务器...]")
+ server_peer = ENetMultiplayerPeer.new()
+ var error = server_peer.create_server(Global.get_server_port())
+ if error == OK:
+ multiplayer.multiplayer_peer = server_peer
+ multiplayer.peer_connected.connect(_on_peer_connected)
+ multiplayer.peer_disconnected.connect(_on_peer_disconnected)
+ print("[服务器创建成功]")
+ return error
+
+# 客户端连接服务器时回调函数
+func _on_peer_connected(id: int) -> void:
+ print("[新的客户端连接 " + str(id) + "]")
+
+# 客户端断开服务器时回调函数
+func _on_peer_disconnected(id: int) -> void:
+ print("[客户端连接断开 " + str(id) + "]")
diff --git a/engine/scripts/framework/utils/request.gd b/engine/scripts/framework/utils/request.gd
new file mode 100644
index 0000000..521d137
--- /dev/null
+++ b/engine/scripts/framework/utils/request.gd
@@ -0,0 +1,30 @@
+#*****************************************************************************
+# @file request.gd
+# @author MakerYang(https://www.makeryang.com)
+# @statement 免费课程配套开源项目,任何形式收费均为盗版
+#*****************************************************************************
+extends Node
+
+# 初始化自定义数据
+var http_request:HTTPRequest = HTTPRequest.new()
+var http_callback = null
+
+# 初始化数据结构
+var data = {
+ "headers": [
+ "Content-Type: application/json",
+ "Account-Token: ",
+ ]
+}
+
+# 请求服务器接口
+func on_server(path: String, method: int, parameter, callback) -> void:
+ if !http_request.is_inside_tree():
+ add_child(http_request)
+ var parameter_json = JSON.stringify(parameter)
+ data["headers"][1] = "Account-Token: " + Global.get_account_token()
+ if http_callback and http_request.is_connected("request_completed", http_callback):
+ http_request.request_completed.disconnect(http_callback)
+ http_request.request_completed.connect(callback)
+ http_callback = callback
+ http_request.request("https://" + Global.get_server_address() + path, data["headers"], method, parameter_json)
diff --git a/readme.md b/readme.md
new file mode 100644
index 0000000..4117403
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,49 @@
+# 🛠️ Engine2D
+
+⚡ 基于Godot的2D游戏开发框架 ⚡
+
+[](https://opensource.org/licenses/MIT)
+
+
+### 🔦 源码下载
+
+> 随着框架不断的迭代,仓库的历史提交数据逐渐庞大,你可以使用下面的命令来加速源码的下载。
+
+```shell
+git clone --depth=1 git@github.com:makeryangcom/Engine2D.git
+```
+
+### 🛸 技术栈
+
+> 构建一个完整的游戏需要多种技术栈的整合,本框架涉及的技术栈如下:
+
+| Software | Version | Describe |
+| - | - | - |
+| Godot | 4.2.1+ | 游戏引擎 |
+| Golang | 1.19.4+ | 后端服务 |
+| NodeJS | 18.13.0+ | 桌面管理工具 |
+
+### ✨ 目录结构
+
+> 框架包含游戏引擎、后端服务、桌面管理工具等核心模块,详见下面的目录结构说明:
+
+```html
+/Engine2D/
+├─engine
+├─server
+├─desktop
+```
+
+### 🚀 配套课程
+
+> 框架配套的相关的课程可以在`https://www.makeryang.com`获取。
+
+### 💡 关于作者
+
+🔗 Wechat: `makeryang8080`
+
+🔗 WebSite: `https://www.makeryang.com`
+
+🔗 Bilibili: `https://space.bilibili.com/596334734`
+
+🔗 DouYin&Tiktok: `MakerYang`
\ No newline at end of file
diff --git a/server/framework/config/config.go b/server/framework/config/config.go
new file mode 100644
index 0000000..e309f3e
--- /dev/null
+++ b/server/framework/config/config.go
@@ -0,0 +1,52 @@
+/**
+ ******************************************************************************
+ * @file config.go
+ * @author MakerYang
+ ******************************************************************************
+ */
+
+package Config
+
+import "time"
+
+var Get = &config{}
+
+type config struct {
+ Service service `json:"service"`
+ Database database `json:"database"`
+ Hash hash `json:"hash"`
+}
+
+type service struct {
+ Mode string `json:"mode"`
+ HttpPort int `json:"http_port"`
+ ReadTimeout time.Duration `json:"read_timeout"`
+ WriteTimeout time.Duration `json:"write_timeout"`
+}
+
+type database struct {
+ Type string `json:"type"`
+ User string `json:"user"`
+ Password string `json:"password"`
+ Host string `json:"host"`
+ Name string `json:"name"`
+}
+
+type hash struct {
+ Salt string `json:"salt"`
+}
+
+func Init() {
+ Get.Service.Mode = "debug"
+ Get.Service.HttpPort = 7000
+ Get.Service.ReadTimeout = 60 * time.Second
+ Get.Service.WriteTimeout = 60 * time.Second
+
+ Get.Database.Name = "database"
+ Get.Database.Type = "mysql"
+ Get.Database.Host = "localhost"
+ Get.Database.User = "root"
+ Get.Database.Password = "88888888"
+
+ Get.Hash.Salt = "game_$@#godot_@$salt_$@$service%#^#%@%#"
+}
diff --git a/server/framework/controller/controller.go b/server/framework/controller/controller.go
new file mode 100644
index 0000000..760da98
--- /dev/null
+++ b/server/framework/controller/controller.go
@@ -0,0 +1,61 @@
+/**
+ ******************************************************************************
+ * @file controller.go
+ * @author MakerYang
+ ******************************************************************************
+ */
+
+package Controller
+
+import (
+ "Game/framework/config"
+ "Game/framework/controller/ping"
+ "context"
+ "fmt"
+ "github.com/gin-gonic/gin"
+ "github.com/gookit/color"
+ "log"
+ "net/http"
+ "os"
+ "os/signal"
+ "time"
+)
+
+func router() *gin.Engine {
+ router := gin.New()
+
+ gin.SetMode(Config.Get.Service.Mode)
+
+ router.GET("/ping", PingController.Ping)
+
+ return router
+}
+
+func Init() {
+ routers := router()
+
+ var HttpServer = &http.Server{
+ Addr: fmt.Sprintf(":%d", Config.Get.Service.HttpPort),
+ Handler: routers,
+ ReadTimeout: Config.Get.Service.ReadTimeout,
+ WriteTimeout: Config.Get.Service.WriteTimeout,
+ MaxHeaderBytes: 1 << 20,
+ }
+
+ go func() {
+ if err := HttpServer.ListenAndServe(); err != nil {
+ }
+ }()
+
+ log.Println("[game]", color.Green.Text("server..."))
+
+ quit := make(chan os.Signal)
+ signal.Notify(quit, os.Interrupt)
+ <-quit
+
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ defer cancel()
+
+ if err := HttpServer.Shutdown(ctx); err != nil {
+ }
+}
diff --git a/server/framework/controller/ping/ping.go b/server/framework/controller/ping/ping.go
new file mode 100644
index 0000000..f4bd3a5
--- /dev/null
+++ b/server/framework/controller/ping/ping.go
@@ -0,0 +1,18 @@
+/**
+ ******************************************************************************
+ * @file ping.go
+ * @author MakerYang
+ ******************************************************************************
+ */
+
+package PingController
+
+import (
+ "Game/framework/utils"
+ "github.com/gin-gonic/gin"
+)
+
+func Ping(c *gin.Context) {
+ Utils.Success(c, Utils.EmptyData{})
+ return
+}
diff --git a/server/framework/database/database.go b/server/framework/database/database.go
new file mode 100644
index 0000000..42a9e31
--- /dev/null
+++ b/server/framework/database/database.go
@@ -0,0 +1,74 @@
+/**
+ ******************************************************************************
+ * @file database.go
+ * @author MakerYang
+ ******************************************************************************
+ */
+
+package Database
+
+import (
+ "Game/framework/config"
+ "fmt"
+ "github.com/gookit/color"
+ "github.com/jinzhu/gorm"
+ _ "github.com/jinzhu/gorm/dialects/mysql"
+ "log"
+ "time"
+)
+
+var Get *gorm.DB
+
+type DefaultField struct {
+ CreateAt int `gorm:"Column:create_at" json:"create_at"`
+ UpdateAt int `gorm:"Column:update_at" json:"update_at"`
+ DeleteAt int `gorm:"Column:delete_at" json:"delete_at"`
+}
+
+func Init() {
+
+ var err error
+
+ Get, err = gorm.Open(Config.Get.Database.Type, fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", Config.Get.Database.User, Config.Get.Database.Password, Config.Get.Database.Host, Config.Get.Database.Name))
+ if err != nil {
+ log.Println("[database]", color.Red.Text(err.Error()))
+ }
+
+ if Config.Get.Service.Mode == "release" {
+ Get.LogMode(false)
+ } else {
+ Get.LogMode(true)
+ }
+
+ gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string {
+ return defaultTableName
+ }
+
+ Get.SingularTable(true)
+
+ Get.Callback().Create().Replace("gorm:update_time_stamp", func(scope *gorm.Scope) {
+ if !scope.HasError() {
+ nowTime := time.Now().Unix()
+ if createTimeField, ok := scope.FieldByName("CreateAt"); ok {
+ if createTimeField.IsBlank {
+ err := createTimeField.Set(nowTime)
+ if err != nil {
+ }
+ }
+ }
+
+ if modifyTimeField, ok := scope.FieldByName("UpdateAt"); ok {
+ if modifyTimeField.IsBlank {
+ err := modifyTimeField.Set(nowTime)
+ if err != nil {
+ }
+ }
+ }
+ }
+ })
+
+ Get.DB().SetMaxIdleConns(1000)
+ Get.DB().SetMaxOpenConns(10000)
+
+ Get.DB().SetConnMaxLifetime(time.Second * 45)
+}
diff --git a/server/framework/database/interface.go b/server/framework/database/interface.go
new file mode 100644
index 0000000..d9fbdd4
--- /dev/null
+++ b/server/framework/database/interface.go
@@ -0,0 +1,65 @@
+/**
+ ******************************************************************************
+ * @file interface.go
+ * @author MakerYang
+ ******************************************************************************
+ */
+
+package Database
+
+import (
+ "github.com/jinzhu/gorm"
+ "time"
+)
+
+type Base struct {
+ TableName string
+}
+
+func New(table string) *Base {
+ return &Base{
+ TableName: table,
+ }
+}
+
+func (base *Base) CreateData(data interface{}) error {
+ err := Get.Table(base.TableName).Create(data).Error
+ return err
+}
+
+func (base *Base) UpdateData(query interface{}, data map[string]interface{}) error {
+ data["update_at"] = time.Now().Unix()
+ err := Get.Table(base.TableName).Where(query).Updates(data).Error
+ return err
+}
+
+func (base *Base) ExprData(query interface{}, field string, operation string, data int) error {
+ err := Get.Table(base.TableName).Where(query).Update(field, gorm.Expr(field+" "+operation+" ?", data)).Error
+ return err
+}
+
+func (base *Base) GetData(dataStruct interface{}, query interface{}, order string) error {
+ err := Get.Table(base.TableName).Where(query).Order(order).First(dataStruct).Error
+ return err
+}
+
+func (base *Base) ListData(dataStruct interface{}, query interface{}, order string, limit int) error {
+ err := Get.Table(base.TableName).Where(query).Order(order).Limit(limit).Find(dataStruct).Error
+ return err
+}
+
+func (base *Base) PageData(dataStruct interface{}, query interface{}, order string, limit int, page int) error {
+ err := Get.Table(base.TableName).Where(query).Order(order).Limit(limit).Offset(page * limit).Find(dataStruct).Error
+ return err
+}
+
+func (base *Base) CountData(query interface{}) (int, error) {
+ count := 0
+ err := Get.Table(base.TableName).Where(query).Count(&count).Error
+ return count, err
+}
+
+func (base *Base) DeleteData(dataStruct interface{}, query interface{}) error {
+ err := Get.Table(base.TableName).Where(query).Delete(dataStruct).Error
+ return err
+}
diff --git a/server/framework/framework.go b/server/framework/framework.go
new file mode 100644
index 0000000..ccf1e7d
--- /dev/null
+++ b/server/framework/framework.go
@@ -0,0 +1,23 @@
+/**
+ ******************************************************************************
+ * @file framework.go
+ * @author MakerYang
+ ******************************************************************************
+ */
+
+package Framework
+
+import (
+ "Game/framework/config"
+ "Game/framework/controller"
+ "Game/framework/database"
+)
+
+func Init() {
+ // 初始化配置
+ Config.Init()
+ // 初始化数据库
+ Database.Init()
+ // 初始化控制器
+ Controller.Init()
+}
diff --git a/server/framework/utils/empty_data.go b/server/framework/utils/empty_data.go
new file mode 100644
index 0000000..dd7202f
--- /dev/null
+++ b/server/framework/utils/empty_data.go
@@ -0,0 +1,3 @@
+package Utils
+
+type EmptyData struct{}
diff --git a/server/framework/utils/hashids.go b/server/framework/utils/hashids.go
new file mode 100644
index 0000000..20e6836
--- /dev/null
+++ b/server/framework/utils/hashids.go
@@ -0,0 +1,27 @@
+package Utils
+
+import (
+ "Game/framework/config"
+ "github.com/speps/go-hashids"
+)
+
+func EncodeId(len int, id ...int) string {
+ hd := hashids.NewData()
+ hd.Salt = Config.Get.Hash.Salt
+ hd.MinLength = len
+ h := hashids.NewWithData(hd)
+ e, _ := h.Encode(id)
+ return e
+}
+
+func DecodeId(len int, encodedId string) ([]int, error) {
+ hd := hashids.NewData()
+ hd.Salt = Config.Get.Hash.Salt
+ hd.MinLength = len
+ h := hashids.NewWithData(hd)
+ d, err := h.DecodeWithError(encodedId)
+ if err != nil {
+ return nil, err
+ }
+ return d, nil
+}
diff --git a/server/framework/utils/header.go b/server/framework/utils/header.go
new file mode 100644
index 0000000..e5d717a
--- /dev/null
+++ b/server/framework/utils/header.go
@@ -0,0 +1,49 @@
+package Utils
+
+import "strings"
+
+func CheckUserAgent(userAgent string) bool {
+ Status := false
+
+ if strings.Contains(userAgent, "GodotEngine") {
+ Status = true
+ }
+
+ return Status
+}
+
+func CheckGame(token string) (int, int, bool) {
+ Status := false
+ GameId := 0
+ GameAccountId := 0
+
+ if token != "" {
+ tokenMap, _ := DecodeId(128, token)
+ if len(tokenMap) == 2 {
+ GameId = tokenMap[0]
+ GameAccountId = tokenMap[1]
+ Status = true
+ }
+ }
+
+ if GameId == 0 || GameAccountId == 0 {
+ Status = false
+ }
+
+ return GameId, GameAccountId, Status
+}
+
+func CheckUser(token string) (int, bool) {
+ Status := false
+ Uid := 0
+
+ if token != "" {
+ tokenMap, _ := DecodeId(32, token)
+ if len(tokenMap) == 3 {
+ Uid = tokenMap[0]
+ Status = true
+ }
+ }
+
+ return Uid, Status
+}
diff --git a/server/framework/utils/mailbox.go b/server/framework/utils/mailbox.go
new file mode 100644
index 0000000..e09b023
--- /dev/null
+++ b/server/framework/utils/mailbox.go
@@ -0,0 +1,17 @@
+package Utils
+
+import "gopkg.in/gomail.v2"
+
+func SendMail(to string, subject string, content string) bool {
+ status := true
+ mail := gomail.NewMessage()
+ mail.SetHeader("From", mail.FormatAddress("open@wileho.com", "GEEKROS"))
+ mail.SetHeader("To", to)
+ mail.SetHeader("Subject", subject)
+ mail.SetBody("text/html", content)
+ send := gomail.NewDialer("smtp.qq.com", 587, "open@wileho.com", "")
+ if err := send.DialAndSend(mail); err != nil {
+ status = false
+ }
+ return status
+}
diff --git a/server/framework/utils/markdown.go b/server/framework/utils/markdown.go
new file mode 100644
index 0000000..180a818
--- /dev/null
+++ b/server/framework/utils/markdown.go
@@ -0,0 +1,27 @@
+package Utils
+
+import (
+ "regexp"
+ "strings"
+)
+
+func FilterMarkdown(input string) string {
+ quoteBlockRegex := regexp.MustCompile(`^\s*>[ \t]*(.*)$`)
+ lines := strings.Split(input, "\n")
+ var quoteLines []string
+ for _, line := range lines {
+ if quoteBlockRegex.MatchString(line) {
+ match := quoteBlockRegex.FindStringSubmatch(line)
+ quoteLines = append(quoteLines, match[1])
+ }
+ }
+ return strings.Join(quoteLines, "")
+}
+
+func FilterSummary(input string, maxLength int) string {
+ text := strings.TrimSpace(input)
+ if len(text) <= maxLength {
+ return text
+ }
+ return text[:maxLength]
+}
diff --git a/server/framework/utils/md5.go b/server/framework/utils/md5.go
new file mode 100644
index 0000000..d412532
--- /dev/null
+++ b/server/framework/utils/md5.go
@@ -0,0 +1,22 @@
+/**
+ ******************************************************************************
+ * @file md5.go
+ * @author MakerYang
+ ******************************************************************************
+ */
+
+package Utils
+
+import (
+ "crypto/md5"
+ "encoding/hex"
+)
+
+func MD5Hash(text string) string {
+ hash := md5.Sum([]byte(text))
+ return hex.EncodeToString(hash[:])
+}
+
+func VerifyPassword(storedPassword, inputPassword string) bool {
+ return MD5Hash(inputPassword) == storedPassword
+}
diff --git a/server/framework/utils/order.go b/server/framework/utils/order.go
new file mode 100644
index 0000000..e57f3e2
--- /dev/null
+++ b/server/framework/utils/order.go
@@ -0,0 +1,18 @@
+package Utils
+
+import (
+ "math/rand"
+ "time"
+)
+
+func CreateOrderNum() string {
+ str := "0123456789"
+ bytes := []byte(str)
+ result := make([]byte, 0)
+ r := rand.New(rand.NewSource(time.Now().UnixNano()))
+ for i := 0; i < 8; i++ {
+ result = append(result, bytes[r.Intn(len(bytes))])
+ }
+ order := time.Now().Format("20060102150405") + string(result)
+ return order
+}
diff --git a/server/framework/utils/phone.go b/server/framework/utils/phone.go
new file mode 100644
index 0000000..2af2465
--- /dev/null
+++ b/server/framework/utils/phone.go
@@ -0,0 +1,69 @@
+package Utils
+
+import (
+ "bytes"
+ "encoding/json"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "regexp"
+)
+
+func MobileFormat(str string) string {
+ re, _ := regexp.Compile("(\\d{3})(\\d{6})(\\d{2})")
+ return re.ReplaceAllString(str, "$1******$3")
+}
+
+func SendMessage(form string, phone string, info string) bool {
+ status := true
+ if form == "" || phone == "" || info == "" {
+ status = false
+ return status
+ }
+ desc := ""
+ if form == "express" {
+ desc = "【GEEKROS】Hi," + info + " ,你在GEEKROS的订单已经发货,请留意快递信息,及时查收。"
+ }
+ if form == "account" {
+ desc = "【GEEKROS】你的验证码为:" + info + " ,有效期10分钟,工作人员绝不会索取此验证码,切勿告知他人。"
+ }
+
+ apiUrl := "https://smssh1.253.com/msg/v1/send/json"
+ params := make(map[string]interface{})
+ params["account"] = ""
+ params["password"] = ""
+ params["phone"] = phone
+ params["msg"] = desc
+ params["report"] = "false"
+
+ bytesData, err := json.Marshal(params)
+ if err != nil {
+ status = false
+ return status
+ }
+
+ reader := bytes.NewReader(bytesData)
+ request, err := http.NewRequest("POST", apiUrl, reader)
+ if err != nil {
+ status = false
+ return status
+ }
+
+ request.Header.Set("Content-Type", "application/json;charset=UTF-8")
+ client := http.Client{}
+ resp, err := client.Do(request)
+ if err != nil {
+ status = false
+ return status
+ }
+
+ respBytes, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ status = false
+ return status
+ }
+
+ log.Println("[PhoneMessage]", string(respBytes))
+
+ return true
+}
diff --git a/server/framework/utils/price.go b/server/framework/utils/price.go
new file mode 100644
index 0000000..a532498
--- /dev/null
+++ b/server/framework/utils/price.go
@@ -0,0 +1,7 @@
+package Utils
+
+import "fmt"
+
+func PriceConvert(num int) string {
+ return fmt.Sprintf("%.2f", float64(num)/100)
+}
diff --git a/server/framework/utils/rand.go b/server/framework/utils/rand.go
new file mode 100644
index 0000000..7e7e48c
--- /dev/null
+++ b/server/framework/utils/rand.go
@@ -0,0 +1,20 @@
+package Utils
+
+import (
+ "fmt"
+ "math/rand"
+ "time"
+)
+
+func RandInt(min, max int) int {
+ if min >= max || min == 0 || max == 0 {
+ return max
+ }
+ return rand.Intn(max-min) + min
+}
+
+func RandCode() string {
+ randNumber := rand.New(rand.NewSource(time.Now().UnixNano()))
+ code := fmt.Sprintf("%06v", randNumber.Int31n(1000000))
+ return code
+}
diff --git a/server/framework/utils/return.go b/server/framework/utils/return.go
new file mode 100644
index 0000000..bf303f8
--- /dev/null
+++ b/server/framework/utils/return.go
@@ -0,0 +1,105 @@
+package Utils
+
+import (
+ "encoding/json"
+ "github.com/gin-gonic/gin"
+ "log"
+ "net/http"
+ "os"
+ "strconv"
+ "time"
+)
+
+type logData struct {
+ Timestamp int64 `json:"timestamp"`
+ TimestampFormat string `json:"timestamp_format"`
+ ClientMethod string `json:"client_method"`
+ ClientIp string `json:"client_ip"`
+ ClientParameter string `json:"client_parameter"`
+ ServerParameter string `json:"server_parameter"`
+ ServerUrl string `json:"server_url"`
+ ServerName string `json:"server_name"`
+ ServerYear string `json:"server_year"`
+ ServerMonth string `json:"server_month"`
+ ServerDay string `json:"server_day"`
+ ServerTime string `json:"server_time"`
+ TimeLength string `json:"time_length"`
+}
+
+func recordLog(c *gin.Context, serverParameter string) {
+ data := &logData{}
+ data.Timestamp = time.Now().Unix()
+ data.TimestampFormat = time.Now().Format("2006-01-02 15:04:05")
+ data.ClientMethod = c.Request.Method
+ data.ClientIp = c.ClientIP()
+ if data.ClientMethod == "GET" {
+ data.ClientParameter = c.Request.RequestURI
+ }
+ if data.ClientMethod == "POST" {
+ clientParam, err := json.Marshal(c.Request.PostForm)
+ if err != nil {
+ data.ClientParameter = ""
+ }
+ if err == nil {
+ data.ClientParameter = string(clientParam)
+ }
+ }
+ scheme := "http://"
+ if c.Request.TLS != nil {
+ scheme = "https://"
+ }
+ serverUrl := scheme + c.Request.Host + c.Request.URL.Path
+ serverName, _ := os.Hostname()
+ data.ServerUrl = serverUrl
+ data.ServerName = serverName
+ data.ClientParameter = c.GetString("client_parameter")
+ data.ServerParameter = serverParameter
+ data.ServerYear = time.Now().Format("2006")
+ data.ServerMonth = time.Now().Format("01")
+ data.ServerDay = time.Now().Format("02")
+ data.ServerTime = time.Now().Format("15:04:05")
+ data.TimeLength = strconv.FormatFloat(float64(time.Now().UnixNano())/1000000-c.GetFloat64("start_time"), 'f', 2, 64)
+ dataString, _ := json.Marshal(data)
+
+ log.Println("[Log]", string(dataString))
+}
+
+func Success(c *gin.Context, data interface{}) {
+ c.JSON(http.StatusOK, gin.H{
+ "code": 0,
+ "msg": "success",
+ "data": data,
+ })
+ logJson, _ := json.Marshal(gin.H{"code": 0, "msg": "success", "data": data})
+ recordLog(c, string(logJson))
+}
+
+func Error(c *gin.Context, data interface{}) {
+ c.JSON(http.StatusOK, gin.H{
+ "code": 10000,
+ "msg": "error",
+ "data": data,
+ })
+ logJson, _ := json.Marshal(gin.H{"code": 10000, "msg": "error", "data": data})
+ recordLog(c, string(logJson))
+}
+
+func Warning(c *gin.Context, code int, msg string, data interface{}) {
+ c.JSON(http.StatusOK, gin.H{
+ "code": code,
+ "msg": msg,
+ "data": data,
+ })
+ logJson, _ := json.Marshal(gin.H{"code": code, "msg": msg, "data": data})
+ recordLog(c, string(logJson))
+}
+
+func AuthError(c *gin.Context, code int, msg string, data interface{}) {
+ c.JSON(http.StatusUnauthorized, gin.H{
+ "code": code,
+ "msg": msg,
+ "data": data,
+ })
+ logJson, _ := json.Marshal(gin.H{"code": code, "msg": msg, "data": data})
+ recordLog(c, string(logJson))
+}
diff --git a/server/framework/utils/time.go b/server/framework/utils/time.go
new file mode 100644
index 0000000..c0a83b1
--- /dev/null
+++ b/server/framework/utils/time.go
@@ -0,0 +1,33 @@
+package Utils
+
+import (
+ "strconv"
+ "time"
+)
+
+func TimeFormat(unix int) (string, string) {
+ timeInt := time.Unix(int64(unix), 0)
+ return timeInt.Format("2006年01月02日"), timeInt.Format("2006-01-02 15:04:05")
+}
+
+func DateFormat(times int) string {
+ createTime := time.Unix(int64(times), 0)
+ now := time.Now().Unix()
+
+ difTime := now - int64(times)
+
+ str := ""
+ if difTime < 60 {
+ str = "刚刚"
+ } else if difTime < 3600 {
+ M := difTime / 60
+ str = strconv.Itoa(int(M)) + "分钟前"
+ } else if difTime < 3600*24 {
+ H := difTime / 3600
+ str = strconv.Itoa(int(H)) + "小时前"
+ } else {
+ str = createTime.Format("2006-01-02 15:04:05")
+ }
+
+ return str
+}
diff --git a/server/go.mod b/server/go.mod
new file mode 100644
index 0000000..b42187d
--- /dev/null
+++ b/server/go.mod
@@ -0,0 +1,42 @@
+module Game
+
+go 1.19
+
+require (
+ github.com/gin-gonic/gin v1.9.1
+ github.com/gookit/color v1.5.4
+ github.com/jinzhu/gorm v1.9.16
+ github.com/speps/go-hashids v1.0.0
+ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
+)
+
+require (
+ github.com/bytedance/sonic v1.9.1 // indirect
+ github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
+ github.com/gabriel-vasile/mimetype v1.4.2 // indirect
+ github.com/gin-contrib/sse v0.1.0 // indirect
+ github.com/go-playground/locales v0.14.1 // indirect
+ github.com/go-playground/universal-translator v0.18.1 // indirect
+ github.com/go-playground/validator/v10 v10.14.0 // indirect
+ github.com/go-sql-driver/mysql v1.5.0 // indirect
+ github.com/goccy/go-json v0.10.2 // indirect
+ github.com/jinzhu/inflection v1.0.0 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.4 // indirect
+ github.com/leodido/go-urn v1.2.4 // indirect
+ github.com/mattn/go-isatty v0.0.19 // indirect
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+ github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/pelletier/go-toml/v2 v2.0.8 // indirect
+ github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
+ github.com/ugorji/go/codec v1.2.11 // indirect
+ github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
+ golang.org/x/arch v0.3.0 // indirect
+ golang.org/x/crypto v0.9.0 // indirect
+ golang.org/x/net v0.10.0 // indirect
+ golang.org/x/sys v0.10.0 // indirect
+ golang.org/x/text v0.9.0 // indirect
+ google.golang.org/protobuf v1.30.0 // indirect
+ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
diff --git a/server/go.sum b/server/go.sum
new file mode 100644
index 0000000..6b45182
--- /dev/null
+++ b/server/go.sum
@@ -0,0 +1,126 @@
+github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
+github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
+github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
+github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
+github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
+github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
+github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
+github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
+github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
+github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
+github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
+github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
+github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
+github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
+github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
+github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
+github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
+github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
+github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
+github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
+github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
+github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
+github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
+github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
+github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
+github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
+github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
+github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
+github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
+github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
+github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
+github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/speps/go-hashids v1.0.0 h1:jdFC07PrExRM4Og5Ev4411Tox75aFpkC77NlmutadNI=
+github.com/speps/go-hashids v1.0.0/go.mod h1:P7hqPzMdnZOfyIk+xrlG1QaSMw+gCBdHKsBDnhpaZvc=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
+github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
+github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
+github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
+github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
+golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
+golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
+golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
+golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
+google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
+gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
+gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/server/main.go b/server/main.go
new file mode 100644
index 0000000..6df4715
--- /dev/null
+++ b/server/main.go
@@ -0,0 +1,15 @@
+/**
+ ******************************************************************************
+ * @file main.go
+ * @author MakerYang
+ ******************************************************************************
+ */
+
+package main
+
+import "Game/framework"
+
+func main() {
+ // 初始化核心框架
+ Framework.Init()
+}
diff --git a/tools/centos/data/wwwroot/default/index.html b/tools/centos/data/wwwroot/default/index.html
new file mode 100644
index 0000000..e69de29
diff --git a/tools/centos/etc/nginx/conf.d/game.makeryang.com.conf b/tools/centos/etc/nginx/conf.d/game.makeryang.com.conf
new file mode 100644
index 0000000..4dd2268
--- /dev/null
+++ b/tools/centos/etc/nginx/conf.d/game.makeryang.com.conf
@@ -0,0 +1,41 @@
+server {
+ listen 80;
+ listen [::]:80;
+ listen 443 ssl http2;
+ listen [::]:443 ssl http2;
+ ssl_certificate /etc/nginx/ssl/game.makeryang.com.pem;
+ ssl_certificate_key /etc/nginx/ssl/game.makeryang.com.key;
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
+ ssl_ciphers TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
+ ssl_prefer_server_ciphers on;
+ ssl_session_timeout 10m;
+ ssl_session_cache builtin:1000 shared:SSL:10m;
+ ssl_buffer_size 1400;
+ add_header Strict-Transport-Security max-age=15768000;
+ ssl_stapling on;
+ ssl_stapling_verify on;
+ server_name game.makeryang.com;
+ access_log off;
+ if ($ssl_protocol = "") { return 301 https://$host$request_uri; }
+ location / {
+ client_max_body_size 100m;
+ proxy_set_header X-Forwarded-Host $host;
+ proxy_set_header X-Forwarded-Server $host;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_pass http://localhost:7000/;
+ proxy_ignore_client_abort on;
+ proxy_set_header Cookie $http_cookie;
+ proxy_set_header Host $host;
+ }
+ location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ {
+ expires 60s;
+ access_log off;
+ }
+ location ~ .*\.(js|css)?$ {
+ expires 60s;
+ access_log off;
+ }
+ location ~ /(\.user\.ini|\.ht|\.git|\.svn|\.project|LICENSE|README\.md) {
+ deny all;
+ }
+}
\ No newline at end of file
diff --git a/tools/centos/etc/nginx/nginx.conf b/tools/centos/etc/nginx/nginx.conf
new file mode 100644
index 0000000..028fa92
--- /dev/null
+++ b/tools/centos/etc/nginx/nginx.conf
@@ -0,0 +1,30 @@
+user nginx;
+worker_processes auto;
+error_log /var/log/nginx/error.log;
+pid /run/nginx.pid;
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ gzip on;
+ gzip_vary on;
+ gzip_proxied any;
+ gzip_min_length 1000;
+ gzip_comp_level 6;
+ gzip_types text/plain application/xml application/json application/javascript text/css;
+ log_format main '$remote_addr - $remote_user [$time_local] "$request" '
+ '$status $body_bytes_sent "$http_referer" '
+ '"$http_user_agent" "$http_x_forwarded_for"';
+ access_log /var/log/nginx/access.log main;
+ sendfile on;
+ tcp_nopush on;
+ tcp_nodelay on;
+ keepalive_timeout 65;
+ types_hash_max_size 4096;
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+ include /etc/nginx/conf.d/*.conf;
+}
+
diff --git a/tools/centos/etc/nginx/ssl/game.makeryang.com.key b/tools/centos/etc/nginx/ssl/game.makeryang.com.key
new file mode 100644
index 0000000..8b0a44d
--- /dev/null
+++ b/tools/centos/etc/nginx/ssl/game.makeryang.com.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAjNDUW/WYlpctqVq0+kRwknV+pZsWWN95sqErhls7047CnWoA
+V/RxUUj8aIOCVgBX91wDXPSRVuPqmu6Eqc/E+5KIvLCZxg6hoj0aTV+Od1+7Ane2
+PgFAUNNTTeNYpDUAIsvejQTBSxhpWYvx+MKXgGL4C9ysLRBYfZOFy9jGwsd5kxM0
+tqZY1jByyX7p/HAEJVCZe8jdfOZssZjoj+NPXRIivsU+vO3Lv0Pr7yY2vsRi3Aa+
+RUCL45t8nbRf9RRA1EkHxnmnuG6QWng/Td5xUbEEkrdreizqH6f08aNJAmyeH9kE
+F61MU7nxfpAG5Pu2Bcj7jZo0eXLz+oDjIKlnkwIDAQABAoIBAAcogHsSP4j8M2aG
+BWgpfX18eo0plpe6+IFDnyZL0f09pxgAcPcHppEGwEoB0WjUyKP66fLaPd8oY98v
+W9AUD0PonYnWAmMmkEHikEk5n9DirWuBMWLyhlX1gCkX8wQZ66FZMr2BbeAG5CgY
+rJrELZZpsYlM1PXPfGgZzTXhFa2GChCeLKla0Z9eQmn5J/eGfaolbrjFeSDAlWOA
+IZHO7cm3vSvNWfsfkKmO/s8dzwlVC86rw0Wpx5crLGVsFXTFlOYTVLIOciXeN2vc
+gfvYD9E/S+HEYAiYtT+J82QVbkxzvdJ8tzqCmD4gUjl4ORRdxNsHZX23mxAcJ0gi
+zXfWsFUCgYEAw7oO0M3TYZpVB5HmU4nWrPXy4HS9L4N2HJMjxX4ihfG53t1cHi2T
+oTuOHtL4H/FZHnhBt2++2W142AeHFvSDsbeCLACZe7zxfVJyWid1EWBUtJEtLJ7n
+rJbuyvR5OsC9TSgijotafet9J+IJGMlv2Z5rJdULJe4k6256bJNbk1cCgYEAuC3o
+0iMv8lcHqIT4h6Q+CZBVZUD4PwkFfcuU5+fMHRbaylAZpolRCc8A4uLilG2+egJK
+Mt7M8dJnEONxffUmlJg0zIdG2xTvDC+3rnz4jtTOEUw/1tB0oCRj84sk4LyNcjkG
+ls2w/tbY08VLwf5H9CnflNt551aJNdLAh1TGRCUCgYEAriJjugvVK7oGOnTo6Zvx
+vfIXwvC5vIMGW0fhhHzDNE4qowhoQ4UjGkiFGhFypeCw/DXbqdsmfgUyhWi1HIww
+erWcf4+M/hTM+UWX7XO7aNk+o2OiQFekIN4r16+IB+igwvuZOx7qRKt1rz0gAMh+
+1atnAsK3Z2inujqRevXjfIMCgYEAjy4BhPsd1wOZTISywKAKKl0uRdzQIBDfV//f
+7rjgkOynggfrKPAvM7TdN4SyKDl4jlkhXZKfOI8c2KA4JndiWrpIsYeoqcAIZizi
+Wp+Ei2UcHY5tQo4jXCtuGHLfZGawf0+ds7aMFlDnlxoV3uXTAhlbWtmUVyeK23DP
+g2WADJECgYAPux2BixHtl0pYDgw2sk1wrV94+hBAVjxIXq5B1jABYP6vKYe6ry40
+BP26LVCcPDHSuhWBUYasKe3OFlXrcBRInnz8HvD0cPsZ2OUTw0muA98S0TL/NAz9
+WMY04UX0LkFroAmZ4OpsN5dnaYUyyLtE4fL1YzY4yaQm2cAjL4503g==
+-----END RSA PRIVATE KEY-----
diff --git a/tools/centos/etc/nginx/ssl/game.makeryang.com.pem b/tools/centos/etc/nginx/ssl/game.makeryang.com.pem
new file mode 100644
index 0000000..8fef3e7
--- /dev/null
+++ b/tools/centos/etc/nginx/ssl/game.makeryang.com.pem
@@ -0,0 +1,61 @@
+-----BEGIN CERTIFICATE-----
+MIIF/DCCBOSgAwIBAgIQBoJL0yXtOOlqcGZrSYZ7/jANBgkqhkiG9w0BAQsFADBu
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMS0wKwYDVQQDEyRFbmNyeXB0aW9uIEV2ZXJ5d2hlcmUg
+RFYgVExTIENBIC0gRzIwHhcNMjQwMjE3MDAwMDAwWhcNMjQwNTE3MjM1OTU5WjAd
+MRswGQYDVQQDExJnYW1lLm1ha2VyeWFuZy5jb20wggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCM0NRb9ZiWly2pWrT6RHCSdX6lmxZY33myoSuGWzvTjsKd
+agBX9HFRSPxog4JWAFf3XANc9JFW4+qa7oSpz8T7koi8sJnGDqGiPRpNX453X7sC
+d7Y+AUBQ01NN41ikNQAiy96NBMFLGGlZi/H4wpeAYvgL3KwtEFh9k4XL2MbCx3mT
+EzS2pljWMHLJfun8cAQlUJl7yN185myxmOiP409dEiK+xT687cu/Q+vvJja+xGLc
+Br5FQIvjm3ydtF/1FEDUSQfGeae4bpBaeD9N3nFRsQSSt2t6LOofp/Txo0kCbJ4f
+2QQXrUxTufF+kAbk+7YFyPuNmjR5cvP6gOMgqWeTAgMBAAGjggLlMIIC4TAfBgNV
+HSMEGDAWgBR435GQX+7erPbFdevVTFVT7yRKtjAdBgNVHQ4EFgQU6CVLerV8rRvI
+fdoqmcaWm4fsq7YwHQYDVR0RBBYwFIISZ2FtZS5tYWtlcnlhbmcuY29tMD4GA1Ud
+IAQ3MDUwMwYGZ4EMAQIBMCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNl
+cnQuY29tL0NQUzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG
+CCsGAQUFBwMCMIGABggrBgEFBQcBAQR0MHIwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v
+Y3NwLmRpZ2ljZXJ0LmNvbTBKBggrBgEFBQcwAoY+aHR0cDovL2NhY2VydHMuZGln
+aWNlcnQuY29tL0VuY3J5cHRpb25FdmVyeXdoZXJlRFZUTFNDQS1HMi5jcnQwDAYD
+VR0TAQH/BAIwADCCAX4GCisGAQQB1nkCBAIEggFuBIIBagFoAHYA7s3QZNXbGs7F
+XLedtM0TojKHRny87N7DUUhZRnEftZsAAAGNtbUunQAABAMARzBFAiAoHm9oq5Du
+j0gXKhJHx3CAUASFmepG+Jz5tEp5Zp/aUgIhAKH9B4MIkeX4XVg7g74me98+CBJp
+dB3Fl71y13Lj0vK+AHUASLDja9qmRzQP5WoC+p0w6xxSActW3SyB2bu/qznYhHMA
+AAGNtbUt/gAABAMARjBEAiAYaTJ6DJNwpYdjHaDuxLZNxDca+4iFb5s3ZH/g5v3R
+3QIgT2V0+vR4/d0IS2X/BN9g2xtdXKM57AS4t1hl3nO6QpAAdwDatr9rP7W2Ip+b
+wrtca+hwkXFsu1GEhTS9pD0wSNf7qwAAAY21tS3XAAAEAwBIMEYCIQCBAcmOf56D
+/zT2t+M17f9HJCuaAAO640nSaEkC23p2jQIhAJbfBeNyZRUwz1hFbzsOMrTrRGIt
+bLtxLEjydi/ChMMSMA0GCSqGSIb3DQEBCwUAA4IBAQCGwgJRgCUSzVHVsxFxHpEW
+9U3iK9abAq215/wG4F1rXOrnlSXANxkyH/5LCbSvLWEAOiOnBQOIWx7dUcNqk6eq
+oh6XF8IDm5U3VFLawpdYEevcn+L4iFGEMtZl368s4EBjLGt5sUsgwKpo4n+ttMVL
+C7np4+ENPa1PS44PZGUEAWakeZwoTNo+5CVRl++XP9ce+PxcROhJ7/msfcf04s2C
+NmzGIkP6xnDmgekGRcjkivbzqPttx75R5yr73voNW2UJ0XH+UWLWZClWnc5MIne8
+3n1bTFuKKeN15V6lOUSFl+DfdJ1C91Oxf03j9miYJ3nnxPgQYqqQTbisgLarUB4J
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIQDeD/te5iy2EQn2CMnO1e0zANBgkqhkiG9w0BAQsFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
+MjAeFw0xNzExMjcxMjQ2NDBaFw0yNzExMjcxMjQ2NDBaMG4xCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xLTArBgNVBAMTJEVuY3J5cHRpb24gRXZlcnl3aGVyZSBEViBUTFMgQ0EgLSBH
+MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO8Uf46i/nr7pkgTDqnE
+eSIfCFqvPnUq3aF1tMJ5hh9MnO6Lmt5UdHfBGwC9Si+XjK12cjZgxObsL6Rg1njv
+NhAMJ4JunN0JGGRJGSevbJsA3sc68nbPQzuKp5Jc8vpryp2mts38pSCXorPR+sch
+QisKA7OSQ1MjcFN0d7tbrceWFNbzgL2csJVQeogOBGSe/KZEIZw6gXLKeFe7mupn
+NYJROi2iC11+HuF79iAttMc32Cv6UOxixY/3ZV+LzpLnklFq98XORgwkIJL1HuvP
+ha8yvb+W6JislZJL+HLFtidoxmI7Qm3ZyIV66W533DsGFimFJkz3y0GeHWuSVMbI
+lfsCAwEAAaOCAU8wggFLMB0GA1UdDgQWBBR435GQX+7erPbFdevVTFVT7yRKtjAf
+BgNVHSMEGDAWgBROIlQgGJXm427mD/r6uRLtBhePOTAOBgNVHQ8BAf8EBAMCAYYw
+HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8C
+AQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp
+Y2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQu
+Y29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG
+/WwBAjAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT
+MAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAQEAoBs1eCLKakLtVRPFRjBIJ9LJ
+L0s8ZWum8U8/1TMVkQMBn+CPb5xnCD0GSA6L/V0ZFrMNqBirrr5B241OesECvxIi
+98bZ90h9+q/X5eMyOD35f8YTaEMpdnQCnawIwiHx06/0BfiTj+b/XQih+mqt3ZXe
+xNCJqKexdiB2IWGSKcgahPacWkk/BAQFisKIFYEqHzV974S3FAz/8LIfD58xnsEN
+GfzyIDkH3JrwYZ8caPTf6ZX9M1GrISN8HnWTtdNCH2xEajRa/h9ZBXjUyFKQrGk2
+n2hcLrfZSbynEC/pSw/ET7H5nWwckjmAJ1l9fcnbqkU/pf6uMQmnfl0JQjJNSg==
+-----END CERTIFICATE-----
diff --git a/tools/centos/etc/systemd/system/game.service b/tools/centos/etc/systemd/system/game.service
new file mode 100644
index 0000000..d5897ff
--- /dev/null
+++ b/tools/centos/etc/systemd/system/game.service
@@ -0,0 +1,13 @@
+[Unit]
+Description=Game
+After=syslog.target network.target
+
+[Service]
+Type=simple
+Environment=GODOT_SILENCE_ROOT_WARNING=1
+WorkingDirectory=/data/wwwroot/game/
+ExecStart=/data/wwwroot/game/server.x86_64 --headless
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/tools/centos/etc/systemd/system/server.service b/tools/centos/etc/systemd/system/server.service
new file mode 100644
index 0000000..ae03be2
--- /dev/null
+++ b/tools/centos/etc/systemd/system/server.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Server
+After=syslog.target network.target
+
+[Service]
+Type=simple
+WorkingDirectory=/data/wwwroot/server/
+ExecStart=/data/wwwroot/server/main
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
diff --git a/tools/update.sh b/tools/update.sh
new file mode 100755
index 0000000..a9eadcb
--- /dev/null
+++ b/tools/update.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+set -e
+
+# 复制Nginx、服务配置配置
+sudo cp -r ./tools/centos/* /
+
+# 复制后端服务到运行目录
+sudo cp -r ./server /data/wwwroot/
+
+# 创建游戏引擎服务端运行目录
+if [ ! -d "/data/wwwroot/game" ]; then
+ mkdir -p /data/wwwroot/game
+fi
+
+# 编译后端服务
+cd /data/wwwroot/server/
+/usr/local/go/bin/go env -w GOSUMDB=off
+export GO111MODULE=on && export GOPROXY=https://goproxy.io && /usr/local/go/bin/go build main.go
+
+# 重启Nginx服务
+sudo systemctl restart nginx.service
+
+# 重启后端服务和游戏服务
+sudo systemctl daemon-reload
+sudo systemctl restart server.service
+sudo systemctl restart game.service
\ No newline at end of file
diff --git a/update.bat b/update.bat
new file mode 100644
index 0000000..1938885
--- /dev/null
+++ b/update.bat
@@ -0,0 +1,5 @@
+@echo off
+
+scp -r ./engine/release/server* root@172.21.255.206:/data/wwwroot/game/
+
+ssh root@172.21.255.206 "chmod +x /data/wwwroot/game/* && cd /opt/Engine2D && sudo ./tools/update.sh"
\ No newline at end of file
diff --git a/wiki/course/0001.md b/wiki/course/0001.md
new file mode 100644
index 0000000..71938af
--- /dev/null
+++ b/wiki/course/0001.md
@@ -0,0 +1,100 @@
+## 第一课
+
+> 第一课时操作引导文档。
+
+### 一、游戏资源下载
+
+> 1、访问:[GitHub](https://www.github.com)
+
+> 2、下载安装Git:[Git](https://git-scm.com)
+
+````shell
+# 生成GitHub SSH KEY
+ssh-keygen -t rsa -C "你的GitHub登录账号"
+````
+
+```shell
+git config -global user.name "你的GitHub用户名"
+git config -global user.email "你的GitHub登录账号"
+```
+```shell
+# 下载游戏源码
+git clone --depth=1 git@github.com:makeryangcom/Engine2D.git
+```
+
+### 二、虚拟机的安装和配置
+
+> 1、CentOS系统镜像下载地址:[CentOS-8.5.2111-x86_64-dvd1.iso](https://mirrors.aliyun.com/centos/8/isos/x86_64/CentOS-8.5.2111-x86_64-dvd1.iso)
+
+> 2、切换到root用户,密码为`root`
+
+```shell
+su
+```
+
+> 3、修改SSH配置,防止后续SSH远程登录时因连接超时自动断开
+
+```shell
+vim /etc/ssh/sshd_config
+```
+
+> 4、获取虚拟机服务器内网IP地址
+
+```shell
+ifconfig
+```
+
+> 5、在本地电脑的命令行工具中通过SSH远程登录到虚拟机服务器
+
+```shell
+ssh root@服务器内网IP地址
+```
+
+> 6、更新软件源
+
+```shell
+sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
+sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
+# 设置阿里云软件源
+wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-8.repo
+# 清理缓存
+yum clean all
+yum makecache
+```
+
+> 7、切换到root用户
+
+```shell
+yum update -y
+```
+
+> 8、安装常用的软件和组件
+
+```shell
+yum install -y vim curl git openssl openssl-devel
+```
+
+> 9、安装Nginx
+
+```shell
+yum install -y nginx
+```
+
+``` bash
+# 启动Nginx服务
+sudo systemctl start nginx.service
+```
+
+``` bash
+# 设置Nginx服务开机启动
+sudo systemctl enable nginx.service
+```
+
+``` bash
+# 常用维护命令-重启Nginx服务
+sudo systemctl restart nginx.service
+# 常用维护命令-停止Nginx服务
+sudo systemctl stop nginx.service
+# 常用维护命令-启动Nginx服务
+sudo systemctl start nginx.service
+```
\ No newline at end of file