diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..e23ad73 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,26 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build and run dev service locally", + "type": "shell", + "command": "docker compose up --build dev", + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Build and run release service locally", + "type": "shell", + "command": "docker compose up --build release", + "problemMatcher": [], + "group": { + "kind": "test", + "isDefault": false + } + } + ] + } + \ No newline at end of file diff --git a/Dockerfile.dev b/Dockerfile.dev index 7f42c19..1f7332e 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,10 +1,13 @@ FROM golang:alpine WORKDIR /app +ENV GO111MODULE=on +RUN go install github.com/cosmtrek/air@latest COPY main.go . COPY pkg/ pkg/ COPY go.sum go.sum COPY go.mod go.mod +RUN go mod tidy RUN go mod download RUN mkdir keys/ RUN go run pkg/auth/pem/main.go /app/keys terra-major-client -ENTRYPOINT go run main.go \ No newline at end of file +ENTRYPOINT air \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 4a8e294..851a74b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -6,12 +6,40 @@ x-db-variables: &db-variables POSTGRES_PASSWORD: $POSTGRES_PASSWORD POSTGRES_DATABASE: $POSTGRES_DATABASE POSTGRES_SSL: $POSTGRES_SSL + COSMOS_DB_HOST: $COSMOS_DB_HOST + COSMOS_DB_PORT: $COSMOS_DB_PORT + COSMOS_DB_PRIMARY_KEY: $COSMOS_DB_PRIMARY_KEY + COSMOS_DB_NAME: $COSMOS_DB_NAME networks: local: services: + cosmos: + container_name: cosmos + image: mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator + tty: true + restart: always + mem_limit: 3G + cpu_count: 4 + environment: + - AZURE_COSMOS_EMULATOR_PARTITION_COUNT=5 + - AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE=true + ports: + - ${COSMOS_DB_PORT}:${COSMOS_DB_PORT} + - 10250-10255:10250-10255 + hostname: cosmos + networks: + local: + aliases: + - cosmos + entrypoint: /bin/bash -c + command: + - | + apt-get update -y && apt-get install -y curl + /usr/local/bin/cosmos/start.sh + postgres: image: postgres:15.3-alpine restart: always @@ -33,7 +61,6 @@ services: dockerfile: ./Dockerfile.dev environment: <<: *db-variables - PKG: characters PORT: 8000 networks: local: @@ -56,4 +83,6 @@ services: volumes: postgres: + driver: local + cosmos: driver: local \ No newline at end of file diff --git a/go.mod b/go.mod index 48f77ec..99dd0ce 100644 --- a/go.mod +++ b/go.mod @@ -3,21 +3,29 @@ module github.com/mw-felker/terra-major-api go 1.20 require ( + github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.5 + github.com/aquilax/go-perlin v1.1.0 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/uuid v1.3.0 github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 - golang.org/x/crypto v0.8.0 + golang.org/x/crypto v0.12.0 gorm.io/driver/postgres v1.5.2 gorm.io/gorm v1.25.1 ) require ( + github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect github.com/felixge/httpsnoop v1.0.1 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgx/v5 v5.3.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - golang.org/x/text v0.9.0 // indirect + github.com/stretchr/testify v1.8.4 // indirect + golang.org/x/net v0.14.0 // indirect + golang.org/x/text v0.12.0 // indirect ) diff --git a/go.sum b/go.sum index 38165c4..2338a43 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,23 @@ +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= +github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0 h1:8q4SaHjFsClSvuVne0ID/5Ka8u3fcIHyqkLjcFpNRHQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0 h1:vcYCAze6p19qBW7MhZybIsqD8sMV8js0NyQM8JDnVtg= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.0/go.mod h1:OQeznEEkTZ9OrhHJoDD8ZDq51FHgXjqtP9z6bEwBq9U= +github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.5 h1:qS0Bp4do0cIvnuQgSGeO6ZCu/q/HlRKl4NPfv1eJ2p0= +github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v0.3.5/go.mod h1:Beh5cHIXJ0oWEDWk9lNFtuklCojLLQ5hl+LqSNTTs0I= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY= +github.com/aquilax/go-perlin v1.1.0 h1:Gg+3jQ24wT4Y5GI7TCRLmYarzUG0k+n/JATFqOimb7s= +github.com/aquilax/go-perlin v1.1.0/go.mod h1:z9Rl7EM4BZY0Ikp2fEN1I5mKSOJ26HQpk0O2TBdN2HE= 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/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= 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/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= @@ -20,16 +34,22 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/main.go b/main.go index 956d5c8..be87904 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,8 @@ import ( core "github.com/mw-felker/terra-major-api/pkg/core" sandboxes "github.com/mw-felker/terra-major-api/pkg/sandboxes/handlers" sandboxModels "github.com/mw-felker/terra-major-api/pkg/sandboxes/models" + terrains "github.com/mw-felker/terra-major-api/pkg/terrains/handlers" + terrainModels "github.com/mw-felker/terra-major-api/pkg/terrains/models" utils "github.com/mw-felker/terra-major-api/pkg/utils" ) @@ -23,6 +25,7 @@ func seedDb(app *core.App) { app.DB.AutoMigrate(&characterModels.Character{}) app.DB.AutoMigrate(&sandboxModels.Sandbox{}) app.DB.AutoMigrate(&sandboxModels.Instance{}) + app.DB.AutoMigrate(&terrainModels.TerrainChunkConfig{}) } func main() { @@ -65,6 +68,8 @@ func main() { app.Router.HandleFunc("/sandboxes/{sandboxId}/instances/{instanceId}", sandboxes.UpdateInstance(app)).Methods("PATCH") app.Router.HandleFunc("/sandboxes/{sandboxId}/instances/{instanceId}", sandboxes.ArchiveInstance(app)).Methods("DELETE") + app.Router.HandleFunc("/sandboxes/{sandboxId}/chunks", terrains.GetChunksBySandboxId(app)).Methods("GET") + corsObj := handlers.CORS(handlers.AllowedMethods([]string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"}), handlers.AllowedOrigins([]string{"*"}), handlers.AllowedHeaders([]string{"X-Requested-With", "Content-Type", "Authorization"})) diff --git a/pkg/characters/handlers/CreateCharacter.go b/pkg/characters/handlers/CreateCharacter.go index 342fc6f..56b7571 100644 --- a/pkg/characters/handlers/CreateCharacter.go +++ b/pkg/characters/handlers/CreateCharacter.go @@ -9,6 +9,7 @@ import ( characters "github.com/mw-felker/terra-major-api/pkg/characters/models" "github.com/mw-felker/terra-major-api/pkg/core" sandboxes "github.com/mw-felker/terra-major-api/pkg/sandboxes/models" + "github.com/mw-felker/terra-major-api/pkg/terrains" utils "github.com/mw-felker/terra-major-api/pkg/utils" ) @@ -56,6 +57,14 @@ func CreateCharacter(app *core.App) http.HandlerFunc { return } + chunks := terrains.GenerateChunksForSandbox(newSandbox.ID) + + chunkCreateResult := app.DB.Create(&chunks) + if chunkCreateResult.Error != nil { + http.Error(writer, chunkCreateResult.Error.Error(), http.StatusInternalServerError) + return + } + response, e := json.Marshal(newCharacter) if e != nil { utils.ReturnError(writer, e.Error()) diff --git a/pkg/core/app.go b/pkg/core/app.go index 53c2008..9b6b94a 100644 --- a/pkg/core/app.go +++ b/pkg/core/app.go @@ -2,15 +2,19 @@ package core import ( "fmt" + "log" + "github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos" "github.com/gorilla/mux" "github.com/mw-felker/terra-major-api/pkg/utils" "gorm.io/driver/postgres" "gorm.io/gorm" + "gorm.io/gorm/logger" ) type App struct { DB *gorm.DB + NoSQL *azcosmos.DatabaseClient Router *mux.Router } @@ -49,14 +53,53 @@ func connectToDb(dbName string) *gorm.DB { return db } +func connectToCosmos() (*azcosmos.DatabaseClient, error) { + COSMOS_DB_PORT := utils.GetEnv("COSMOS_DB_PORT", "8081") + COSMOS_DB_HOST := utils.GetEnv("COSMOS_DB_HOST", "cosmos") + url := "https://" + COSMOS_DB_HOST + ":" + COSMOS_DB_PORT + COSMOS_DB_PRIMARY_KEY := utils.GetEnv("COSMOS_DB_PRIMARY_KEY") + COSMOS_DB_NAME := utils.GetEnv("COSMOS_DB_NAME", "terramajor") + + cred, err := azcosmos.NewKeyCredential(COSMOS_DB_PRIMARY_KEY) + if err != nil { + log.Println("Failed to create Cosmos DB key credential:", err) + return nil, err + } + + client, err := azcosmos.NewClientWithKey(url, cred, nil) + if err != nil { + log.Println("Failed to create Cosmos client:", err) + return nil, err + } + + database, err := client.NewDatabase(COSMOS_DB_NAME) + if err != nil { + log.Println("Failed to create Cosmos DB database client:", err) + return nil, err + } + + return database, nil +} + func CreateApp() *App { fmt.Println("Starting up app...") var dbConnection = connectToDb("postgres") var POSTGRES_DATABASE = utils.GetEnv("POSTGRES_DATABASE", "terramajor") checkDbExistsAndCreate(dbConnection, POSTGRES_DATABASE) + db := connectToDb(POSTGRES_DATABASE) + db.Logger = logger.Default.LogMode(logger.Silent) + //db.Logger.LogMode(logger.Silent) + + noSqlClient, error := connectToCosmos() + if error != nil { + log.Println("Failed to get Cosmos DB database client:", error) + return nil + } + return &App{ DB: connectToDb(POSTGRES_DATABASE), + NoSQL: noSqlClient, Router: mux.NewRouter(), } } diff --git a/pkg/sandboxes/handlers/CreateSandbox.go b/pkg/sandboxes/handlers/CreateSandbox.go index 5d911bd..6456909 100644 --- a/pkg/sandboxes/handlers/CreateSandbox.go +++ b/pkg/sandboxes/handlers/CreateSandbox.go @@ -2,20 +2,34 @@ package handlers import ( "encoding/json" + "fmt" "net/http" "strings" + authClient "github.com/mw-felker/terra-major-api/pkg/auth/client" "github.com/mw-felker/terra-major-api/pkg/core" models "github.com/mw-felker/terra-major-api/pkg/sandboxes/models" + "github.com/mw-felker/terra-major-api/pkg/terrains" + utils "github.com/mw-felker/terra-major-api/pkg/utils" ) func CreateSandbox(app *core.App) http.HandlerFunc { return func(writer http.ResponseWriter, request *http.Request) { + + claims, claimsError := authClient.ParseAndValidateToken(request) + if claimsError != nil { + utils.ReturnError(writer, claimsError.Error(), http.StatusUnauthorized) + return + } + + accountId := claims.AccountId + //characterId := claims.CharacterId + decoder := json.NewDecoder(request.Body) var newSandbox models.Sandbox - err := decoder.Decode(&newSandbox) - if err != nil { - http.Error(writer, err.Error(), http.StatusBadRequest) + decoderError := decoder.Decode(&newSandbox) + if decoderError != nil { + http.Error(writer, decoderError.Error(), http.StatusBadRequest) return } @@ -24,16 +38,28 @@ func CreateSandbox(app *core.App) http.HandlerFunc { return } + newSandbox.AccountId = accountId + result := app.DB.Create(&newSandbox) if result.Error != nil { if strings.Contains(result.Error.Error(), "23505") { http.Error(writer, "A sandbox for this characterId already exists", http.StatusConflict) } else { - http.Error(writer, result.Error.Error(), http.StatusInternalServerError) } return } + chunks := terrains.GenerateChunksForSandbox(newSandbox.ID) + + // Print the chunks to the command line + fmt.Println(chunks) + + chunkCreateResult := app.DB.Create(&chunks) + if chunkCreateResult.Error != nil { + http.Error(writer, chunkCreateResult.Error.Error(), http.StatusInternalServerError) + return + } + response, e := json.Marshal(newSandbox) if e != nil { http.Error(writer, e.Error(), http.StatusInternalServerError) diff --git a/pkg/terrains/handlers/GetChunksBySandboxId.go b/pkg/terrains/handlers/GetChunksBySandboxId.go new file mode 100644 index 0000000..de0c6cb --- /dev/null +++ b/pkg/terrains/handlers/GetChunksBySandboxId.go @@ -0,0 +1,78 @@ +package handlers + +import ( + "encoding/json" + "net/http" + "strconv" + + "github.com/gorilla/mux" + "github.com/mw-felker/terra-major-api/pkg/core" + sandboxesModels "github.com/mw-felker/terra-major-api/pkg/sandboxes/models" + terrainModels "github.com/mw-felker/terra-major-api/pkg/terrains/models" + utils "github.com/mw-felker/terra-major-api/pkg/utils" +) + +func GetChunksBySandboxId(app *core.App) http.HandlerFunc { + return func(writer http.ResponseWriter, request *http.Request) { + + vars := mux.Vars(request) + sandboxId := vars["sandboxId"] + + query := request.URL.Query() + + xQuery, _ := strconv.ParseFloat(query.Get("x"), 64) + x := float32(xQuery) + + zQuery, _ := strconv.ParseFloat(query.Get("z"), 64) + z := float32(zQuery) + + y := float32(0) // all chunks have a 0 y value + + var queryPosition = sandboxesModels.Vector3{ + X: &x, + Y: &y, + Z: &z, + } + + if queryPosition.X == nil || queryPosition.Z == nil { + http.Error(writer, "x and z coordinates are required", http.StatusBadRequest) + return + } + + radius, err := strconv.ParseFloat(query.Get("radius"), 32) + if err != nil { + http.Error(writer, "Invalid radius", http.StatusBadRequest) + return + } + + var chunks []terrainModels.TerrainChunkConfig + result := app.DB.Raw(` + SELECT * FROM terrain_chunks + WHERE + SQRT( + POWER(CAST(position->>'x' AS FLOAT) - ?, 2) + + POWER(CAST(position->>'z' AS FLOAT) - ?, 2) + ) <= ? AND sandbox_id = ? + `, *queryPosition.X, *queryPosition.Z, radius, sandboxId).Scan(&chunks) + + if result.Error != nil { + http.Error(writer, result.Error.Error(), http.StatusInternalServerError) + return + } + + if len(chunks) == 0 { + http.Error(writer, "", http.StatusNotFound) + return + } + + response, err := json.Marshal(chunks) + if err != nil { + utils.ReturnError(writer, err.Error(), http.StatusInternalServerError) + return + } + + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + writer.Write(response) + } +} diff --git a/pkg/terrains/main.go b/pkg/terrains/main.go new file mode 100644 index 0000000..67797fe --- /dev/null +++ b/pkg/terrains/main.go @@ -0,0 +1,75 @@ +package terrains + +import ( + "log" + + "github.com/google/uuid" + sandboxModels "github.com/mw-felker/terra-major-api/pkg/sandboxes/models" + terrainModels "github.com/mw-felker/terra-major-api/pkg/terrains/models" +) + +const ( + chunksPerGeneration = 100 + seed = 1920 + frequency = 0.005 + gain = 0.001 + octaves = 3 + lacunarity = 2.0 + heightmapResolution = 513 + chunkDimension = 512 + chunkHeight = 64 + alphamapResolution = 512 + detailResolution = 512 + resolutionPerPatch = 16 +) + +func GenerateChunksForSandbox(sandboxId string) []*terrainModels.TerrainChunkConfig { + if sandboxId == "" { + log.Fatalln("Please provide a sandbox ID when storing chunks") + return nil + } + + chunks := generateChunks(sandboxId) + return chunks +} + +func floatPtr(f float32) *float32 { + return &f +} + +func generateChunks(sandboxId string) []*terrainModels.TerrainChunkConfig { + var terrainHeight = chunkHeight + var chunks []*terrainModels.TerrainChunkConfig + gridSize := int(chunksPerGeneration / 2) + offset := int(gridSize / 2) + + for i := -offset; i < offset; i++ { + for j := -offset; j < offset; j++ { + globalX := float32(i * chunkDimension) + globalZ := float32(j * chunkDimension) + position := sandboxModels.Vector3{ + X: &globalX, + Y: floatPtr(0), + Z: &globalZ, + } + newChunk := &terrainModels.TerrainChunkConfig{ + ID: uuid.New().String(), + Position: position, + Dimension: chunkDimension, + Height: terrainHeight, + DetailResolution: detailResolution, + ResolutionPerPatch: resolutionPerPatch, + HeightmapResolution: heightmapResolution, + AlphamapResolution: alphamapResolution, + Seed: seed, + Frequency: frequency, + Gain: gain, + Octaves: octaves, + Lacunarity: lacunarity, + SandboxId: sandboxId, + } + chunks = append(chunks, newChunk) + } + } + return chunks +} diff --git a/pkg/terrains/models/TerrainChunkConfig.go b/pkg/terrains/models/TerrainChunkConfig.go new file mode 100644 index 0000000..c4ff369 --- /dev/null +++ b/pkg/terrains/models/TerrainChunkConfig.go @@ -0,0 +1,35 @@ +package models + +import ( + "time" + + "github.com/google/uuid" + sandboxModels "github.com/mw-felker/terra-major-api/pkg/sandboxes/models" + "gorm.io/gorm" +) + +type Heightmap [][]float64 + +type TerrainChunkConfig struct { + ID string `gorm:"type:uuid;primary_key;unique;" json:"id"` + SandboxId string `gorm:"type:uuid;not null;" json:"sandboxId"` + Position sandboxModels.Vector3 `gorm:"type:jsonb;not null" json:"position"` + Dimension int `gorm:"type:int;not null" json:"dimension"` + Height int `gorm:"type:int;not null" json:"height"` + DetailResolution int `gorm:"type:int;not null" json:"detailResolution"` + ResolutionPerPatch int `gorm:"type:int;not null" json:"resolutionPerPatch"` + HeightmapResolution int `gorm:"type:int;not null" json:"heightmapResolution"` + AlphamapResolution int `gorm:"type:int;not null" json:"alphamapResolution"` + Seed int `gorm:"type:int;not null" json:"seed"` + Frequency float32 `gorm:"type:float;not null" json:"frequency"` + Gain float32 `gorm:"type:float;not null" json:"gain"` + Octaves int `gorm:"type:float;not null" json:"octaves"` + Lacunarity float32 `gorm:"type:float;not null" json:"lacunarity"` + Created time.Time `gorm:"autoCreateTime" json:"created"` + Updated time.Time `gorm:"autoUpdateTime" json:"updated"` +} + +func (chunk *TerrainChunkConfig) BeforeCreate(tx *gorm.DB) (err error) { + chunk.ID = uuid.New().String() + return +} diff --git a/pkg/utils/getEnv.go b/pkg/utils/getEnv.go index 282a613..19a0484 100644 --- a/pkg/utils/getEnv.go +++ b/pkg/utils/getEnv.go @@ -2,9 +2,12 @@ package utils import "os" -func GetEnv(key, fallback string) string { +func GetEnv(key string, fallback ...string) string { if value, ok := os.LookupEnv(key); ok { return value } - return fallback + if len(fallback) > 0 { + return fallback[0] + } + return "" // Default value if no fallback is provided }