From a380de3a44194ada6bc386e494aaf3f1eef8e2c4 Mon Sep 17 00:00:00 2001 From: Tony Bark Date: Thu, 2 May 2024 09:17:45 -0400 Subject: [PATCH] Mock FreeSO API - Until the real FreeSO API server is properly reconfigured, a mock API will take it's place using Mockoon. - Ported over a few elements from FSO.Common into the client. --- README.md | 12 +- docs/api.md | 859 ++++++++++++++++++ .../Admin/AdminEventsController.cs | 20 +- .../FSO.Server.Common.csproj | 5 +- server/README.md | 6 +- server/fsomockapi.json | 146 +++ server/tso.common/FSO.Common.csproj | 5 +- .../MeshSimplify/SymmetricMatrix.cs | 14 +- src/common/map.zig | 42 + src/common/render.zig | 34 + 10 files changed, 1114 insertions(+), 29 deletions(-) create mode 100644 docs/api.md create mode 100644 server/fsomockapi.json create mode 100644 src/common/map.zig create mode 100644 src/common/render.zig diff --git a/README.md b/README.md index 8126a3b..184e3f4 100644 --- a/README.md +++ b/README.md @@ -25,21 +25,25 @@ Will this succeed? *I have no idea*. I'm not much of a game developer, but that ## Requirements - The Sims Online -- Client: [Zig](https://ziglang.org/) 0.11 or newer -- API Server: [.NET 8.0](https://dotnet.microsoft.com/en-us/) or later +- Client + - OpenGL + - [Zig](https://ziglang.org/) 0.11 or newer +- API Server + - [.NET](https://dotnet.microsoft.com/en-us/) 8.0 or later + - [Mockoon](https://mockoon.com/) for mock APIs ## Getting Started 1. **Clone the Repository**: ```bash - git clone https://github.com/tonytins/ztso.git + git clone https://github.com/tonytins/mysimulation.git ``` 2. **Navigate to the Repository**: ```bash - cd ztso + cd mysimulation ``` 3. **Run the Examples**: Execute the code examples using the Zig compiler. For instance: diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..0335cd9 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,859 @@ +# FreeSO API + +## Table of Contents +1. [Overview](#overview) +2. [API](#api) + 1. [Avatars](#avatars) + 1. [Get Avatars By Page](#get-avatars-by-page) + 2. [Get Avatars By Neighborhood](#get-avatars-by-neighborhood) + 3. [Get Online Avatars](#get-online-avatars) + 4. [Get Avatars By IDs](#get-avatars-by-ids) + 5. [Get Avatars By User ID (Protected)](#get-avatars-by-user-id-protected) + 2. [Avatar](#avatar) + 1. [Get Avatar By ID](#get-avatar-by-id) + 2. [Get Avatar By Name](#get-avatar-by-name) + 3. [Lots](#lots) + 1. [Get Lots By Page](#get-lots-by-page) + 2. [Get Lots By Neighborhood](#get-lots-by-neighborhood) + 3. [Get Online Lots](#get-online-lots) + 4. [Lot](#lot) + 1. [Get Lot By ID](#get-lot-by-id) + 2. [Get Lot By Location](#get-lot-by-location) + 3. [Get Lot By Name](#get-lot-by-name) + 5. [Top 100](#top-100) + 1. [Get All Top 100s](#get-all-top-100s) + 2. [Get Top 100 By Category](#get-top-100-by-category) + 6. [Neighborhoods](#neighborhoods) + 1. [Get Neighborhoods](#get-neighborhoods) + 7. [Neighborhood](#neighborhood) + 1. [Get Neighborhood By ID](#get-neighborhood-by-id) + 2. [Get Neighborhood By Name](#get-neighborhood-by-name) + 8. [Bulletins](#bulletins) + 1. [Get Bulletins By Neighborhood](#get-bulletins-by-neighborhood) + 2. [Get Bulletins By Type](#get-bulletins-by-type) + 9. [Bulletin](#bulletin) + 1. [Get Bulletin By ID](#get-bulletin-by-id) + 10. [Election](#election) + 1. [Get Election By Neighborhood](#get-election-by-neighborhood) + 11. [OAuth](#oauth) + 1. [Get Token](#get-token) + 12. [City](#city) + 1. [city.json](#cityjson) + 13. [Media](#media) + 1. [Get Lot Thumbnail](#get-lot-thumbnail) +3. [Extending The API](#extending-the-api) +4. [Notable Projects Using The API](#notable-projects-using-the-api) + +# Overview +This document describes the resources that make up FreeSO's public API. It is currently in beta and subject to change at any time. + +The live server API, `api.freeso.org` can be accessed via HTTP or HTTPS. You should use HTTPS to access the live server API unless absolutely necessary. This documentation will include examples using the live server, but if you are building and testing new API features in a dev build, just replace `api.freeso.org` with whatever your API URL is (ex. `localhost:9000/userapi/city/1/city.json`). + +Feel free to update missing/incorrect information by [editing this page](https://github.com/riperiperi/FreeSO/wiki/Public-API/_edit). + +**For more information about some of the data returned by the API, please see [Public API Data Definitions](https://github.com/riperiperi/FreeSO/wiki/Public-API-Data-Definitions)** + +*** + +## Avatars +### Get Avatars By Page +``` +/userapi/city/{shardId}/avatars/page/{pageNum}?avatars_on_page={avatarsPerPage} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shardId` | `integer` | The value of `shard_id` in `fso_shards` for a city. This will likely always be `1`. | +| `pageNum` | `integer` | The page of avatars you'd like to request. pageNum `1` will give you the total number of pages. | +| `avatarsPerPage` | `integer` (Optional) | The number of avatars to return per page. Default is `100`, max is `500`. | + +#### Response +```json +{ + "page": 1, + "total_pages": 1, + "total_avatars": 1, + "avatars_on_page": 1, + "avatars": [ + { + "avatar_id": 887, + "shard_id": 1, + "name": "burglar cop", + "gender": 0, + "date": 1486420929, + "description": " the law is a suggestion\r\n but its a pretty good one tbh\r\n\r\n -me\r\n\r\ndont freak out if im just standing there starving im probably developing something worth dying for\r\n", + "current_job": 5, + "mayor_nhood": null + } + ] +} +``` +#### Live Response + + +### Get Avatars By Neighborhood +``` +/userapi/city/{shardId}/avatars/neighborhood/{nhoodId} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shardId` | `integer` | The value of `shard_id` in `fso_shards` for a city. This will likely always be `1`. | +| `nhoodId` | `integer` | The value of `neighborhood_id` in `fso_neighborhoods` for a neighborhood. | + +#### Response +```json +{ + "avatars": [ + { + "avatar_id": 887, + "shard_id": 1, + "name": "burglar cop", + "gender": 0, + "date": 1486420929, + "description": " the law is a suggestion\r\n but its a pretty good one tbh\r\n\r\n -me\r\n\r\ndont freak out if im just standing there starving im probably developing something worth dying for\r\n", + "current_job": 5, + "mayor_nhood": null + } + ] +} +``` +#### Live Response + + +### Get Online Avatars +``` +/userapi/avatars/online?compact={compactBool} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `compact` | `boolean` (Optional) | Compact returns `avatars_online_count` and an empty `avatars` array. Default is false. | + +#### Response +```json +{ + "avatars_online_count": 1, + "avatars": [ + { + "avatar_id": 1, + "name": "burglar cop", + "privacy_mode": 0, + "location": 13828398 + } + ] +} +``` +#### Live Response + + +### Get Avatars By IDs +``` +/userapi/avatars/?ids={avatarIds} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `avatarIds` | `string` | A list of `avatar_id`s from `fso_avatars` separated by commas. | + +#### Response +```json +{ + "avatars": [ + { + "avatar_id": 887, + "shard_id": 1, + "name": "burglar cop", + "gender": 0, + "date": 1486420929, + "description": " the law is a suggestion\n but its a pretty good one tbh\r\n\r\n -me\r\n\ndont freak out if im just standing there starving im probably developing something worth dying for\n", + "current_job": 5, + "mayor_nhood": null + } + ] +} +``` +#### Live Response + + +### Get Avatars By User ID (Protected) +``` +/userapi/user/avatars +``` +Returns an array of the avatars associated with a User ID. Requires a [valid token](#get-token) for authorization. + +#### Response +```json +{ + "avatars": [ + { + "avatar_id": 887, + "shard_id": 1, + "name": "burglar cop", + "gender": 0, + "date": 1486420929, + "description": " the law is a suggestion\n but its a pretty good one tbh\r\n\r\n -me\r\n\ndont freak out if im just standing there starving im probably developing something worth dying for\n", + "current_job": 5, + "mayor_nhood": null + } + ] +} +``` +#### Live Response +Send a GET request using something like [Postman](https://www.getpostman.com/downloads/) with an authorization header of type bearer token and a [valid token](#get-token) to + +## Avatar +### Get Avatar By ID +``` +/userapi/avatars/{avatarId} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `avatarId` | `integer` | The value of `avatar_id` in `fso_avatars` for an avatar. | + +#### Response +```json +{ + "avatar_id": 887, + "shard_id": 1, + "name": "burglar cop", + "gender": 0, + "date": 1486420929, + "description": " the law is a suggestion\r\n but its a pretty good one tbh\r\n\r\n -me\r\n\r\ndont freak out if im just standing there starving im probably developing something worth dying for\r\n", + "current_job": 5, + "mayor_nhood": null +} +``` +#### Live Response + + +### Get Avatar By Name +``` +/userapi/city/{shardId}/avatars/name/{avatarName} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shardId` | `integer` | The value of `shard_id` in `fso_shards` for a city. This will likely always be `1`. | +| `avatarName` | `string` | The value of `name` in `fso_avatars` for an avatar. **Warning: Make sure this string is URL encoded** | + +#### Response +```json +{ + "avatar_id": 887, + "shard_id": 1, + "name": "burglar cop", + "gender": 0, + "date": 1486420929, + "description": " the law is a suggestion\r\n but its a pretty good one tbh\r\n\r\n -me\r\n\r\ndont freak out if im just standing there starving im probably developing something worth dying for\r\n", + "current_job": 5, + "mayor_nhood": null +} +``` +#### Live Response + + +## Lots +### Get Lots By Page +``` +/userapi/city/{shardId}/lots/page/{pageNum}?lots_on_page={lotsPerPage} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shardId` | `integer` | The value of `shard_id` in `fso_shards` for a city. This will likely always be `1`. | +| `pageNum` | `integer` | The page of lots you'd like to request. pageNum `1` will give you the total number of pages. | +| `lotsPerPage` | `integer` (Optional) | The number of lots to return per page. Default is `100`, max is `500`. | + +#### Response +```json +{ + "page": 1, + "total_pages": 1, + "total_lots": 1, + "lots_on_page": 1, + "lots": [ + { + "lot_id": 6852, + "location": 13828398, + "name": "M.O.M.I. Headquarters", + "description": "", + "category": 5, + "admit_mode": 3, + "neighborhood_id": 54, + "avatars_in_lot": 0 + } + ] +} +``` +#### Live Response + + +### Get Lots By Neighborhood +``` +/userapi/city/{shardId}/lots/neighborhood/{nhoodId} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shardId` | `integer` | The value of `shard_id` in `fso_shards` for a city. This will likely always be `1`. | +| `nhoodId` | `integer` | The value of `neighborhood_id` in `fso_neighborhoods` for a neighborhood. | + +#### Response +```json +{ + "lots": [ + { + "lot_id": 6852, + "location": 13828398, + "name": "M.O.M.I. Headquarters", + "description": "", + "category": 5, + "admit_mode": 3, + "neighborhood_id": 54, + "avatars_in_lot": 0 + } + ] +} +``` +#### Live Response + + +### Get Online Lots +``` +/userapi/city/{shardId}/lots/online?compact={compactBool} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shardId` | `integer` | The value of `shard_id` in `fso_shards` for a city. This will likely always be `1`. | +| `compactBool` | `boolean` (Optional) | Compact returns `total_lots_online`, `total_avatars_in_lots_online` and an empty `lots` array. Default is false. | + +#### Response +```json +{ + "total_lots_online": 1, + "total_avatars_in_lots_online": 1, + "lots": [ + { + "location": 13828398, + "name": "M.O.M.I. Headquarters", + "description": "", + "category": 5, + "neighborhood_id": 54, + "avatars_in_lot": 0 + } + ] +} +``` +#### Live Response + + +### Get Lots By IDs +``` +/userapi/lots?ids={lotIds} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `lotIds` | `string` | A list of `lot_id`s from `fso_lots` separated by commas. | + +#### Response +```json +{ + "lots": [ + { + "lot_id": 6852, + "shard_id": 1, + "owner_id": 887, + "roommates": [ + 887 + ], + "location": 13828398, + "name": "M.O.M.I. Headquarters", + "description": "", + "location": 13828398, + "neighborhood_id": 54, + "created_date": 1518961270, + "category": 5, + "skill_mode": 0, + "admit_mode": 1 + } + ] +} +``` +#### Live Response + + +## Lot +### Get Lot By ID +``` +/userapi/lots/{lotId} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `lotId` | `integer` | The value of `lot_id` in `fso_lots` for a lot. | + +#### Response +```json +{ + "lot_id": 6852, + "shard_id": 1, + "owner_id": 887, + "roommates": [ + 887 + ], + "name": "M.O.M.I. Headquarters", + "description": "", + "location": 13828398, + "neighborhood_id": 54, + "created_date": 1518961270, + "category": 5, + "skill_mode": 0, + "admit_mode": 1 +} +``` +#### Live Response + + +### Get Lot By Location +``` +/userapi/city/{shardId}/lots/location/{locationId} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shardId` | `integer` | The value of `shard_id` in `fso_shards` for a city. This will likely always be `1`. | +| `locationId` | `integer` | The value of `location` in `fso_lots` for a lot. | + +#### Response +```json +{ + "lot_id": 6852, + "shard_id": 1, + "owner_id": 887, + "roommates": [ + 887 + ], + "name": "M.O.M.I. Headquarters", + "description": "", + "location": 13828398, + "neighborhood_id": 54, + "created_date": 1518961270, + "category": 5, + "skill_mode": 0, + "admit_mode": 1 +} +``` +#### Live Response + + +### Get Lot By Name +``` +/userapi/city/{shardId}/lots/name/{lotName} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shardId` | `integer` | The value of `shard_id` in `fso_shards` for a city. This will likely always be `1`. | +| `lotName` | `string` | The value of `name` in `fso_lots` for a lot. **Warning: Make sure this string is URL encoded** | + +#### Response +```json +{ + "lot_id": 6852, + "shard_id": 1, + "owner_id": 887, + "roommates": [ + 887 + ], + "name": "M.O.M.I. Headquarters", + "description": "", + "location": 13828398, + "neighborhood_id": 54, + "created_date": 1518961270, + "category": 5, + "skill_mode": 0, + "admit_mode": 1 +} +``` +#### Live Response + + +## Top 100 +### Get All Top 100s +``` +/userapi/city/{shardId}/lots/top100/all +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shardId` | `integer` | The value of `shard_id` in `fso_shards` for a city. This will likely always be `1`. | + +#### Response +```json +{ + "lots": [ + { + "category": 5, + "rank": 1, + "shard_id": 1, + "lot_name": "M.O.M.I. Headquarters", + "lot_location": 13828398, + "lot_id": 6852 + } + ] +} +``` +#### Live Response + + +### Get Top 100 By Category +``` +/userapi/city/{shardId}/lots/top100/category/{lotCategory} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shardId` | `integer` | The value of `shard_id` in `fso_shards` for a city. This will likely always be `1`. | +| `lotCategory` | `integer` | The category type (1-11) | + +#### Response +```json +{ + "lots": [ + { + "category": 5, + "rank": 1, + "shard_id": 1, + "lot_name": "M.O.M.I. Headquarters", + "lot_location": 13828398, + "lot_id": 6852 + } + ] +} +``` +#### Live Response + + +## Neighborhoods +### Get Neighborhoods +``` +/userapi/city/{shardId}/neighborhoods/all +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shardId` | `integer` | The value of `shard_id` in `fso_shards` for a city. This will likely always be `1`. | + +#### Response +```json +{ + "neighborhoods": [ + { + "neighborhood_id": 54, + "name": "D.A.M.N.", + "description": "Fully known as the D.A.D.D.I. And M.O.M.I. Neighborhood. The home of the Sunrise Crater government, who have the final say over all decisions and neighborhoods despite never being elected.\r\n\r\nFamous for its huge annual events, incredibly high rate of arson and non-existent firefighter response, this location has a higher mortality rate for visitors than any other mountain on the planet.", + "color": 0, + "town_hall_id": 6634, + "icon_url": null, + "mayor_id": 108523, + "mayor_elected_date": 1565012163, + "election_cycle_id": null + } + ] +} +``` +#### Live Response + + +## Neighborhood +### Get Neighborhood By ID +``` +/userapi/neighborhoods/{nhoodId} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `nhoodId` | `integer` | The value of `neighborhood_id` in `fso_neighborhoods` for a neighborhood. | + +#### Response +```json +{ + "neighborhood_id": 54, + "name": "D.A.M.N.", + "description": "Fully known as the D.A.D.D.I. And M.O.M.I. Neighborhood. The home of the Sunrise Crater government, who have the final say over all decisions and neighborhoods despite never being elected.\r\n\r\nFamous for its huge annual events, incredibly high rate of arson and non-existent firefighter response, this location has a higher mortality rate for visitors than any other mountain on the planet.", + "color": 0, + "town_hall_id": 6634, + "icon_url": null, + "mayor_id": 108523, + "mayor_elected_date": 1565012163, + "election_cycle_id": null +} +``` +#### Live Response + + +### Get Neighborhood By Name +``` +/userapi/neighborhoods/{nhoodName} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `nhoodName` | `string` | The value of `name` in `fso_neighborhoods` for a neighborhood. **Warning: Make sure this string is URL encoded** | + +#### Response +```json +{ + "neighborhood_id": 54, + "name": "D.A.M.N.", + "description": "Fully known as the D.A.D.D.I. And M.O.M.I. Neighborhood. The home of the Sunrise Crater government, who have the final say over all decisions and neighborhoods despite never being elected.\r\n\r\nFamous for its huge annual events, incredibly high rate of arson and non-existent firefighter response, this location has a higher mortality rate for visitors than any other mountain on the planet.", + "color": 0, + "town_hall_id": 6634, + "icon_url": null, + "mayor_id": 108523, + "mayor_elected_date": 1565012163, + "election_cycle_id": null +} +``` +#### Live Response + + +## Bulletins +### Get Bulletins By Neighborhood +``` +/userapi/neighborhood/{nhoodId}/bulletins +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `nhoodId` | `integer` | The value of `neighborhood_id` in `fso_neighborhoods` for a neighborhood. | + +#### Response +```json +{ + "bulletins": [ + { + "bulletin_id": 241, + "neighborhood_id": 54, + "avatar_id": 887, + "title": "Why are we still here?", + "body": "Just to Suffer?", + "date": 1561318161, + "flags": 0, + "lot_id": 13828399, + "type": 0 + } + ] +} +``` +#### Live Response + + +### Get Bulletins By Type +``` +/userapi/neighborhood/{nhoodId}/bulletins/type/{bulletinType} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `nhoodId` | `integer` | The value of `neighborhood_id` in `fso_neighborhoods` for a neighborhood. | +| `bulletinType` | `integer` | `0` - Mayor posts, `1` - System messages, `2` - Community posts. **Warning: System messages may reference game assets instead of providing a human readable bulletin.** | + +#### Response +```json +{ + "bulletins": [ + { + "bulletin_id": 241, + "neighborhood_id": 54, + "avatar_id": 887, + "title": "Why are we still here?", + "body": "Just to Suffer?", + "date": 1561318161, + "flags": 0, + "lot_id": 13828399, + "type": 0 + } + ] +} +``` +#### Live Response + + +## Bulletin +### Get Bulletin By ID +``` +/userapi/neighborhood/{nhoodId}/bulletins/{bulletinId} +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `nhoodId` | `integer` | The value of `neighborhood_id` in `fso_neighborhoods` for a neighborhood. | +| `bulletinId` | `integer` | The value of `bulletin_id` in `fso_bulletin_posts` for a bulletin. | + +#### Response +```json +{ + "bulletin_id": 241, + "neighborhood_id": 54, + "avatar_id": 887, + "title": "Why are we still here?", + "body": "Just to Suffer?", + "date": 1561318161, + "flags": 0, + "lot_id": 13828399, + "type": 0 +} +``` +#### Live Response + + +## Election +### Get Election By Neighborhood +``` +/userapi/neighborhood/{nhoodId}/elections +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `nhoodId` | `integer` | The value of `neighborhood_id` in `fso_neighborhoods` for a neighborhood. | + +#### Response +```json +{ + "current_state": 1, + "neighborhood_id": 54, + "start_date": 1565630999, + "end_date": 1566062999, + "candidates": [] +} +``` +```json +{ + "error": "Election cycle not found" +} +``` +#### Live Response + + +## OAuth +### Get Token +``` +/userapi/oauth/token +``` +> Warning: Access to this endpoint may be restricted by URL/IP at any time. + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `username` | `string` | The value of `neighborhood_id` in `fso_neighborhoods` for a neighborhood. | +| `password` | `string` | The value of `neighborhood_id` in `fso_neighborhoods` for a neighborhood. | +| `permission_level` | `integer` | The level of account access requested for the token (1-4). 1 - Read, 2 - Update, 3 - Write, 4 - Delete | + +#### Response +```json +{ + "access_token": "ROoPRE007bqYBABGylS3TJREv8kOh49E6z7Qa2wXBryCxcRn8NFWrV48SNTKVL1K7wkwAEsqeKMHoIi6F4WOkZYUiKZ8ar0II3JqOZB9db3rgfHpZELcYvsCNM0CBy4pIaofhnoj2qI4JVy7mq27i9O0ZiIMLB9JLksxsmMAMefm8482VU5RjhDQRX16jFNjoEK8Rtb3rBJq340LCeAA9XOgnisG4iwjeaK1zjgU93i8VCe1GTpCowS5C9UX2", + "expires_in": 3600 +} +``` +#### Live Response: +Send a `form-data` POST containing the parameters using something like [Postman](https://www.getpostman.com/downloads/) to + +## City +### city.json +``` +/userapi/city/{shardId}/city.json +``` +Returns every reserved lot, its name, online lots, and all online lot's populations. + +> **Warning:** This endpoint may be deprecated in favor of recent API additions. You should migrate existing projects to use them. + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shardId` | `integer` | The value of `shard_id` in `fso_shards` for a city. This will likely always be `1`. | + +#### Response Description +| Name | Type | Description | +| -- | -- | --------- | +| `names` | `array[string]` | An array of every lot name in alphabetical order. | +| `reservedLots` | `array[integer]` | An array of every reserved lot's location (the index matches up with the names array). | +| `activeLots` | `array[integer]` | An array of lot locations for lots that are open. | +| `onlineCount` | `array[integer]` | An array of lot population for lots that are open (the index matches up with the activeLots array). | + +#### Response +```json +{ + "names": [ + "Sunrise Crater Town Hall", + "M.O.M.I. Headquarters" + ], + "reservedLots": [ + 13828397, + 13828398 + ], + "activeLots": [ + 13828397 + ], + "onlineCount": [ + 10 + ] +} +``` +#### Live Response + + +## Media +### Get Lot Thumbnail +``` +/userapi/city/{shardId}/{lotLocation}.png +``` + +#### Parameters +| Name | Type | Description | +| ---- | ---- | ----------- | +| `shardId` | `integer` | The value of `shard_id` in `fso_shards` for a city. This will likely always be `1`. | +| `lotLocation` | `integer` | The location of a reserved lot. | + +#### Response +![M.O.M.I. Headquarters thumbnail](https://api.freeso.org/userapi/city/1/13828398.png) +#### Live Response + + +*** + +# Extending The API +If the API is missing some data you think would be beneficial, you can open an [issue](https://github.com/riperiperi/FreeSO/issues) to discuss it, but the best solution would be to submit a [pull request](https://github.com/riperiperi/FreeSO/pulls) yourself. [This PR](https://github.com/riperiperi/FreeSO/pull/152) by [@Cowplant-Simmer-Collin](https://github.com/Cowplant-Simmer-Collin) is a great example of how to add new API features. + +# Notable Projects Using The API +The following are popular projects known to consume the API. They should be notified of any breaking changes. Feel free to add your own to this list. +* [TSOMania](http://www.tsomania.net/) +* [FreeSO Dashboard](https://dashboard.thecode.house) [@dotequals](https://github.com/dotequals) +* [FreeSO Notifier](https://discord.gg/KuzzJZ7) - Nebulae#0666 \ No newline at end of file diff --git a/server/FSO.Server.Api.Core/Controllers/Admin/AdminEventsController.cs b/server/FSO.Server.Api.Core/Controllers/Admin/AdminEventsController.cs index 45ca1bb..5eab7b1 100755 --- a/server/FSO.Server.Api.Core/Controllers/Admin/AdminEventsController.cs +++ b/server/FSO.Server.Api.Core/Controllers/Admin/AdminEventsController.cs @@ -25,17 +25,15 @@ namespace FSO.Server.Api.Core.Controllers.Admin if (order == null) order = "start_day"; var api = Api.INSTANCE; api.DemandModerator(Request); - using (var da = api.DAFactory.Get()) + using var da = api.DAFactory.Get(); + + if (limit > 100) { - - if (limit > 100) - { - limit = 100; - } - - var result = da.Events.All((int)offset, (int)limit, order); - return ApiResponse.PagedList(Request, HttpStatusCode.OK, result); + limit = 100; } + + var result = da.Events.All((int)offset, (int)limit, order); + return ApiResponse.PagedList(Request, HttpStatusCode.OK, result); } [HttpGet("presets")] @@ -50,7 +48,7 @@ namespace FSO.Server.Api.Core.Controllers.Admin } [HttpPost("presets")] - public IActionResult CreatePreset([FromBody]PresetCreateModel request) + public IActionResult CreatePreset([FromBody] PresetCreateModel request) { var api = Api.INSTANCE; api.DemandModerator(Request); @@ -104,7 +102,7 @@ namespace FSO.Server.Api.Core.Controllers.Admin // POST admin/updates (start update generation) [HttpPost] - public IActionResult Post([FromBody]EventCreateModel request) + public IActionResult Post([FromBody] EventCreateModel request) { var api = Api.INSTANCE; api.DemandModerator(Request); diff --git a/server/FSO.Server.Common/FSO.Server.Common.csproj b/server/FSO.Server.Common/FSO.Server.Common.csproj index a69ae16..891c90a 100644 --- a/server/FSO.Server.Common/FSO.Server.Common.csproj +++ b/server/FSO.Server.Common/FSO.Server.Common.csproj @@ -1,6 +1,6 @@  - net45 + net45;net8.0 Library false true @@ -11,7 +11,8 @@ MinimumRecommendedRules.ruleset - + ..\packages/Newtonsoft.Json.13.0.1/lib/net45/Newtonsoft.Json.dll True diff --git a/server/README.md b/server/README.md index 7fe71ce..1ca9fa4 100644 --- a/server/README.md +++ b/server/README.md @@ -8,6 +8,6 @@ As the API server is already complete, zTSO's client and server will have separa ## Support Cycle -| Version | Release Date | Type | End of Support | -| ------- | ------------ | ---- | -------------- | -| 0.88 | March 31 | LTS | TBA | +| Version | Release Date | Type | End of Support | +| ------- | ------------ | ---- | ------------------ | +| 0.88 | March 31 | LTS | January 10th, 2027 | diff --git a/server/fsomockapi.json b/server/fsomockapi.json new file mode 100644 index 0000000..f50d13d --- /dev/null +++ b/server/fsomockapi.json @@ -0,0 +1,146 @@ +{ + "uuid": "2addc65d-3a58-4d34-8aab-8376800669de", + "lastMigration": 32, + "name": "FreeSO API", + "endpointPrefix": "api", + "latency": 0, + "port": 3001, + "hostname": "", + "folders": [], + "routes": [ + { + "uuid": "bd0b74a7-5b82-4934-bd6f-13b69df8b7f0", + "type": "http", + "documentation": "Returns every reserved lot, its name, online lots, and all online lot's populations.", + "method": "get", + "endpoint": "city/1", + "responses": [ + { + "uuid": "d8127941-3c34-4c78-9737-572ccfa112fa", + "body": "{\n \"names\": [\n \"Town Hall\",\n \"M.O.M.I. Headquarters\"\n ],\n \"reservedLots\": [\n 13828397,\n 13828398\n ],\n \"activeLots\": [\n 13828397\n ],\n \"onlineCount\": [\n 10\n ]\n}", + "latency": 0, + "statusCode": 200, + "label": "", + "headers": [], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": true, + "crudKey": "id", + "callbacks": [] + } + ], + "responseMode": null + }, + { + "uuid": "f3fb2f37-5402-4547-8781-8791a8795997", + "type": "http", + "documentation": "OAuth Reponse", + "method": "get", + "endpoint": "oauth/token", + "responses": [ + { + "uuid": "dad8bcb1-bf62-4eaf-9ad7-53ec5bf0021d", + "body": "{\n \"access_token\": \"ROoPRE007bqYBABGylS3TJREv8kOh49E6z7Qa2wXBryCxcRn8NFWrV48SNTKVL1K7wkwAEsqeKMHoIi6F4WOkZYUiKZ8ar0II3JqOZB9db3rgfHpZELcYvsCNM0CBy4pIaofhnoj2qI4JVy7mq27i9O0ZiIMLB9JLksxsmMAMefm8482VU5RjhDQRX16jFNjoEK8Rtb3rBJq340LCeAA9XOgnisG4iwjeaK1zjgU93i8VCe1GTpCowS5C9UX2\",\n \"expires_in\": 3600\n}", + "latency": 0, + "statusCode": 200, + "label": "OAuth", + "headers": [], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": true, + "crudKey": "id", + "callbacks": [] + } + ], + "responseMode": null + }, + { + "uuid": "eb27265e-acbf-4d0e-84cc-b1ffc573bc02", + "type": "http", + "documentation": "", + "method": "get", + "endpoint": "city/1/avatars/456", + "responses": [ + { + "uuid": "30119a6a-e6ae-4afc-8e54-d2b42dbf4da8", + "body": "{\n \"avatar_id\": 456,\n \"shard_id\": 1,\n \"name\": \"Tony Bark\",\n \"gender\": 0,\n \"date\": 1486420929,\n \"description\": \"Arf! That's me. Tony Bark.\",\n \"current_job\": 5,\n \"mayor_nhood\": null\n}", + "latency": 0, + "statusCode": 200, + "label": "", + "headers": [], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": true, + "crudKey": "id", + "callbacks": [] + } + ], + "responseMode": null + } + ], + "rootChildren": [ + { + "type": "route", + "uuid": "bd0b74a7-5b82-4934-bd6f-13b69df8b7f0" + }, + { + "type": "route", + "uuid": "f3fb2f37-5402-4547-8781-8791a8795997" + }, + { + "type": "route", + "uuid": "eb27265e-acbf-4d0e-84cc-b1ffc573bc02" + } + ], + "proxyMode": false, + "proxyHost": "", + "proxyRemovePrefix": false, + "tlsOptions": { + "enabled": false, + "type": "CERT", + "pfxPath": "", + "certPath": "", + "keyPath": "", + "caPath": "", + "passphrase": "" + }, + "cors": true, + "headers": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "proxyReqHeaders": [ + { + "key": "", + "value": "" + } + ], + "proxyResHeaders": [ + { + "key": "", + "value": "" + } + ], + "data": [], + "callbacks": [] +} \ No newline at end of file diff --git a/server/tso.common/FSO.Common.csproj b/server/tso.common/FSO.Common.csproj index 66b0fba..888cc32 100755 --- a/server/tso.common/FSO.Common.csproj +++ b/server/tso.common/FSO.Common.csproj @@ -44,7 +44,7 @@ MinimumRecommendedRules.ruleset - net45 + net45;net8.0 false @@ -87,9 +87,8 @@ + - - diff --git a/server/tso.common/MeshSimplify/SymmetricMatrix.cs b/server/tso.common/MeshSimplify/SymmetricMatrix.cs index 23b0be3..50814f5 100755 --- a/server/tso.common/MeshSimplify/SymmetricMatrix.cs +++ b/server/tso.common/MeshSimplify/SymmetricMatrix.cs @@ -2,8 +2,9 @@ { public class SymmetricMatrix { - public SymmetricMatrix(double c) { - for (int i=0; i<10; i++) m[i] = c; + public SymmetricMatrix(double c) + { + for (int i = 0; i < 10; i++) m[i] = c; } @@ -13,9 +14,9 @@ double m44) { m[0] = m11; m[1] = m12; m[2] = m13; m[3] = m14; - m[4] = m22; m[5] = m23; m[6] = m24; - m[7] = m33; m[8] = m34; - m[9] = m44; + m[4] = m22; m[5] = m23; m[6] = m24; + m[7] = m33; m[8] = m34; + m[9] = m44; } // Make plane @@ -28,7 +29,8 @@ m[9] = d * d; } - public double this[int c] { + public double this[int c] + { get { return m[c]; } set { m[c] = value; } } diff --git a/src/common/map.zig b/src/common/map.zig new file mode 100644 index 0000000..80dfe42 --- /dev/null +++ b/src/common/map.zig @@ -0,0 +1,42 @@ +pub const LotCategory = enum(u32) { + none = 0, + money = 1, + offbeat = 2, + romance = 3, + services = 4, + shopping = 5, + skills = 6, + welcome = 7, + games = 8, + entertainment = 9, + residence = 10, + community = 11, //cannot be set by users + + recent = 255, //for filter searches +}; + +pub const Top100Category = enum(32) { + lot_money = 1, + lot_offbeat = 2, + lot_romance = 3, + lot_services = 4, + lot_shopping = 5, + lot_skills = 6, + lot_welcome = 7, + lot_games = 8, + lot_entertainment = 9, + lot_residence = 10, + avatar_most_famous = 11, + avatar_best_karma = 12, + avatar_friendliest = 13, + avatar_most_infamous = 14, + avatar_meanest = 15, +}; + +pub const UserReferenceType = enum(32) { + EA = 1, + MAXIS = 2, + MOMI = 3, + TSO = 4, + AVATAR = 5, +}; diff --git a/src/common/render.zig b/src/common/render.zig new file mode 100644 index 0000000..7eb93d5 --- /dev/null +++ b/src/common/render.zig @@ -0,0 +1,34 @@ +pub const CursorType = enum { + Normal, + ArrowUp, + ArrowUpLeft, + ArrowUpRight, + ArrowDown, + ArrowDownLeft, + ArrowDownRight, + ArrowLeft, + ArrowRight, + LiveNothing, + LiveObjectUnavail, + LivePerson, + IBeam, + + SimsRotate, + SimsRotateNE, + SimsRotateSE, + SimsRotateSW, + SimsRotateNW, + + SimsMove, + SimsPlace, + + Hourglass, + + LiveObjectAvail, + LiveObject1Star, + LiveObject2Star, + LiveObject3Star, + LiveObject4Star, + LiveObject5Star, + LiveObjectSpecial, +};