stuff
This commit is contained in:
parent
7b512e78d5
commit
305b2bed4a
|
@ -1,4 +1,6 @@
|
|||
using Dalamud.Game.Command;
|
||||
using Dalamud.Utility;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
|
||||
namespace OrangeGuidanceTomestone;
|
||||
|
||||
|
@ -19,16 +21,47 @@ internal class Commands : IDisposable {
|
|||
|
||||
private void OnCommand(string command, string arguments) {
|
||||
switch (arguments) {
|
||||
case "ban":
|
||||
case "ban": {
|
||||
var name = this.Plugin.DataManager.GetExcelSheet<TerritoryType>()?.GetRow(this.Plugin.ClientState.TerritoryType)
|
||||
?.PlaceName
|
||||
.Value
|
||||
?.Name
|
||||
?.ToDalamudString()
|
||||
.TextValue;
|
||||
|
||||
if (this.Plugin.Config.BannedTerritories.Contains(this.Plugin.ClientState.TerritoryType)) {
|
||||
this.Plugin.ChatGui.Print($"{name} is already on the ban list.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.Plugin.Config.BannedTerritories.Add(this.Plugin.ClientState.TerritoryType);
|
||||
this.Plugin.SaveConfig();
|
||||
this.Plugin.ChatGui.Print($"Added {name} to the ban list.");
|
||||
|
||||
this.Plugin.Messages.RemoveVfx();
|
||||
this.Plugin.Messages.Clear();
|
||||
break;
|
||||
case "unban":
|
||||
}
|
||||
case "unban": {
|
||||
var name = this.Plugin.DataManager.GetExcelSheet<TerritoryType>()?.GetRow(this.Plugin.ClientState.TerritoryType)
|
||||
?.PlaceName
|
||||
.Value
|
||||
?.Name
|
||||
?.ToDalamudString()
|
||||
.TextValue;
|
||||
|
||||
if (!this.Plugin.Config.BannedTerritories.Contains(this.Plugin.ClientState.TerritoryType)) {
|
||||
this.Plugin.ChatGui.Print($"{name} is not on the ban list.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.Plugin.Config.BannedTerritories.Remove(this.Plugin.ClientState.TerritoryType);
|
||||
this.Plugin.SaveConfig();
|
||||
this.Plugin.ChatGui.Print($"Removed {name} from the ban list.");
|
||||
|
||||
this.Plugin.Messages.SpawnVfx();
|
||||
break;
|
||||
}
|
||||
case "refresh":
|
||||
this.Plugin.Messages.SpawnVfx();
|
||||
break;
|
||||
|
|
|
@ -8,4 +8,7 @@ public class Configuration : IPluginConfiguration {
|
|||
|
||||
public string ApiKey { get; set; } = string.Empty;
|
||||
public HashSet<uint> BannedTerritories { get; set; } = new();
|
||||
public bool DisableTrials = true;
|
||||
public bool DisableDeepDungeon = true;
|
||||
public bool RemoveGlow = true;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Numerics;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Logging;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Newtonsoft.Json;
|
||||
using OrangeGuidanceTomestone.Helpers;
|
||||
|
||||
|
@ -15,9 +16,22 @@ internal class Messages : IDisposable {
|
|||
private Dictionary<Guid, Message> Current { get; } = new();
|
||||
private Queue<Message> SpawnQueue { get; } = new();
|
||||
|
||||
private HashSet<uint> Trials { get; } = new();
|
||||
private HashSet<uint> DeepDungeons { get; } = new();
|
||||
|
||||
internal Messages(Plugin plugin) {
|
||||
this.Plugin = plugin;
|
||||
|
||||
foreach (var cfc in this.Plugin.DataManager.GetExcelSheet<ContentFinderCondition>()!) {
|
||||
if (cfc.ContentType.Row == 4) {
|
||||
this.Trials.Add(cfc.TerritoryType.Row);
|
||||
}
|
||||
|
||||
if (cfc.ContentType.Row == 21) {
|
||||
this.DeepDungeons.Add(cfc.TerritoryType.Row);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.Plugin.Config.ApiKey != string.Empty) {
|
||||
this.SpawnVfx();
|
||||
}
|
||||
|
@ -34,7 +48,7 @@ internal class Messages : IDisposable {
|
|||
this.Plugin.ClientState.Login -= this.SpawnVfx;
|
||||
this.Plugin.Framework.Update -= this.HandleSpawnQueue;
|
||||
|
||||
this.RemoveVfx(null, null);
|
||||
this.RemoveVfx();
|
||||
}
|
||||
|
||||
private unsafe void HandleSpawnQueue(Framework framework) {
|
||||
|
@ -42,10 +56,10 @@ internal class Messages : IDisposable {
|
|||
return;
|
||||
}
|
||||
|
||||
PluginLog.Log($"spawning vfx for {message.Id}");
|
||||
PluginLog.Debug($"spawning vfx for {message.Id}");
|
||||
var rotation = Quaternion.CreateFromYawPitchRoll(message.Yaw, 0, 0);
|
||||
if (this.Plugin.Vfx.SpawnStatic(message.Id, VfxPath, message.Position, rotation) == null) {
|
||||
PluginLog.Log("trying again");
|
||||
PluginLog.Debug("trying again");
|
||||
this.SpawnQueue.Enqueue(message);
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +78,14 @@ internal class Messages : IDisposable {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.Plugin.Config.DisableTrials && this.Trials.Contains(territory)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.Plugin.Config.DisableDeepDungeon && this.DeepDungeons.Contains(territory)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.RemoveVfx(null, null);
|
||||
|
||||
Task.Run(async () => {
|
||||
|
@ -95,6 +117,12 @@ internal class Messages : IDisposable {
|
|||
this.Plugin.Vfx.RemoveAll();
|
||||
}
|
||||
|
||||
internal void Clear() {
|
||||
this.CurrentMutex.Wait();
|
||||
this.Current.Clear();
|
||||
this.CurrentMutex.Release();
|
||||
}
|
||||
|
||||
internal IEnumerable<Message> Nearby() {
|
||||
if (this.Plugin.ClientState.LocalPlayer is not { } player) {
|
||||
return Array.Empty<Message>();
|
||||
|
|
|
@ -58,15 +58,15 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.8"/>
|
||||
<PackageReference Include="Fody" Version="6.6.3" PrivateAssets="all"/>
|
||||
<PackageReference Include="Resourcer.Fody" Version="1.8.0" PrivateAssets="all"/>
|
||||
<PackageReference Include="YamlDotNet" Version="12.0.0"/>
|
||||
<PackageReference Include="DalamudPackager" Version="2.1.8" />
|
||||
<PackageReference Include="Fody" Version="6.6.3" PrivateAssets="all" />
|
||||
<PackageReference Include="Resourcer.Fody" Version="1.8.0" PrivateAssets="all" />
|
||||
<PackageReference Include="YamlDotNet" Version="12.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="../server/packs/*.yaml" LinkBase="packs"/>
|
||||
<EmbeddedResource Remove="../server/packs/*_old*.yaml"/>
|
||||
<EmbeddedResource Include="../server/packs/*.yaml" LinkBase="packs" />
|
||||
<EmbeddedResource Remove="../server/packs/*_old*.yaml" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -3,6 +3,7 @@ using Dalamud.Game;
|
|||
using Dalamud.Game.ClientState;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.Command;
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.Plugin;
|
||||
|
||||
|
@ -14,6 +15,9 @@ public class Plugin : IDalamudPlugin {
|
|||
[PluginService]
|
||||
internal DalamudPluginInterface Interface { get; init; }
|
||||
|
||||
[PluginService]
|
||||
internal ChatGui ChatGui { get; init; }
|
||||
|
||||
[PluginService]
|
||||
internal ClientState ClientState { get; init; }
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ internal class MainWindow {
|
|||
this.Tabs = new List<ITab> {
|
||||
new Write(this.Plugin),
|
||||
new MessageList(this.Plugin),
|
||||
new Settings(this.Plugin),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
using ImGuiNET;
|
||||
|
||||
namespace OrangeGuidanceTomestone.Ui.MainWindowTabs;
|
||||
|
||||
internal class Settings : ITab {
|
||||
public string Name => "Settings";
|
||||
|
||||
private Plugin Plugin { get; }
|
||||
|
||||
internal Settings(Plugin plugin) {
|
||||
this.Plugin = plugin;
|
||||
}
|
||||
|
||||
public void Draw() {
|
||||
var anyChanged = false;
|
||||
var vfx = false;
|
||||
|
||||
anyChanged |= vfx |= ImGui.Checkbox("Disable in trials", ref this.Plugin.Config.DisableTrials);
|
||||
anyChanged |= vfx |= ImGui.Checkbox("Disable in Deep Dungeons", ref this.Plugin.Config.DisableDeepDungeon);
|
||||
anyChanged |= vfx |= ImGui.Checkbox("Remove glow effect from signs", ref this.Plugin.Config.RemoveGlow);
|
||||
|
||||
if (anyChanged) {
|
||||
this.Plugin.SaveConfig();
|
||||
}
|
||||
|
||||
if (vfx) {
|
||||
this.Plugin.Messages.RemoveVfx();
|
||||
this.Plugin.Messages.Clear();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1035,6 +1035,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"bytes",
|
||||
"chrono",
|
||||
"rand",
|
||||
"serde",
|
||||
|
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
anyhow = "1"
|
||||
base64 = "0.13"
|
||||
bytes = "1"
|
||||
chrono = "0.4"
|
||||
rand = "0.8"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
create table extra_tokens (
|
||||
id text not null primary key,
|
||||
extra integer not null
|
||||
);
|
|
@ -288,6 +288,7 @@ words:
|
|||
- core
|
||||
- fingers
|
||||
- horns
|
||||
- feet
|
||||
|
||||
- name: Affinities
|
||||
words:
|
||||
|
|
|
@ -48,4 +48,6 @@ pub struct RetrievedMessageTerritory {
|
|||
pub positive_votes: i32,
|
||||
pub negative_votes: i32,
|
||||
pub user_vote: i64,
|
||||
#[serde(skip)]
|
||||
pub created: NaiveDateTime,
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ mod get_location;
|
|||
mod vote;
|
||||
mod get_mine;
|
||||
mod get_message;
|
||||
mod claim;
|
||||
|
||||
pub fn routes(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||
register::register(Arc::clone(&state))
|
||||
|
@ -26,6 +27,7 @@ pub fn routes(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
.or(get_message::get_message(Arc::clone(&state)))
|
||||
.or(get_location::get_location(Arc::clone(&state)))
|
||||
.or(get_mine::get_mine(Arc::clone(&state)))
|
||||
.or(claim::claim(Arc::clone(&state)))
|
||||
.recover(handle_rejection)
|
||||
.boxed()
|
||||
}
|
||||
|
@ -62,6 +64,7 @@ pub enum WebError {
|
|||
InvalidIndex,
|
||||
TooManyMessages,
|
||||
NoSuchMessage,
|
||||
InvalidExtraCode,
|
||||
}
|
||||
|
||||
impl Reject for WebError {}
|
||||
|
@ -72,21 +75,41 @@ pub struct AnyhowRejection(anyhow::Error);
|
|||
impl Reject for AnyhowRejection {}
|
||||
|
||||
async fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {
|
||||
let status = if let Some(AnyhowRejection(e)) = err.find::<AnyhowRejection>() {
|
||||
let (status, name, desc) = if let Some(AnyhowRejection(e)) = err.find::<AnyhowRejection>() {
|
||||
eprintln!("{:#?}", e);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"internal_error",
|
||||
"an internal logic error occured",
|
||||
)
|
||||
} else if let Some(e) = err.find::<WebError>() {
|
||||
match e {
|
||||
WebError::InvalidAuthToken => StatusCode::BAD_REQUEST,
|
||||
WebError::InvalidPackId => StatusCode::NOT_FOUND,
|
||||
WebError::InvalidIndex => StatusCode::NOT_FOUND,
|
||||
WebError::TooManyMessages => StatusCode::BAD_REQUEST,
|
||||
WebError::NoSuchMessage => StatusCode::NOT_FOUND,
|
||||
WebError::InvalidAuthToken => (StatusCode::BAD_REQUEST, "invalid_auth_token", "the auth token was not valid"),
|
||||
WebError::InvalidPackId => (StatusCode::NOT_FOUND, "invalid_pack_id", "the server does not have a pack registered with that id"),
|
||||
WebError::InvalidIndex => (StatusCode::NOT_FOUND, "invalid_index", "one of the provided indices was out of range"),
|
||||
WebError::TooManyMessages => (StatusCode::BAD_REQUEST, "too_many_messages", "you have run out of messages - delete one and try again"),
|
||||
WebError::NoSuchMessage => (StatusCode::NOT_FOUND, "no_such_message", "no message with that id was found"),
|
||||
WebError::InvalidExtraCode => (StatusCode::BAD_REQUEST, "invalid_extra_code", "that extra code was not found"),
|
||||
}
|
||||
} else {
|
||||
eprintln!("{:#?}", err);
|
||||
StatusCode::INTERNAL_SERVER_ERROR
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"internal_error",
|
||||
"an unhandled error was encountered",
|
||||
)
|
||||
};
|
||||
|
||||
Ok(warp::reply::with_status(warp::reply(), status))
|
||||
#[derive(serde::Serialize)]
|
||||
struct ErrorMessage {
|
||||
code: &'static str,
|
||||
message: &'static str,
|
||||
}
|
||||
|
||||
let message = ErrorMessage {
|
||||
code: name,
|
||||
message: desc,
|
||||
};
|
||||
|
||||
Ok(warp::reply::with_status(warp::reply::json(&message), status))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Context;
|
||||
use bytes::Bytes;
|
||||
use uuid::Uuid;
|
||||
use warp::{Filter, Rejection, Reply};
|
||||
use warp::filters::BoxedFilter;
|
||||
|
||||
use crate::message::RetrievedMessageTerritory;
|
||||
use crate::State;
|
||||
use crate::web::{AnyhowRejection, WebError};
|
||||
|
||||
pub fn claim(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||
warp::post()
|
||||
.and(warp::path("claim"))
|
||||
.and(warp::path::end())
|
||||
.and(super::get_id(Arc::clone(&state)))
|
||||
.and(warp::body::content_length_limit(256))
|
||||
.and(warp::body::bytes())
|
||||
.and_then(move |(id, _), code: Bytes| logic(Arc::clone(&state), id, code))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
async fn logic(state: Arc<State>, id: i64, bytes: Bytes) -> Result<impl Reply, Rejection> {
|
||||
let bytes: Vec<u8> = bytes.into_iter().collect();
|
||||
let code = String::from_utf8(bytes)
|
||||
.context("invalid utf8 for extra code")
|
||||
.map_err(AnyhowRejection)
|
||||
.map_err(warp::reject::custom)?;
|
||||
|
||||
let code = sqlx::query!(
|
||||
// language=sqlite
|
||||
r#"delete from extra_tokens where id = ? returning extra as "extra!: i64""#,
|
||||
code,
|
||||
)
|
||||
.fetch_optional(&state.db)
|
||||
.await
|
||||
.context("could not get code from database")
|
||||
.map_err(AnyhowRejection)
|
||||
.map_err(warp::reject::custom)?;
|
||||
|
||||
if let Some(code) = code {
|
||||
sqlx::query!(
|
||||
// language=sqlite
|
||||
"update users set extra = ? where id = ?",
|
||||
code.extra,
|
||||
id,
|
||||
)
|
||||
.execute(&state.db)
|
||||
.await
|
||||
.context("could not update user")
|
||||
.map_err(AnyhowRejection)
|
||||
.map_err(warp::reject::custom)?;
|
||||
|
||||
return Ok(code.extra.to_string());
|
||||
}
|
||||
|
||||
Err(warp::reject::custom(WebError::InvalidExtraCode))
|
||||
}
|
|
@ -34,7 +34,8 @@ async fn logic(state: Arc<State>, id: i64, message_id: Uuid) -> Result<impl Repl
|
|||
m.message,
|
||||
coalesce(sum(v.vote between 0 and 1), 0) as positive_votes,
|
||||
coalesce(sum(v.vote between -1 and 0), 0) as negative_votes,
|
||||
v2.vote as user_vote
|
||||
v2.vote as user_vote,
|
||||
m.created
|
||||
from messages m
|
||||
left join votes v on m.id = v.message
|
||||
left join votes v2 on m.id = v2.message and v2.user = ?
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Context;
|
||||
|
@ -13,12 +14,18 @@ pub fn get_mine(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
.and(warp::path("messages"))
|
||||
.and(warp::path::end())
|
||||
.and(super::get_id(Arc::clone(&state)))
|
||||
.and_then(move |(id, _)| logic(Arc::clone(&state), id))
|
||||
.and(warp::query())
|
||||
.and_then(move |(id, extra), query: HashMap<String, String>| logic(Arc::clone(&state), id, extra, query))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
async fn logic(state: Arc<State>, id: i64) -> Result<impl Reply, Rejection> {
|
||||
let messages = sqlx::query_as!(
|
||||
async fn logic(state: Arc<State>, id: i64, extra: i64, mut query: HashMap<String, String>) -> Result<impl Reply, Rejection> {
|
||||
let version = query.remove("v")
|
||||
.unwrap_or_else(|| "1".to_string())
|
||||
.parse::<u8>()
|
||||
.unwrap_or(1);
|
||||
|
||||
let mut messages = sqlx::query_as!(
|
||||
RetrievedMessageTerritory,
|
||||
// language=sqlite
|
||||
r#"
|
||||
|
@ -31,7 +38,8 @@ async fn logic(state: Arc<State>, id: i64) -> Result<impl Reply, Rejection> {
|
|||
m.message,
|
||||
coalesce(sum(v.vote between 0 and 1), 0) as positive_votes,
|
||||
coalesce(sum(v.vote between -1 and 0), 0) as negative_votes,
|
||||
v2.vote as user_vote
|
||||
v2.vote as user_vote,
|
||||
m.created
|
||||
from messages m
|
||||
left join votes v on m.id = v.message
|
||||
left join votes v2 on m.id = v2.message and v2.user = ?
|
||||
|
@ -45,5 +53,24 @@ async fn logic(state: Arc<State>, id: i64) -> Result<impl Reply, Rejection> {
|
|||
.context("could not get messages from database")
|
||||
.map_err(AnyhowRejection)
|
||||
.map_err(warp::reject::custom)?;
|
||||
Ok(warp::reply::json(&messages))
|
||||
|
||||
messages.sort_by_key(|msg| msg.created);
|
||||
messages.reverse();
|
||||
|
||||
if version == 1 {
|
||||
return Ok(warp::reply::json(&messages));
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct Mine {
|
||||
messages: Vec<RetrievedMessageTerritory>,
|
||||
extra: i64,
|
||||
}
|
||||
|
||||
let mine = Mine {
|
||||
messages,
|
||||
extra,
|
||||
};
|
||||
|
||||
Ok(warp::reply::json(&mine))
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ pub fn vote(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
.and(warp::path("votes"))
|
||||
.and(warp::path::end())
|
||||
.and(super::get_id(Arc::clone(&state)))
|
||||
.and(warp::body::content_length_limit(3))
|
||||
.and(warp::body::json())
|
||||
.and_then(move |message_id: Uuid, (id, _), vote: i8| logic(Arc::clone(&state), id, message_id, vote))
|
||||
.boxed()
|
||||
|
|
|
@ -14,6 +14,7 @@ pub fn write(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
.and(warp::path("messages"))
|
||||
.and(warp::path::end())
|
||||
.and(super::get_id(Arc::clone(&state)))
|
||||
.and(warp::body::content_length_limit(1024))
|
||||
.and(warp::body::json())
|
||||
.and_then(move |(id, extra), message: Message| logic(Arc::clone(&state), id, extra, message))
|
||||
.boxed()
|
||||
|
|
Loading…
Reference in New Issue