KO UO Topic http - LIHACHTETAN/ClassicUO-Bad-Newbie-CSharp-Scripts-IDE GitHub Wiki
ะฃะบัะฐัะฝััะบะฐ ยท ะ ัััะบะธะน ยท English ยท Deutsch ยท Franรงais ยท Italiano ยท Espaรฑol ยท ็น้ซไธญๆ ยท ๆฅๆฌ่ช ยท ํ๊ตญ์ด
ํ ยท C# ยท IDE ยท UO API ยท AโZ ยท ์ ยท ์ธ์ด
HTTP-์ง์ ๋ฐ ์๋ต ์ฝ๊ธฐ. ์ํ ์ฝ๋, ํค๋, ์๋ต ๋ณธ๋ฌธ์ ๋ณ๋์ ๋ฐ์ดํฐ์ ๋๋ค.
| ์ฃผ์ | ๋ช ๋ น ๋ฐ ์ค๋ช |
|---|---|
| HTTP_Get | UO.HTTP_Get |
| HTTP_Post | UO.HTTP_Post |
| HTTP_Header | UO.HTTP_Header |
| HTTP_Body | UO.HTTP_Body |
| ์ธ๋ถ ๋ฉ์์ง | UO.Messenger - ํ ๋ ๊ทธ๋จ, ๋์ค์ฝ๋, ๋ฐ์ด๋ฒ |
UO.HTTP_Get ยท UO.HTTP_Post ยท UO.HTTP_Header ยท UO.HTTP_Body
๊ฐ ๋ช ๋ น ์นด๋์๋ ์ง์ ์ฝ๋, ํจ์ ๋ฐ ํด๋์ค ๋ฑ ์ฌ๋ฌ ๊ฐ์ง ๋ ๋ฆฝ์ ์ธ ์๋๋ฆฌ์ค๊ฐ ์์ต๋๋ค. ๋ค์์ ์ ํ๋ ์งง์ ์๋๋ฆฌ์ค์ ๋๋ค. ์ ํ์ฌํญ๊ณผ ์ ์ฒด ๋ถ์์ด ์นด๋์ ํฌํจ๋์ด ์์ต๋๋ค.
๋งค๊ฐ๋ณ์, ๊ฒฐ๊ณผ ๋ฐ ๋ชจ๋ ์๋๋ฆฌ์ค
UO.HTTP_Get("https://example.com/csharp-config.json");
try
{
string body = Convert.ToString(UO.HTTP_Body()) ?? "";
using (var document = System.Text.Json.JsonDocument.Parse(body))
{
if (document.RootElement.TryGetProperty("minMana", out var value) &&
value.TryGetInt32(out int threshold) && threshold is >= 0 and <= 100)
return threshold;
}
}
catch (System.Text.Json.JsonException)
{
UO.Print("Response is not a valid configuration; using the default.");
}
return 30;๋งค๊ฐ๋ณ์, ๊ฒฐ๊ณผ ๋ฐ ๋ชจ๋ ์๋๋ฆฌ์ค
UO.HTTP_Get("https://example.com/C#-permission");
var permission = TrimText(UO.HTTP_Body());
return Truth(permission == "allow");
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
string TrimText(object? value) => (Convert.ToString(value) ?? "").Trim();ะฃะบัะฐัะฝััะบะฐ ยท ะ ัััะบะธะน ยท English ยท Deutsch ยท Franรงais ยท Italiano ยท Espaรฑol ยท ็น้ซไธญๆ ยท ๆฅๆฌ่ช ยท ํ๊ตญ์ด
dynamic UO.HTTP_Body();์ด ์คํฌ๋ฆฝํธ์ ๋ง์ง๋ง HTTP ์๋ต ํ ์คํธ๋ฅผ ์ฝ์ต๋๋ค. ์๋ฅผ ๋ค์ด HTTP_Get ํ์ ์ค์ ์ผ๋ก JSON๋ฅผ ๊ตฌ๋ฌธ ๋ถ์ํ๊ฑฐ๋ ์๋น์ค ์๋ต์ ์์ ๋ฌธ์์ด๊ณผ ๋น๊ตํ ์ ์์ต๋๋ค. ํ๋ ์์ฒด๋ ๋คํธ์ํฌ๋ก ์ด๋ํ์ง ์์ต๋๋ค.
๋งค๊ฐ๋ณ์๊ฐ ์์ต๋๋ค.
string โ ์ ์ฅ๋ ํ ์คํธ. ์ด ๋ฐํ์์ ์ฒซ ๋ฒ์งธ ์์ฒญ ์ , ์คํธ๋ฆผ์ GET ๋ค, ๋คํธ์ํฌ ์ค๋ฅ ํ - ๋น ์ค์ ๋๋ค. ์ผ๋ฐ์ ์ธ ๋ต๋ณ์๋ ๋ณธ๋ฌธ์ด ๋น์ด ์์ต๋๋ค(์: HTTP 204). ๊ฒ์ฌ ์ฌ๋ถ๋ฅผ ํ๋จํ๊ธฐ ์ํด ๊ฒฐ๊ณผ๋ฅผ true/false์ ๋น๊ตํ์ง ๋ง์ธ์.
- ๋ง์ง๋ง ์๋ต์ ์คํฌ๋ฆฝํธ์ ํ์ฌ ๋ฐํ์์๋ง ์ ์ฅ๋ฉ๋๋ค. ์ด ๋ฐํ์์ ๋ค์ GET/POST๊ฐ ์ด๋ฅผ ๋์ฒดํฉ๋๋ค. ๋์์ ์คํ๋๋ ๋ค๋ฅธ ์คํฌ๋ฆฝํธ๋ ์ด๋ฅผ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค. ๋ต๋ณ์ ํ๋กํ์ ์ ์ฅ๋์ง ์์ต๋๋ค. ๋ค์ ์์ฒญ ์ดํ์ ํ์ํ๋ค๋ฉด ๋ณธ๋ฌธ๊ณผ ํค๋๋ฅผ ๋ฏธ๋ฆฌ ๋ณ์์ ๋ณต์ฌํด ๋์ธ์.
- GET/POST ์คํ ์ค์ธ ์คํฌ๋ฆฝํธ ์ค๋ ๋์์ ์๋ต์ ๊ธฐ๋ค๋ฆฝ๋๋ค. ๋ณธ๋ฌธ์ ์์ฒญํ๊ณ ์ฝ๋ ๋ฐ ๊ฑธ๋ฆฌ๋ ์ด ์๊ฐ์ 20์ด์ ๋๋ค. ์คํฌ๋ฆฝํธ๋ฅผ ์ค์งํ๋ฉด ๋๊ธฐ๊ฐ ์ทจ์๋ฉ๋๋ค. HTTP_Body/HTTP_Header ์๋ฌด๊ฒ๋ ๊ธฐ๋ํ์ง ๋ง์ธ์. FileStream๊ฐ ์ ์ก๋๋ ๊ฒฝ์ฐ์๋ ์ ์ฒด ๋ณธ๋ฌธ์ด ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋๋ฉ๋๋ค. ์ด๋ ๋์ฉ๋ ํ์ผ์ ์คํธ๋ฆฌ๋ฐ ๋ค์ด๋ก๋๊ฐ ์๋๋๋ค.
- ์ธ์ฝ๋ฉ์ด ์๊ฑฐ๋ ์ ์ ์๋ ๊ฒฝ์ฐ(UTF-8) ํ ์คํธ๋ ์๋ต์ ๋ฌธ์ ์ธํธ์ ๋ฐ๋ผ ๋์ฝ๋ฉ๋ฉ๋๋ค. ๋ต๋ณ HTTP 4xx/5xx๋ ์ฝ์ต๋๋ค. ๋คํธ์ํฌ ์ค๋ฅ๋ ์๊ฐ ์ด๊ณผ๊ฐ ๋ฐ์ํ๋ฉด ํด๋ผ์ด์ธํธ๋ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ๊ณ ๋ณธ๋ฌธ๊ณผ ํค๋๋ ๋น์ด ์๊ฒ ๋ฉ๋๋ค. Try/Catch๋ ์์ ์๋ต ํ์ธ์ ๋์ฒดํ์ง ์์ต๋๋ค. ์คํฌ๋ฆฝํธ ์ทจ์๊ฐ ๋์ฑ ํ์ฅ๋ฉ๋๋ค. ๋ก์ปฌ ํ์ผ ์ฐ๊ธฐ ๋๋ ์๋ชป๋ ์ธ์ ์ค๋ฅ๋ Try/Catch๋ฅผ ํตํด ํฌ์ฐฉ๋ ์ ์์ต๋๋ค.
- HTTP_Body๋ ๋ง์ง๋ง ๋ฒํผ๋ง ์ฝ์ต๋๋ค. ์์ฒญ์ ๋ฐ๋ณตํ์ง ์๊ณ ์๋ต์ ์ง์ฐ์ง ์์ผ๋ฉฐ ๋ค๋ฅธ ์คํฌ๋ฆฝํธ์์ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ์ง ์์ต๋๋ค. ๋ฐ์ด๋๋ฆฌ GET ์ดํ์๋ ์ด ํ ์คํธ ๋ฒํผ๊ฐ ์๋ MemoryStream.ToArray() ๋๋ ์ ์ฅ๋ ํ์ผ์ ์ฌ์ฉํ์ธ์.
๊ฐ ์์ ๋ ๋ณ๋์ ํ์ผ .csx๋ก ์ ์ฅํ๊ณ IDE์์ ์คํํ ์ ์์ต๋๋ค. UO ๊ฐ์ฒด์ ๋๊ธฐ ๊ธฐ๋ฅ์ ํ์ฌ ๊ฒ์ ์ธ์
์ ํธ์คํธ๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ฐ๋ชจ serial ์ด๋ฆ, ์ขํ, ์ฃผ์๋ฅผ ์์ ์ ๊ฒ์ผ๋ก ๋ฐ๊พธ์ธ์.
์ด ์ฝ๋๋ฅผ ๋ณ๋์ .csx ํ์ผ๋ก ์คํํ์ธ์. ์ธ์๋ ํธ์ถ์ ์ง์ ํ์๋ฉ๋๋ค. ์์ ์ ์ด๋ฆ, serial, ์ฃผ์๋ฅผ ์์ ์ ๊ฐ์ผ๋ก ๋ฐ๊พธ์ธ์.
ํ ๋ฒ์ ํธ์ถ ๊ฒฐ๊ณผ๋ฅผ ์ ๋์ ํ์ํฉ๋๋ค. ์ซ์๋ฅผ bool๋ก ๋ณํํ์ง ์์ผ๋ฉฐ, ๋ฐฐ์ด์ด๋ฉด ์์ ์๋ฅผ ํ์ํฉ๋๋ค.
UO.HTTP_Get("https://example.com/");
object? result = UO.HTTP_Body();
UO.Print(result is Array values ? "Count: " + values.Length : Convert.ToString(result));๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- ์๋น์ค๋ ํ์ฉ์ ๋ฐํํด์ผ ํฉ๋๋ค. ๋น ๋ต์ ํฌํจํ ๋ ๋ค๋ฅธ ๋ต์ false์ ๋๋ค. ์ด ์์์๋ ํด์๋๋ง ๊ณ์ฐํฉ๋๋ค. ์ด๋์ด๋ ์ ํฌ๋ฅผ ์ ๋ฐํ์ง ์์ต๋๋ค.
- example.com ์ฃผ์๋ ์์์ผ ๋ฟ์ด๋ฉฐ ๊ทธ๋ฌํ ์๋น์ค๋ฅผ ์ ๊ณตํ์ง ์์ต๋๋ค. ์์ ์ ๊ฒ์ผ๋ก ๊ต์ฒดํ์ญ์์ค. ์์ ๋ฅผ ์คํํ๋ฉด ์ค์ HTTP ์ฟผ๋ฆฌ๊ฐ ์์ฑ๋ฉ๋๋ค. ์ด ์์์๋ ๊ฒ์ ์์ ์ ์ํํ์ง ์์ต๋๋ค.
UO.HTTP_Get("https://example.com/C#-permission");
var permission = TrimText(UO.HTTP_Body());
return Truth(permission == "allow");
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
string TrimText(object? value) => (Convert.ToString(value) ?? "").Trim();๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- ๋จผ์ ๊ฒฝ๋ก ์ด๋ฆ์ด ์ ์ฅ๋ ๋ค์ ์ค๋ช ์ด ์์ฒญ๋ฉ๋๋ค. routeName๊ฐ ์์ผ๋ฉด ๋ ๋ฒ์งธ GET๊ฐ ์ฒซ ๋ฒ์งธ ๋ต๋ณ์ ๋์ฒดํฉ๋๋ค.
- example.com ์ฃผ์๋ ์์์ผ ๋ฟ์ด๋ฉฐ ๊ทธ๋ฌํ ์๋น์ค๋ฅผ ์ ๊ณตํ์ง ์์ต๋๋ค. ์์ ์ ๊ฒ์ผ๋ก ๊ต์ฒดํ์ญ์์ค. ์์ ๋ฅผ ์คํํ๋ฉด ์ค์ HTTP ์ฟผ๋ฆฌ๊ฐ ์์ฑ๋ฉ๋๋ค. ์ด ์์์๋ ๊ฒ์ ์์ ์ ์ํํ์ง ์์ต๋๋ค.
return RunScenario();
object? RunScenario()
{
UO.HTTP_Get("https://example.com/route-name");
var routeName = UO.HTTP_Body();
UO.HTTP_Get("https://example.com/route-description");
return routeName + ": " + UO.HTTP_Body();
return null;
}๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- System.IO.MemoryStream์ GET ์ดํ์๋ ๋ฐ์ดํธ๊ฐ ์คํธ๋ฆผ์ ์๊ณ HTTP_Body๋ ๋น์ด ์์ต๋๋ค. ์ด ๊ท์น์ ์ฌ๋ฐ๋ฅธ ์ด์ง ๋ต๋ณ์๋ ์ ์ฉ๋ฉ๋๋ค. ๋น ํ ์คํธ๋ ๋ฐ์ดํธ๊ฐ ์์์ ์๋ฏธํ์ง ์์ต๋๋ค.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
using (var data = new System.IO.MemoryStream())
{
UO.HTTP_Get("https://example.com/route-data.bin", data);
string body = Convert.ToString(UO.HTTP_Body()) ?? "";
UO.Print($"Binary bytes: {data.Length}; text-body characters: {body.Length}");
return body;
}
return null;
}
}C#์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํฉ๋๋ค. ์ ํํ UO ์ด๋ฆ์ ์ฌ์ฉํ์ธ์. ์ซ์ ํ๋๊ทธ๋ 0๊ณผ ๋น๊ตํ๊ณ ๋ฐํ ํ์์ด bool์ผ ๋๋ง bool์ ์ฌ์ฉํ์ธ์.
๋งค๊ฐ๋ณ์: ๋งค๊ฐ๋ณ์๊ฐ ์์ต๋๋ค.
๊ฒฐ๊ณผ: dynamic / Any.
ํธ์ถ ์:
๋ด๋ถ ๊ตฌํ ์ฝ๋์ด๋ฉฐ ๋ ๋ฆฝ ์คํฌ๋ฆฝํธ๋ก ์คํํ ์ ์์ต๋๋ค.
case "http_body": return new InjectionValue(httpBody);ะฃะบัะฐัะฝััะบะฐ ยท ะ ัััะบะธะน ยท English ยท Deutsch ยท Franรงais ยท Italiano ยท Espaรฑol ยท ็น้ซไธญๆ ยท ๆฅๆฌ่ช ยท ํ๊ตญ์ด
void UO.HTTP_Get(object? url);
void UO.HTTP_Get(object? url, object? lStream);HTTP/HTTPS์ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํฉ๋๋ค. ์๋น์ค์์ ์ค์ ์ ์ฝ๊ฑฐ๋ ํ์ผ์ ์์ ํ๋ ๋ฐ ์ ํฉํฉ๋๋ค. ๊ฒ์ ์ฐ๊ฒฐ์ ๊ด๋ฆฌํ๊ฑฐ๋ ๋ค์ด๋ก๋ํ ์ฝ๋๋ฅผ ์คํํ์ง ์์ต๋๋ค.
-
url- ํ์ string: ์ ์ฒด ์ฃผ์ http:// ๋๋ https://. example.com์ ์๋น์ค ์ฃผ์๋ก ๋ฐ๊ฟ๋๋ค. ์ด ์์ฒญ์๋ ๊ฒ์ ๋ฐ ๊ฒ์ ์๋ฒ๊ฐ ํ์ํ์ง ์์ต๋๋ค. ๊ฒ์ ํ๋ก์ ํ๋กํ์ด ์๋ ํ๋ก์ธ์ค์ ์ผ๋ฐ ๋คํธ์ํฌ ์ฐ๊ฒฐ์ด ์ฌ์ฉ๋ฉ๋๋ค. -
lStream๋ ์ ํ์ ํ์ค์ ๋๋ค. .NET System.IO.Stream, ์ฐ๊ธฐ ๊ฐ๋ฅ: ์๋ฅผ ๋ค์ด ์๋ก์ด System.IO.MemoryStream() ๋๋ System.IO.File.Create(๊ฒฝ๋ก)์ ๋๋ค. ๊ทธ๊ฒ์ด ์๊ฑฐ๋ 0/null๋ฅผ ์ฌ์ฉํ๋ฉด ํ ์คํธ๋ HTTP_Body()๊ฐ ๋ฉ๋๋ค. ์ค๋ ๋๋ ์๋ณธ ๋ฐ์ดํธ๋ฅผ ๋ฐ์ต๋๋ค. ๊ฒ์ ๊ฐ๋ฅํ ์คํธ๋ฆผ์ ๊ฒฝ์ฐ ์ด์ ์ฝํ ์ธ ๋ 0์ผ๋ก ์ฌ์ค์ ๋๊ณ ์ฐ๊ธฐ ์ ํ์ ์์น๋ 0๊ฐ ๋ฉ๋๋ค. ํ์ํ ์ ์๋ ์ค๋ ๋๋ ํ์ฌ ์์น์ ๋ํ ์ฐ๊ธฐ๋ฅผ ๋ฐ์ต๋๋ค. File.Create๋ฅผ ํตํด FileStream์ ์์ฑํ๋ฉด ํ์ผ์ด ์ฆ์ ๋ฌดํจํ๋ฉ๋๋ค. ์์ ๋๋ ํ ๋ฆฌ๊ฐ ์กด์ฌํด์ผ ํฉ๋๋ค. ๋ถ์ ์ ํ ์ธ์ ๋๋ ์ฝ๊ธฐ ์ ์ฉ ์คํธ๋ฆผ์ ์์ฒญ ์ ์ ๊ฑฐ๋ถ๋ฉ๋๋ค.
void - ๋ฐํ ๊ฐ์ด ์์ต๋๋ค. ๋ณ๋์ ํ์ ์ผ๋ก ์ ํํ์ธ์. ๊ฒฐ๊ณผ๋ bool, ID ๋๋ ๋ฐ์ดํธ ์๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. HTTP_Body()๋ ์ผ๋ฐ ์์ฒญ ์ดํ์ ํ ์คํธ๋ฅผ ์ฝ๊ณ , ์ ์ก๋ ์คํธ๋ฆผ์์ ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ต๋๋ค.
- ๋ง์ง๋ง ์๋ต์ ์คํฌ๋ฆฝํธ์ ํ์ฌ ๋ฐํ์์๋ง ์ ์ฅ๋ฉ๋๋ค. ์ด ๋ฐํ์์ ๋ค์ GET/POST๊ฐ ์ด๋ฅผ ๋์ฒดํฉ๋๋ค. ๋์์ ์คํ๋๋ ๋ค๋ฅธ ์คํฌ๋ฆฝํธ๋ ์ด๋ฅผ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค. ๋ต๋ณ์ ํ๋กํ์ ์ ์ฅ๋์ง ์์ต๋๋ค. ๋ค์ ์์ฒญ ์ดํ์ ํ์ํ๋ค๋ฉด ๋ณธ๋ฌธ๊ณผ ํค๋๋ฅผ ๋ฏธ๋ฆฌ ๋ณ์์ ๋ณต์ฌํด ๋์ธ์.
- GET/POST ์คํ ์ค์ธ ์คํฌ๋ฆฝํธ ์ค๋ ๋์์ ์๋ต์ ๊ธฐ๋ค๋ฆฝ๋๋ค. ๋ณธ๋ฌธ์ ์์ฒญํ๊ณ ์ฝ๋ ๋ฐ ๊ฑธ๋ฆฌ๋ ์ด ์๊ฐ์ 20์ด์ ๋๋ค. ์คํฌ๋ฆฝํธ๋ฅผ ์ค์งํ๋ฉด ๋๊ธฐ๊ฐ ์ทจ์๋ฉ๋๋ค. HTTP_Body/HTTP_Header ์๋ฌด๊ฒ๋ ๊ธฐ๋ํ์ง ๋ง์ธ์. FileStream๊ฐ ์ ์ก๋๋ ๊ฒฝ์ฐ์๋ ์ ์ฒด ๋ณธ๋ฌธ์ด ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋๋ฉ๋๋ค. ์ด๋ ๋์ฉ๋ ํ์ผ์ ์คํธ๋ฆฌ๋ฐ ๋ค์ด๋ก๋๊ฐ ์๋๋๋ค.
- ์ธ์ฝ๋ฉ์ด ์๊ฑฐ๋ ์ ์ ์๋ ๊ฒฝ์ฐ(UTF-8) ํ ์คํธ๋ ์๋ต์ ๋ฌธ์ ์ธํธ์ ๋ฐ๋ผ ๋์ฝ๋ฉ๋ฉ๋๋ค. ๋ต๋ณ HTTP 4xx/5xx๋ ์ฝ์ต๋๋ค. ๋คํธ์ํฌ ์ค๋ฅ๋ ์๊ฐ ์ด๊ณผ๊ฐ ๋ฐ์ํ๋ฉด ํด๋ผ์ด์ธํธ๋ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ๊ณ ๋ณธ๋ฌธ๊ณผ ํค๋๋ ๋น์ด ์๊ฒ ๋ฉ๋๋ค. Try/Catch๋ ์์ ์๋ต ํ์ธ์ ๋์ฒดํ์ง ์์ต๋๋ค. ์คํฌ๋ฆฝํธ ์ทจ์๊ฐ ๋์ฑ ํ์ฅ๋ฉ๋๋ค. ๋ก์ปฌ ํ์ผ ์ฐ๊ธฐ ๋๋ ์๋ชป๋ ์ธ์ ์ค๋ฅ๋ Try/Catch๋ฅผ ํตํด ํฌ์ฐฉ๋ ์ ์์ต๋๋ค.
- GET ์ค๋ ๋๊ฐ ์์ผ๋ฉด ํ ์คํธ์ ์ ๋ชฉ์ ์ ๋ฐ์ดํธํฉ๋๋ค. GET๋ ์คํธ๋ฆผ๊ณผ ํจ๊ป ๋ฐ์ดํธ๋ฅผ ์ฐ๊ณ HTTP_Body๋ฅผ ์ง์ฐ๊ณ ํค๋๋ฅผ ์ ์ฅํฉ๋๋ค. ๋น ์๋ต/๋คํธ์ํฌ ์ค๋ฅ๋ผ๋ ์คํธ๋ฆผ์ ๋ด์ฉ์ ๋น ๋ฐ์ดํฐ๋ก ๋์ฒดํฉ๋๋ค. ์ด์ ํ์ผ์ ์ ์ฅํ๋ ค๋ฉด ๋จผ์ MemoryStream์ ๋ค์ด๋ก๋ํ๊ณ ๋ฐ์ดํฐ๋ฅผ ํ์ธํ์ธ์.
๊ฐ ์์ ๋ ๋ณ๋์ ํ์ผ .csx๋ก ์ ์ฅํ๊ณ IDE์์ ์คํํ ์ ์์ต๋๋ค. UO ๊ฐ์ฒด์ ๋๊ธฐ ๊ธฐ๋ฅ์ ํ์ฌ ๊ฒ์ ์ธ์
์ ํธ์คํธ๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ฐ๋ชจ serial ์ด๋ฆ, ์ขํ, ์ฃผ์๋ฅผ ์์ ์ ๊ฒ์ผ๋ก ๋ฐ๊พธ์ธ์.
์ด ์ฝ๋๋ฅผ ๋ณ๋์ .csx ํ์ผ๋ก ์คํํ์ธ์. ์ธ์๋ ํธ์ถ์ ์ง์ ํ์๋ฉ๋๋ค. ์์ ์ ์ด๋ฆ, serial, ์ฃผ์๋ฅผ ์์ ์ ๊ฐ์ผ๋ก ๋ฐ๊พธ์ธ์.
๋ช ๋ น์ ๋ ๋ฆฝ๋ ๋ฌธ์ ๋๋ค. ์์ ๋ฉ์์ง๋ ํธ์ถ ์์์ ๋ํ๋ด๋ฉฐ ์๋ฒ ๋์์ ์๋ฃ๋ฅผ ํ์ธํ์ง ์์ต๋๋ค.
UO.Print("Calling UO.HTTP_Get");
UO.HTTP_Get("https://example.com/");๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- example.com - ๋ฐ๋ชจ ์ฃผ์; ๊ทธ๊ฒ์ ๋น์ ๊ฒ์ผ๋ก ๊ต์ฒดํ์ญ์์ค. System.Text.Json์ ์๋ต ๋ณธ๋ฌธ์ ์ฝ๊ณ 0๋ถํฐ 100๊น์ง ์ ์ minMana๋ง ํ์ฉํฉ๋๋ค. ๋น์ด ์๊ฑฐ๋ ์ ํจํ์ง ์์ JSON๋ ๊ธฐ๋ณธ๊ฐ 30๋ฅผ ์ ๊ณตํฉ๋๋ค.
UO.HTTP_Get("https://example.com/csharp-config.json");
try
{
string body = Convert.ToString(UO.HTTP_Body()) ?? "";
using (var document = System.Text.Json.JsonDocument.Parse(body))
{
if (document.RootElement.TryGetProperty("minMana", out var value) &&
value.TryGetInt32(out int threshold) && threshold is >= 0 and <= 100)
return threshold;
}
}
catch (System.Text.Json.JsonException)
{
UO.Print("Response is not a valid configuration; using the default.");
}
return 30;๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- ํ์ค ์์คํ .IO.MemoryStream์ด ์ ์ก๋ฉ๋๋ค. ์๋ต์ ์๋ณธ ๋ฐ์ดํธ๋ฅผ ์์ ํฉ๋๋ค. HTTP_Body๊ฐ ๋น์ด ์๊ฒ ๋ฉ๋๋ค. ๊ธฐ์กด download.bin์ ๋น์ด ์์ง ์์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ ํ์๋ง ๊ต์ฒด๋ฉ๋๋ค. ๊ธธ์ด๋ฅผ ํ์ธํ๋ค๊ณ ํด์ ๋ด์ฉ์ด ์ ํํ๋ค๋ ๊ฒ์ ์ฆ๋ช ํ๋ ๊ฒ์ ์๋๋๋ค.
return RunScenario();
object? RunScenario()
{
using (var data = new System.IO.MemoryStream())
{
UO.HTTP_Get("https://example.com/route-data.bin", data);
if (data.Length == 0)
{
UO.Print("The response is empty; no file was written.");
return false;
}
System.IO.File.WriteAllBytes("download.bin", data.ToArray());
return true;
}
return null;
}๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- System.IO.File.Create๋ ํ์ผ์ ์์ฑํ๊ฑฐ๋ ์ฆ์ null๋ก ๋ง๋ญ๋๋ค. GET๋ ์๋ ๋ฐ์ดํธ๋ฅผ ์๋๋ค. ์๋ต์ด ๋น์ด ์์ผ๋ฉด ํ์ผ์ ๋น์ด ์๋ ์ํ๋ก ์ ์ง๋ฉ๋๋ค. ์ด์ ๋ฒ์ ์ ์ ์ฅํ๋ ค๋ฉด ๋จผ์ ์ด์ ์คํฌ๋ฆฝํธ์ ๋ง์ฐฌ๊ฐ์ง๋ก MemoryStream๋ฅผ ์ฌ์ฉํ์ธ์. ๋ฅผ ์ฌ์ฉํ๋ฉด ์คํธ๋ฆผ์ด ๋ซํ๋๋ค.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
using (var output = System.IO.File.Create("http-download.bin"))
{
UO.HTTP_Get("https://example.com/route-data.bin", output);
}
return UO.HTTP_Header();
return null;
}
}C#์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํฉ๋๋ค. ์ ํํ UO ์ด๋ฆ์ ์ฌ์ฉํ์ธ์. ์ซ์ ํ๋๊ทธ๋ 0๊ณผ ๋น๊ตํ๊ณ ๋ฐํ ํ์์ด bool์ผ ๋๋ง bool์ ์ฌ์ฉํ์ธ์.
๋งค๊ฐ๋ณ์: url (Any)
๊ฒฐ๊ณผ: void / Unit.
ํธ์ถ ์:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.HttpRequest:bridge.HttpRequest("GET", Text(0), string.Empty). -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Text:Text(0). -
InjectionScript.Runtime.ObjectTypes.MemoryStreamObject.ReplaceBytes:memoryStream.ReplaceBytes(raw).
๋ด๋ถ ๊ตฌํ ์ฝ๋์ด๋ฉฐ ๋ ๋ฆฝ ์คํฌ๋ฆฝํธ๋ก ์คํํ ์ ์์ต๋๋ค.
case "http_get":
{
bool hasStream = arguments.Length > 1
&& !(arguments[1].Kind == InjectionValueKind.Integer && arguments[1].Integer == 0)
&& arguments[1].Kind != InjectionValueKind.Unit;
// Validate before network side effects and before changing the last response.
if (hasStream && !(arguments[1].Object is MemoryStreamObject))
throw new NativeSubrutineException("UO.HTTP_Get: LStream must be a writable System.IO.Stream, 0, or omitted.");
string[] response = bridge.HttpRequest("GET", Text(0), string.Empty);
httpHeader = response.Length > 1 ? response[1] : string.Empty;
httpBody = hasStream ? string.Empty : response.Length > 0 ? response[0] : string.Empty;
if (!hasStream)
{
return InjectionValue.Unit;
}
byte[] raw = response.Length > 3 && !string.IsNullOrEmpty(response[3])
? Convert.FromBase64String(response[3])
: Array.Empty<byte>();
if (arguments[1].Object is MemoryStreamObject memoryStream)
memoryStream.ReplaceBytes(raw);
else
throw new NativeSubrutineException("UO.HTTP_Get: LStream must be a writable System.IO.Stream.");
// Stream overloads keep the response as bytes, not cached text.
return InjectionValue.Unit;
}๋งค๊ฐ๋ณ์: url (Any), lStream (Any)
๊ฒฐ๊ณผ: void / Unit.
ํธ์ถ ์:
-
ClassicUO.CSharp.CSharpScriptGlobals.CSharpScriptGlobals. -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.HttpRequest:bridge.HttpRequest("GET", Text(0), string.Empty). -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Text:Text(0). -
InjectionScript.Runtime.ObjectTypes.MemoryStreamObject.ReplaceBytes:memoryStream.ReplaceBytes(raw).
๋ด๋ถ ๊ตฌํ ์ฝ๋์ด๋ฉฐ ๋ ๋ฆฝ ์คํฌ๋ฆฝํธ๋ก ์คํํ ์ ์์ต๋๋ค.
if (name == "HTTP_Get" && arguments.Length == 2 && arguments[1] is Stream stream)
{
if (!stream.CanWrite) throw new ArgumentException("HTTP_Get requires a writable .NET stream.");
// Adapt the existing binary response path without fetching the
// response twice or converting its bytes through text encoding.
var type = typeof(InjectionValue).Assembly.GetType("InjectionScript.Runtime.ObjectTypes.MemoryStreamObject", throwOnError: true)!;
using var native = (IDisposable)Activator.CreateInstance(type, nonPublic: true)!;
value = Invoke(name, [arguments[0], native]);
var bytes = (InjectionValue)type.GetMethod("ToArray")!.Invoke(native, null)!;
byte[] payload = bytes.Array.Select(item => checked((byte)item.Integer)).ToArray();
if (stream.CanSeek) { stream.SetLength(0); stream.Position = 0; }
stream.Write(payload);
if (stream.CanSeek) stream.Position = 0;
}
else value = Invoke(name, arguments);๋ด๋ถ ๊ตฌํ ์ฝ๋์ด๋ฉฐ ๋ ๋ฆฝ ์คํฌ๋ฆฝํธ๋ก ์คํํ ์ ์์ต๋๋ค.
case "http_get":
{
bool hasStream = arguments.Length > 1
&& !(arguments[1].Kind == InjectionValueKind.Integer && arguments[1].Integer == 0)
&& arguments[1].Kind != InjectionValueKind.Unit;
// Validate before network side effects and before changing the last response.
if (hasStream && !(arguments[1].Object is MemoryStreamObject))
throw new NativeSubrutineException("UO.HTTP_Get: LStream must be a writable System.IO.Stream, 0, or omitted.");
string[] response = bridge.HttpRequest("GET", Text(0), string.Empty);
httpHeader = response.Length > 1 ? response[1] : string.Empty;
httpBody = hasStream ? string.Empty : response.Length > 0 ? response[0] : string.Empty;
if (!hasStream)
{
return InjectionValue.Unit;
}
byte[] raw = response.Length > 3 && !string.IsNullOrEmpty(response[3])
? Convert.FromBase64String(response[3])
: Array.Empty<byte>();
if (arguments[1].Object is MemoryStreamObject memoryStream)
memoryStream.ReplaceBytes(raw);
else
throw new NativeSubrutineException("UO.HTTP_Get: LStream must be a writable System.IO.Stream.");
// Stream overloads keep the response as bytes, not cached text.
return InjectionValue.Unit;
}ะฃะบัะฐัะฝััะบะฐ ยท ะ ัััะบะธะน ยท English ยท Deutsch ยท Franรงais ยท Italiano ยท Espaรฑol ยท ็น้ซไธญๆ ยท ๆฅๆฌ่ช ยท ํ๊ตญ์ด
dynamic UO.HTTP_Header();์ด ์คํฌ๋ฆฝํธ์ ๋ง์ง๋ง HTTP ์๋ต ํค๋(์: Content-Type)๋ฅผ ์ฝ์ด ์ ์ธ๋ ๋ฐ์ดํฐ ํ์์ ์ฐพ์ต๋๋ค. ์ด๋ ์๋ต ๋ณธ๋ฌธ, ์์ฒญ ํค๋ ๋๋ ์ซ์ ์ฝ๋ HTTP์ด ์๋๋๋ค.
๋งค๊ฐ๋ณ์๊ฐ ์์ต๋๋ค.
string โ ์ด๋ฆ: ๊ฐ ํ์์ ์ค์ด๋ฉฐ CRLF๋ก ๊ตฌ๋ถ๋ฉ๋๋ค. ์ฒซ ๋ฒ์งธ ์์ฒญ ์ ๊ณผ ๋คํธ์ํฌ ์ค๋ฅ ํ - ๋น ์ค์ ๋๋ค. HTTP/1.1 200 OK ์ค์ ์ฌ๊ธฐ์ ์์ต๋๋ค. ์ํ ์ฝ๋๋ ๋ณ๋์ ๋ช ๋ น์ผ๋ก ํ์๋์ง ์์ต๋๋ค. ์ด๋ฆ์ ์์์ ๋์๋ฌธ์๋ ๋ณด์ฅ๋์ง ์์ต๋๋ค.
- ๋ง์ง๋ง ์๋ต์ ์คํฌ๋ฆฝํธ์ ํ์ฌ ๋ฐํ์์๋ง ์ ์ฅ๋ฉ๋๋ค. ์ด ๋ฐํ์์ ๋ค์ GET/POST๊ฐ ์ด๋ฅผ ๋์ฒดํฉ๋๋ค. ๋์์ ์คํ๋๋ ๋ค๋ฅธ ์คํฌ๋ฆฝํธ๋ ์ด๋ฅผ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค. ๋ต๋ณ์ ํ๋กํ์ ์ ์ฅ๋์ง ์์ต๋๋ค. ๋ค์ ์์ฒญ ์ดํ์ ํ์ํ๋ค๋ฉด ๋ณธ๋ฌธ๊ณผ ํค๋๋ฅผ ๋ฏธ๋ฆฌ ๋ณ์์ ๋ณต์ฌํด ๋์ธ์.
- GET/POST ์คํ ์ค์ธ ์คํฌ๋ฆฝํธ ์ค๋ ๋์์ ์๋ต์ ๊ธฐ๋ค๋ฆฝ๋๋ค. ๋ณธ๋ฌธ์ ์์ฒญํ๊ณ ์ฝ๋ ๋ฐ ๊ฑธ๋ฆฌ๋ ์ด ์๊ฐ์ 20์ด์ ๋๋ค. ์คํฌ๋ฆฝํธ๋ฅผ ์ค์งํ๋ฉด ๋๊ธฐ๊ฐ ์ทจ์๋ฉ๋๋ค. HTTP_Body/HTTP_Header ์๋ฌด๊ฒ๋ ๊ธฐ๋ํ์ง ๋ง์ธ์. FileStream๊ฐ ์ ์ก๋๋ ๊ฒฝ์ฐ์๋ ์ ์ฒด ๋ณธ๋ฌธ์ด ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋๋ฉ๋๋ค. ์ด๋ ๋์ฉ๋ ํ์ผ์ ์คํธ๋ฆฌ๋ฐ ๋ค์ด๋ก๋๊ฐ ์๋๋๋ค.
- ์ธ์ฝ๋ฉ์ด ์๊ฑฐ๋ ์ ์ ์๋ ๊ฒฝ์ฐ(UTF-8) ํ ์คํธ๋ ์๋ต์ ๋ฌธ์ ์ธํธ์ ๋ฐ๋ผ ๋์ฝ๋ฉ๋ฉ๋๋ค. ๋ต๋ณ HTTP 4xx/5xx๋ ์ฝ์ต๋๋ค. ๋คํธ์ํฌ ์ค๋ฅ๋ ์๊ฐ ์ด๊ณผ๊ฐ ๋ฐ์ํ๋ฉด ํด๋ผ์ด์ธํธ๋ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ๊ณ ๋ณธ๋ฌธ๊ณผ ํค๋๋ ๋น์ด ์๊ฒ ๋ฉ๋๋ค. Try/Catch๋ ์์ ์๋ต ํ์ธ์ ๋์ฒดํ์ง ์์ต๋๋ค. ์คํฌ๋ฆฝํธ ์ทจ์๊ฐ ๋์ฑ ํ์ฅ๋ฉ๋๋ค. ๋ก์ปฌ ํ์ผ ์ฐ๊ธฐ ๋๋ ์๋ชป๋ ์ธ์ ์ค๋ฅ๋ Try/Catch๋ฅผ ํตํด ํฌ์ฐฉ๋ ์ ์์ต๋๋ค.
- HTTP_Header๋ ์๋ต ํค๋์ ๋ด์ฉ์ ๊ฒฐํฉํฉ๋๋ค. ๋ฐ์ด๋๋ฆฌ GET ์ดํ์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด๋ฆ์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์๊ณ ํ์ธํด์ผ ํฉ๋๋ค. Content-Type์ ์ฝํ ์ธ ๊ฒ์ฌ๊ฐ ์๋ ์๋ฒ ๋ฌธ์ ๋๋ค. ๋ค์ด๋ก๋ํ ํ ์คํธ๋ฅผ ์ฝ๋๋ก ์คํํ์ง ๋ง์ธ์.
๊ฐ ์์ ๋ ๋ณ๋์ ํ์ผ .csx๋ก ์ ์ฅํ๊ณ IDE์์ ์คํํ ์ ์์ต๋๋ค. UO ๊ฐ์ฒด์ ๋๊ธฐ ๊ธฐ๋ฅ์ ํ์ฌ ๊ฒ์ ์ธ์
์ ํธ์คํธ๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ฐ๋ชจ serial ์ด๋ฆ, ์ขํ, ์ฃผ์๋ฅผ ์์ ์ ๊ฒ์ผ๋ก ๋ฐ๊พธ์ธ์.
์ด ์ฝ๋๋ฅผ ๋ณ๋์ .csx ํ์ผ๋ก ์คํํ์ธ์. ์ธ์๋ ํธ์ถ์ ์ง์ ํ์๋ฉ๋๋ค. ์์ ์ ์ด๋ฆ, serial, ์ฃผ์๋ฅผ ์์ ์ ๊ฐ์ผ๋ก ๋ฐ๊พธ์ธ์.
ํ ๋ฒ์ ํธ์ถ ๊ฒฐ๊ณผ๋ฅผ ์ ๋์ ํ์ํฉ๋๋ค. ์ซ์๋ฅผ bool๋ก ๋ณํํ์ง ์์ผ๋ฉฐ, ๋ฐฐ์ด์ด๋ฉด ์์ ์๋ฅผ ํ์ํฉ๋๋ค.
UO.HTTP_Get("https://example.com/");
object? result = UO.HTTP_Header();
UO.Print(result is Array values ? "Count: " + values.Length : Convert.ToString(result));๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- ์ ๋ชฉ์ ํ ์ค์ฉ ๊ตฌ๋ฌธ ๋ถ์๋ฉ๋๋ค. Content-Type ์ด๋ฆ์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํ์ง ์๊ณ ๋น๊ต๋ฉ๋๋ค. ๋ฌธ์์ด์ด ์์ผ๋ฉด ๋น ๋ฌธ์์ด์ด ๋ฐํ๋ฉ๋๋ค.
UO.HTTP_Get("https://example.com/csharp-status");
return ReadHeader(Convert.ToString(UO.HTTP_Header()) ?? "", "Content-Type");
string ReadHeader(string headers, string name)
{
foreach (string line in headers.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries))
{
int separator = line.IndexOf(':');
if (separator > 0 && line[..separator].Trim().Equals(name, StringComparison.OrdinalIgnoreCase))
return line[(separator + 1)..].Trim();
}
return "";
}๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- ๋ก์ปฌ์ ์ ์ฅ๋ ํค๋ ํ ์คํธ๊ฐ ํ์ธ๋ฉ๋๋ค. Content-Type ์์ฒด๋ JSON์ ์ ํ์ฑ์ ๋ณด์ฅํ์ง ์์ต๋๋ค. System.Text.Json์ ๋ด์ฉ์ ๋ณ๋๋ก ํ์ธํ์ธ์.
return RunScenario();
object? RunScenario()
{
UO.HTTP_Get("https://example.com/csharp-status");
string headers = Convert.ToString(UO.HTTP_Header()) ?? "";
return headers.Contains("application/json", StringComparison.OrdinalIgnoreCase);
return null;
}๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- GET๋ ์์ค ๋ฐ์ดํธ๋ฅผ System.IO.MemoryStream๋ก ์ ๋ฌํฉ๋๋ค. ๋ง์ง๋ง ์๋ต ํค๋๋ ์ฌ์ ํ HTTP_Header;์ ๋๋ค. ์ด ์์์ ํ ์คํธ HTTP_Body๊ฐ ๋น์ด ์์ต๋๋ค. ํค๋๋ง ํ์ผ์ ์ ์ฅ๋ฉ๋๋ค.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
using (var data = new System.IO.MemoryStream())
{
UO.HTTP_Get("https://example.com/route-data.bin", data);
string headers = Convert.ToString(UO.HTTP_Header()) ?? "";
System.IO.File.WriteAllText("http-response-headers.txt", headers);
UO.Print($"Saved response headers; downloaded {data.Length} binary bytes.");
return headers;
}
return null;
}
}C#์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํฉ๋๋ค. ์ ํํ UO ์ด๋ฆ์ ์ฌ์ฉํ์ธ์. ์ซ์ ํ๋๊ทธ๋ 0๊ณผ ๋น๊ตํ๊ณ ๋ฐํ ํ์์ด bool์ผ ๋๋ง bool์ ์ฌ์ฉํ์ธ์.
๋งค๊ฐ๋ณ์: ๋งค๊ฐ๋ณ์๊ฐ ์์ต๋๋ค.
๊ฒฐ๊ณผ: dynamic / Any.
ํธ์ถ ์:
๋ด๋ถ ๊ตฌํ ์ฝ๋์ด๋ฉฐ ๋ ๋ฆฝ ์คํฌ๋ฆฝํธ๋ก ์คํํ ์ ์์ต๋๋ค.
case "http_header": return new InjectionValue(httpHeader);ะฃะบัะฐัะฝััะบะฐ ยท ะ ัััะบะธะน ยท English ยท Deutsch ยท Franรงais ยท Italiano ยท Espaรฑol ยท ็น้ซไธญๆ ยท ๆฅๆฌ่ช ยท ํ๊ตญ์ด
dynamic UO.HTTP_Post(object? url, object? postData);POST ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ HTTP ์๋น์ค์ ํ ์คํธ๋ฅผ ๋ณด๋ด๊ณ ์๋ต ํ ์คํธ๋ฅผ ๋ฐํํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์คํฌ๋ฆฝํธ๋ ๊ฒฝ๋ก ์ค์ง๋ฅผ ๋ณด๊ณ ํ ์ ์์ต๋๋ค. ์ด๋ ์ด๋ฏธ ๋ง๋ค์ด์ง Telegram/Discord ๋ช ๋ น์ด ์๋๋๋ค. ํด๋น ํ๋กํ ์ฝ, ์ธ์ฆ ๋ฐ ์์ฒญ ํ์์ ๋ณ๋์ ์ง์์ด ํ์ํฉ๋๋ค.
-
url- ํ์ string: ์ ์ฒด ์ฃผ์ http:// ๋๋ https://. example.com์ ์๋น์ค ์ฃผ์๋ก ๋ฐ๊ฟ๋๋ค. ์ด ์์ฒญ์๋ ๊ฒ์ ๋ฐ ๊ฒ์ ์๋ฒ๊ฐ ํ์ํ์ง ์์ต๋๋ค. ๊ฒ์ ํ๋ก์ ํ๋กํ์ด ์๋ ํ๋ก์ธ์ค์ ์ผ๋ฐ ๋คํธ์ํฌ ์ฐ๊ฒฐ์ด ์ฌ์ฉ๋ฉ๋๋ค. -
postDataโ ์์ฒญ ๋ณธ๋ฌธ์ด ์๋ ํ์ string์ ๋๋ค. UTF-8์์ ์ฝํ ์ธ ์ ํ: text/plain; charset=utf-8. ์๋ ์์ ์ธ์ฝ๋ฉ ๋ฐ application/json์ผ๋ก์ ์ ํ์ ์์ต๋๋ค. System.Text.Json.JsonSerializer.Serialize๋ ํ ์คํธ๋ง ์์ฑํฉ๋๋ค. ์์ ์๋ฒ๋ JSON๋ฅผ ์ ํํ๊ฒ text/plain์ผ๋ก ํ์ฉํด์ผ ํฉ๋๋ค. ์ด๋ฌํ ๋ช ๋ น์ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์ ์ ์ ํค๋๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
string โ ์๋ต ํ ์คํธ; HTTP_Body()๋ฅผ ํตํด์๋ ์ ๊ทผํ ์ ์์ต๋๋ค. ์ด๋ bool๋ ์๋๊ณ ์ฝ๋ HTTP๋ ์๋๋๋ค. ๋น ๋ฌธ์์ด์ ์ค๋ฅ๋ฅผ ๋ํ๋ด์ง ์์ง๋ง, ๋น์ด ์์ง ์์ ๋ฌธ์์ด์ ์๋ฒ์์์ ์์ ์ฑ๊ณต์ ๋ํ๋ด์ง ์์ต๋๋ค.
- ๋ง์ง๋ง ์๋ต์ ์คํฌ๋ฆฝํธ์ ํ์ฌ ๋ฐํ์์๋ง ์ ์ฅ๋ฉ๋๋ค. ์ด ๋ฐํ์์ ๋ค์ GET/POST๊ฐ ์ด๋ฅผ ๋์ฒดํฉ๋๋ค. ๋์์ ์คํ๋๋ ๋ค๋ฅธ ์คํฌ๋ฆฝํธ๋ ์ด๋ฅผ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค. ๋ต๋ณ์ ํ๋กํ์ ์ ์ฅ๋์ง ์์ต๋๋ค. ๋ค์ ์์ฒญ ์ดํ์ ํ์ํ๋ค๋ฉด ๋ณธ๋ฌธ๊ณผ ํค๋๋ฅผ ๋ฏธ๋ฆฌ ๋ณ์์ ๋ณต์ฌํด ๋์ธ์.
- GET/POST ์คํ ์ค์ธ ์คํฌ๋ฆฝํธ ์ค๋ ๋์์ ์๋ต์ ๊ธฐ๋ค๋ฆฝ๋๋ค. ๋ณธ๋ฌธ์ ์์ฒญํ๊ณ ์ฝ๋ ๋ฐ ๊ฑธ๋ฆฌ๋ ์ด ์๊ฐ์ 20์ด์ ๋๋ค. ์คํฌ๋ฆฝํธ๋ฅผ ์ค์งํ๋ฉด ๋๊ธฐ๊ฐ ์ทจ์๋ฉ๋๋ค. HTTP_Body/HTTP_Header ์๋ฌด๊ฒ๋ ๊ธฐ๋ํ์ง ๋ง์ธ์. FileStream๊ฐ ์ ์ก๋๋ ๊ฒฝ์ฐ์๋ ์ ์ฒด ๋ณธ๋ฌธ์ด ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋๋ฉ๋๋ค. ์ด๋ ๋์ฉ๋ ํ์ผ์ ์คํธ๋ฆฌ๋ฐ ๋ค์ด๋ก๋๊ฐ ์๋๋๋ค.
- ์ธ์ฝ๋ฉ์ด ์๊ฑฐ๋ ์ ์ ์๋ ๊ฒฝ์ฐ(UTF-8) ํ ์คํธ๋ ์๋ต์ ๋ฌธ์ ์ธํธ์ ๋ฐ๋ผ ๋์ฝ๋ฉ๋ฉ๋๋ค. ๋ต๋ณ HTTP 4xx/5xx๋ ์ฝ์ต๋๋ค. ๋คํธ์ํฌ ์ค๋ฅ๋ ์๊ฐ ์ด๊ณผ๊ฐ ๋ฐ์ํ๋ฉด ํด๋ผ์ด์ธํธ๋ ์ค๋ฅ๋ฅผ ๊ธฐ๋กํ๊ณ ๋ณธ๋ฌธ๊ณผ ํค๋๋ ๋น์ด ์๊ฒ ๋ฉ๋๋ค. Try/Catch๋ ์์ ์๋ต ํ์ธ์ ๋์ฒดํ์ง ์์ต๋๋ค. ์คํฌ๋ฆฝํธ ์ทจ์๊ฐ ๋์ฑ ํ์ฅ๋ฉ๋๋ค. ๋ก์ปฌ ํ์ผ ์ฐ๊ธฐ ๋๋ ์๋ชป๋ ์ธ์ ์ค๋ฅ๋ Try/Catch๋ฅผ ํตํด ํฌ์ฐฉ๋ ์ ์์ต๋๋ค.
- POST ๋ณธ๋ฌธ๊ณผ ํค๋๋ฅผ ์ ๋ฐ์ดํธํ๊ณ ๋์ผํ ๋ณธ๋ฌธ์ ๋ฌธ์์ด๋ก ๋ฐํํฉ๋๋ค. ์๋ต์ด ๋น์ด ์๋ค๋ ์ด์ ๋ง์ผ๋ก POST์ ์๋์ผ๋ก ๋ฐ๋ณตํ์ง ๋ง์ธ์. ์๋ฒ๊ฐ ์ด๋ฏธ ์์ ์ ์ํํ์ ์๋ ์์ต๋๋ค. ์์ ์ ์น์ธ/์ํ ํ์ธ์ HTTP-์ฑ๊ณต์ ๋ํ ๊ธฐ๋ณธ ์ ๊ณต ๊ธฐํธ๊ฐ ์๋๋ผ ์๋น์ค์ ๋ํ ๋์์ ๋๋ค.
๊ฐ ์์ ๋ ๋ณ๋์ ํ์ผ .csx๋ก ์ ์ฅํ๊ณ IDE์์ ์คํํ ์ ์์ต๋๋ค. UO ๊ฐ์ฒด์ ๋๊ธฐ ๊ธฐ๋ฅ์ ํ์ฌ ๊ฒ์ ์ธ์
์ ํธ์คํธ๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ฐ๋ชจ serial ์ด๋ฆ, ์ขํ, ์ฃผ์๋ฅผ ์์ ์ ๊ฒ์ผ๋ก ๋ฐ๊พธ์ธ์.
์ด ์ฝ๋๋ฅผ ๋ณ๋์ .csx ํ์ผ๋ก ์คํํ์ธ์. ์ธ์๋ ํธ์ถ์ ์ง์ ํ์๋ฉ๋๋ค. ์์ ์ ์ด๋ฆ, serial, ์ฃผ์๋ฅผ ์์ ์ ๊ฐ์ผ๋ก ๋ฐ๊พธ์ธ์.
ํ ๋ฒ์ ํธ์ถ ๊ฒฐ๊ณผ๋ฅผ ์ ๋์ ํ์ํฉ๋๋ค. ์ซ์๋ฅผ bool๋ก ๋ณํํ์ง ์์ผ๋ฉฐ, ๋ฐฐ์ด์ด๋ฉด ์์ ์๋ฅผ ํ์ํฉ๋๋ค.
object? result = UO.HTTP_Post("https://example.com/", "Hello from C#");
UO.Print(result is Array values ? "Count: " + values.Length : Convert.ToString(result));๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- ์๋น์ค๋ Route ์ค์ง๋จ ํ ์คํธ๋ฅผ ์๋ฝํ๊ณ ๋์์ ๋ฐ๋ผ ์๋ฝ๋จ์ผ๋ก ์๋ตํฉ๋๋ค. Main์ ์ด ํ ์คํธ๋ก๋ง true๋ฅผ ๋ฐํํฉ๋๋ค. ์ด๋ HTTP ์ฝ๋ ํ์ธ์ด ์๋ ์๋น์ค ํ๋กํ ์ฝ ํ์ธ์ ๋๋ค.
- example.com ์ฃผ์๋ ์์์ผ ๋ฟ์ด๋ฉฐ ๊ทธ๋ฌํ ์๋น์ค๋ฅผ ์ ๊ณตํ์ง ์์ต๋๋ค. ์์ ์ ๊ฒ์ผ๋ก ๊ต์ฒดํ์ญ์์ค. ์์ ๋ฅผ ์คํํ๋ฉด ์ค์ HTTP ์ฟผ๋ฆฌ๊ฐ ์์ฑ๋ฉ๋๋ค. ์ด ์์์๋ ๊ฒ์ ์์ ์ ์ํํ์ง ์์ต๋๋ค.
var reply = UO.HTTP_Post("https://example.com/C#-event", "Route stopped");
return Truth(TrimText(reply) == "accepted");
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
string TrimText(object? value) => (Convert.ToString(value) ?? "").Trim();๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- System.Text.Json.JsonSerializer๋ ์ฌ์ ๋ฌธ์์ด์ ์ด์ค์ผ์ดํํฉ๋๋ค. JSON๋ฅผ ํ์ธํ ํ ์ํ ๊ฐ์ ์ฝ์ต๋๋ค. ๋ฐ๋ชจ ์ฃผ์๋ฅผ ๊ทํ์ ๊ฒ์ผ๋ก ๋ฐ๊พธ์ญ์์ค.
return RunScenario();
object? RunScenario()
{
var report = new Dictionary<string, string>
{
["event"] = "route-stopped",
["text"] = "line one\nline two"
};
string payload = System.Text.Json.JsonSerializer.Serialize(report);
string reply = Convert.ToString(UO.HTTP_Post("https://example.com/csharp-report", payload)) ?? "";
try
{
using (var document = System.Text.Json.JsonDocument.Parse(reply))
{
return document.RootElement.TryGetProperty("status", out var value) ? value.GetString() : "unknown";
}
}
catch (System.Text.Json.JsonException)
{
return "invalid response";
}
return null;
}๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- firstReply ๋ฐ firstHeaders๋ ๋ต๋ณ POST๋ฅผ ์ ์ฅํฉ๋๋ค. ํ์ GET๋ ๋ด๋ถ ๋ฒํผ๋ฅผ ๋์ฒดํ์ง๋ง ๋ก์ปฌ ๋ณ์์๋ ์ฌ์ ํ ์ฒซ ๋ฒ์งธ ์๋ต์ด ํฌํจ๋ฉ๋๋ค.
- example.com ์ฃผ์๋ ์์์ผ ๋ฟ์ด๋ฉฐ ๊ทธ๋ฌํ ์๋น์ค๋ฅผ ์ ๊ณตํ์ง ์์ต๋๋ค. ์์ ์ ๊ฒ์ผ๋ก ๊ต์ฒดํ์ญ์์ค. ์์ ๋ฅผ ์คํํ๋ฉด ์ค์ HTTP ์ฟผ๋ฆฌ๊ฐ ์์ฑ๋ฉ๋๋ค. ์ด ์์์๋ ๊ฒ์ ์์ ์ ์ํํ์ง ์์ต๋๋ค.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var firstReply = UO.HTTP_Post("https://example.com/C#-event", "Route stopped");
var firstHeaders = UO.HTTP_Header();
UO.HTTP_Get("https://example.com/C#-status");
return firstReply + "|" + firstHeaders;
return null;
}
}C#์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํฉ๋๋ค. ์ ํํ UO ์ด๋ฆ์ ์ฌ์ฉํ์ธ์. ์ซ์ ํ๋๊ทธ๋ 0๊ณผ ๋น๊ตํ๊ณ ๋ฐํ ํ์์ด bool์ผ ๋๋ง bool์ ์ฌ์ฉํ์ธ์.
๋งค๊ฐ๋ณ์: url (Any), postData (Any)
๊ฒฐ๊ณผ: dynamic / Any.
ํธ์ถ ์:
-
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility. -
ClassicUO.Game.Managers.ClassicUOInjectionApiBridge.HttpRequest:bridge.HttpRequest("POST", Text(0), Text(1)). -
InjectionScript.Runtime.InjectionApiUO.ExecuteClientApiCompatibility::Text:Text(0).
๋ด๋ถ ๊ตฌํ ์ฝ๋์ด๋ฉฐ ๋ ๋ฆฝ ์คํฌ๋ฆฝํธ๋ก ์คํํ ์ ์์ต๋๋ค.
case "http_post":
{
string[] response = bridge.HttpRequest("POST", Text(0), Text(1));
httpBody = response.Length > 0 ? response[0] : string.Empty;
httpHeader = response.Length > 1 ? response[1] : string.Empty;
return new InjectionValue(httpBody);
}ะฃะบัะฐัะฝััะบะฐ ยท ะ ัััะบะธะน ยท English ยท Deutsch ยท Franรงais ยท Italiano ยท Espaรฑol ยท ็น้ซไธญๆ ยท ๆฅๆฌ่ช ยท ํ๊ตญ์ด
dynamic UO.Messenger(object? provider);๋ฌธ์ ์๋ฆผ ๋ฐ Telegram, Discord ๋๋ Viber ๋ฉ์์ง ์์ ์ ์ํ ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค. ์๋ฅผ ๋ค์ด ์คํฌ๋ฆฝํธ๋ ๋ฆฌ์์ค ์์ง ์ข ๋ฃ๋ฅผ ์๋ฆฌ๊ฑฐ๋ ๋ฏธ๋ฆฌ ์ง์ ๋ ์ฌ์ฉ์์ ์ค์ง ์์ฒญ์ ํ์ธํ ์ ์์ต๋๋ค. ๊ฐ์ฒด๋ฅผ ์์ฑํด๋ ์์ง ๋ด์ ์ฐ๊ฒฐ๋์ง ์์ผ๋ฉฐ ์๋ฌด ๊ฒ๋ ๋ณด๋ด์ง ์์ต๋๋ค.
-
provider- string: "์ ๋ณด", "๋์ค์ฝ๋" ๋๋ "๋ฐ์ด๋ฒ"; ๊ฒฝ์ฐ๋ ์ค์ํ์ง ์์ต๋๋ค. ๋ค๋ฅธ ๊ฐ์ ์ค๋ฅ๋ฅผ ๋ฐ์์ํต๋๋ค.
๊ฐ์ฒด Messenger. ์ด๊ฒ์ bool๋ ์๋๊ณ ID๋ ์๋๋๋ค. ID ์ด ๊ฐ์ฒด์ ๋ฉ์์ง, ๋ณด๋ธ ์ฌ๋ ๋ฐ ์ฑํ ์ ํญ์ string์ ๋๋ค. ๋ฌธ์์ด๊ณผ ๋น๊ตํ๊ณ Convert.ToInt32/Convert.ToDouble๋ฅผ ํตํด ๋ณํํ์ง ๋ง์ธ์.
-
Provider() โ string;Connected() โ 1/0(true/false) : ๋ฒค๋ ๋ฐ ์ต์ข ์น์ธ ํ์ธ ๊ฒฐ๊ณผ. Connected๋ ํ์ฌ ์ธํฐ๋ท ๊ฐ์ฉ์ฑ์ ๋ณด์ฅํ์ง ์์ต๋๋ค. -
Connect(token) โ null: ๋ด ํ ํฐ์ ํ์ธํฉ๋๋ค.ConnectFromFile(path) โ null: ํ์ผ์์ ์ต๋ 1024 ๋ฐ์ดํธ๊น์ง UTF-8 ํ ํฐ์ ์ฝ์ต๋๋ค. ์๋ ๊ฒฝ๋ก๋ ํ์ฌ ์คํฌ๋ฆฝํธ ํด๋์์ ๊ณ์ฐ๋ฉ๋๋ค. ๋ค์ ์ฐ๊ฒฐํ๋ ค๋ฉด Disconnect๊ฐ ํ์ํฉ๋๋ค. Try/Catch๋ฅผ ํตํด ์ค๋ฅ๋ฅผ ํฌ์ฐฉํ ์ ์์ต๋๋ค. -
Disconnect() โ null: ๋ก์ปฌ ์์ ์ ์ค์งํ๊ณ ํ ํฐ๊ณผ ์ปค์๋ฅผ ์ง์๋๋ค. ๊ฐ์ฒด๋ฅผ ๋ค์ ์ฐ๊ฒฐํ ์ ์์ต๋๋ค.Dispose() โ null: ๊ฐ์ฒด๋ฅผ ์์ ํ ๋ซ์ต๋๋ค. -
SendMessage(text, recipient) โ string: ID ๋ฉ์์ง๋ฅผ ๋ฐ์์ต๋๋ค. ๋งค๊ฐ๋ณ์ - ํ ์คํธ ๋ฐ ๋ฌธ์์ด ์ฑํ ID ํ ๋ ๊ทธ๋จ, ์ฑ๋ ID Discord ๋๋ ID Viber ๊ฐ์ ์. ๊ธธ์ด ์ ํ: ๊ฐ๊ฐ 4096/2000/7000; ๋ํ Viber JSON โค30000 ๋ฐ์ดํธ์ ๋๋ค. ๋น ํ ์คํธ๋ ๊ธ์ง๋ฉ๋๋ค. Discord๋ ๋ชจ๋ ์ฌ๋/์ญํ ์ ๋ํ ์ธ๊ธ์ ์์ฑํ์ง ์์ต๋๋ค. -
WatchChannel(channelId) โ null: Discord๋ ํ์ฌ ๋ง์ง๋ง ๋ฉ์์ง๋ฅผ ๊ธฐ์ตํ๊ณ ๋ค์ ๋ฉ์์ง๋ง ์ฝ์ต๋๋ค.WatchChannel(channelId, afterMessageId) โ null: ์ฃผ์ด์ง ๋ฌธ์์ด ID ๋ค์์ ์์ํฉ๋๋ค. '0'์๋ ๊ธฐ๋ก์ด ํฌํจ๋ฉ๋๋ค. ๊ฐ์ฒด๋น ์ต๋ 32 ์ฑ๋. -
Receive(timeoutSeconds) โ Array;Receive(): 0 ์๊ฐ ์ด๊ณผ. ๋ฒ์ 0..20 ์ด; ๋น ๋ฐฐ์ด์ ์ฌ์ฉ ๊ฐ๋ฅํ ๋ฌธ์ ๋ฉ์์ง๊ฐ ์์์ ์๋ฏธํฉ๋๋ค. Telegram์ long ํด๋ง์ ์ฌ์ฉํ๊ณ , Discord๋ ์ ํํ ์ฑ๋์ ํด๋งํ๊ณ , Viber๋ ์นํ ๋๊ธฐ์ด์ ์ฝ์ต๋๋ค. ๋คํธ์ํฌ ์์ฒญ์๋ ์ต๋ 30์ด๊ฐ ์์๋ ์ ์์ต๋๋ค. - ๊ฐ MessengerMessage:
Id(),SenderId(),SenderName(),ChatId(),Text()โ string. ์ฑ๋์ ํ ๋ ๊ทธ๋จ ๊ฒ์๋ฌผ์๋ SenderId์ด ์์ ์ ์์ต๋๋ค. ์ฒจ๋ถ ํ์ผ, ํ ์คํธ๊ฐ ์๋ ์ด๋ฒคํธ, ๋ด์ Discord ๋ฉ์์ง๋ ๋ฐํ๋์ง ์์ต๋๋ค. -
RetryAfter() โ int: ์๋น์ค ์ ํ ํ ๋๊ธฐ ์๊ฐ(์ด)์ ๋๋ค. ์ด ๊ธฐ๊ฐ์ด ๋ง๋ฃ๋๊ธฐ ์ ์๋ ์๋ก์ด HTTP ์์ฒญ์ด ์คํ๋์ง ์์ต๋๋ค. ์คํจ ํ ์ ์ก์ ์๋์ผ๋ก ๋ฐ๋ณต๋์ง ์์ต๋๋ค. ์๋ฒ๊ฐ ์ด๋ฏธ ๋ฉ์์ง๋ฅผ ๋ฐ์์ ์๋ ์์ต๋๋ค. -
StartReceiver(localPort, publicHttpsUrl) โ int: Viber ์ ์ฉ; port 1..65535, ์ฌ์ฉ ์ค์ธ ๋ก์ปฌ ํฌํธ๋ฅผ ๋ฐํํฉ๋๋ค. ๊ณต๊ฐ HTTPS-์ฃผ์๋ /viber/๋ก ๋๋๊ณ ๋ฏธ๋ฆฌ ์๋ ๋ณธ๋ฌธ๊ณผ ์๋ช ํค๋๋ฅผ ์ฌ์ฉํ์ฌ POST๋ฅผ 127.0.0.1:port/viber/๋ก ์ ๋ฌํด์ผ ํฉ๋๋ค. ์ด ๋ฉ์๋๋ Viber์ ์นํ ์ ๋ฑ๋กํฉ๋๋ค. - ๊ฐ์ธ ๊ณ์ ๋น๋ฐ๋ฒํธ๊ฐ ์๋ ๋ด ํ ํฐ์ด ํ์ํฉ๋๋ค. ๊ธฐ์กด ์นํ ์ด ์๋ ํ ๋ ๊ทธ๋จ์ ์ ๊ฑฐํ์ง ์๊ณ ๊ฑฐ๋ถ๋ฉ๋๋ค. Discord์๋ ์ฑ๋ ์ฝ๊ธฐ/์ ์ก ๊ถํ์ด ํ์ํ๋ฉฐ ์ก์ธ์ค ๊ฐ๋ฅํ ํ ์คํธ๋ฅผ ์ํด์๋ MESSAGE_CONTENT๊ฐ ํ์ํฉ๋๋ค. Viber๋ ๊ตฌ๋ ํ ์ฌ์ฉ์์๊ฒ ๋ณด๋ ๋๋ค.
- ์์ ์ ์ ์ฒด ์คํ์ ๊ตฌ๋ฌธ ๋ถ์ํ ํ์๋ง ์ปค์๋ฅผ ์ ์ฅํฉ๋๋ค. Telegram/Discord๋ ์์ฒญ๋น ์ต๋ 100 ํญ๋ชฉ์ ๋ฐํํฉ๋๋ค. ํ์ ํจํท์ ๋ํด ๋ค์ ์์ ์ ํธ์ถํ์ญ์์ค. ๋ ๋ฒ์งธ ๋ ผ์์ด ์๋ ๋ถ์ผ์น WatchChannel๋ ์ด์ ์ด์ผ๊ธฐ๋ฅผ ๊ฑด๋๋๋๋ค.
- Viber๋ ์์ค ๋ณธ๋ฌธ์ HMAC-SHA256์ ํ์ธํฉ๋๋ค. ๋๊ธฐ์ด - 100 ๋ฉ์์ง, ๋ฐ๋ณต๋๋ ID๋ ๋ง์ง๋ง 2048 ์ ๋ฌ์ ๋ํด ์ ์ฅ๋ฉ๋๋ค. ์ค๋ฒํ๋ก๋ ์๋น์ค๋ณ ์ฌ์๋๋ฅผ ์ํด HTTP 503๋ฅผ ์ ๊ณตํฉ๋๋ค. Content-Length๊ฐ ์๋ HTTPS ํ๋ก์๊ฐ ํ์ํฉ๋๋ค. ๋ก์ปฌ ์ ๋ ฅ์ ๋ํ ์ฒญํฌ ์์ฒญ์ ๊ฑฐ๋ถ๋ฉ๋๋ค.
- ํ ํฐ์ Connect ํ๋กํ, ์ค๋ฅ ํ ์คํธ ๋๋ ์ธ์ ๊ธฐ๋ก์ ๊ธฐ๋ก๋์ง ์์ต๋๋ค. ๋๋ฒ๊ฑฐ์ ํ์๋๋ ์คํฌ๋ฆฝํธ ๋ณ์์ ์ ์ฅํ์ง ์์ผ๋ ค๋ฉด ConnectFromFile๋ฅผ ์ฌ์ฉํ์ธ์. ํ ํฐ ํ์ผ์ ๊ฒ์ํ์ง ๋ง์ญ์์ค.
- ํ๋ก์์ ๋ด๋ถ์ ๊ฐ์ฒด๋ฅผ ๋ง๋ญ๋๋ค. ๋์์ 32 ์ดํ; /Dispose๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ์ผ์ฐ ํด์ ๋ฉ๋๋ค. ์คํฌ๋ฆฝํธ๊ฐ ์๋ฃ๋๊ฑฐ๋ ์คํจํ๊ฑฐ๋ ์ค์ง๋๋ฉด ๋ชจ๋ ๋ฉ์ ์ ๊ฐ์ฒด๊ฐ ๋ซํ๋๋ค. Viber ์์ ๊ธฐ๋ฅผ ๋ซ์๋ ์๋น์ค์์ ์นํ ์ด ์ญ์ ๋์ง๋ ์์ต๋๋ค.
- ์ด๊ฒ์ ํ ์คํธ ์ธํฐํ์ด์ค์ ๋๋ค. ์์ ๋ ํ ์คํธ๋ฅผ ์ฝ๋๋ก ์คํํ์ง ์์ผ๋ฉฐ ๊ฒ์ ๊ณ์ ์ ์ฐ๊ฒฐํ์ง ์์ต๋๋ค. ๋ณด๋ธ ์ฌ๋์ ์ ๋ขฐํ๊ธฐ ์ํ ์กฐ๊ฑด์ ์คํฌ๋ฆฝํธ ์์ฒด์์ ์ค์ ๋ฉ๋๋ค.
๊ฐ ์์ ๋ ๋ณ๋์ ํ์ผ .csx๋ก ์ ์ฅํ๊ณ IDE์์ ์คํํ ์ ์์ต๋๋ค. UO ๊ฐ์ฒด์ ๋๊ธฐ ๊ธฐ๋ฅ์ ํ์ฌ ๊ฒ์ ์ธ์
์ ํธ์คํธ๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ฐ๋ชจ serial ์ด๋ฆ, ์ขํ, ์ฃผ์๋ฅผ ์์ ์ ๊ฒ์ผ๋ก ๋ฐ๊พธ์ธ์.
์ด ์ฝ๋๋ฅผ ๋ณ๋์ .csx ํ์ผ๋ก ์คํํ์ธ์. ์ธ์๋ ํธ์ถ์ ์ง์ ํ์๋ฉ๋๋ค. ์์ ์ ์ด๋ฆ, serial, ์ฃผ์๋ฅผ ์์ ์ ๊ฐ์ผ๋ก ๋ฐ๊พธ์ธ์.
dynamic messenger = UO.Messenger("telegram");
UO.Print(messenger.Provider());
messenger.Dispose();๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- telegram-token.txt๋ฅผ ์คํฌ๋ฆฝํธ ์์ ๋๊ณ 12345678๋ฅผ ์ฑํ ID๋ก ๋ฐ๊พธ์ธ์. ์ด ์์์๋ ํ๋์ ์๋ฆผ์ ๋ณด๋ด๊ณ ID ๋ฌธ์์ด์ ๋ฐํํฉ๋๋ค. ์๋ฒ ์๋ต์ ์์ ํ๋ค๊ณ ํด์ ์ฌ๋์ด ์ฝ์ ๋ด์ฉ์ ํ์ธํ๋ ๊ฒ์ ์๋๋๋ค.
- ์์ ๋ง์ ๋ด ์ค์ ์ด ํ์ํฉ๋๋ค. ์์ ๋ ๋ก์ปฌ ํ ์คํธ ๋ต๋ณ์ผ๋ก ํ ์คํธ๋ฉ๋๋ค. ์ค์ ์ฌ์ฉ์์๊ฒ ์ ์ก๋์ง ์์์ต๋๋ค.
var bot = UO.Messenger("telegram");
using (var resource = bot)
{
bot.ConnectFromFile("telegram-token.txt");
var messageId = bot.SendMessage("Harvest finished", "12345678");
return messageId;
}๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- ์ฑ๋๊ณผ ID ํ์ฉ๋ ๋ฐ์ ์๋ฅผ ์ ๋ ฅํ์ธ์. true ์ด ์ํ๊ฐ ๊ทธ ์ฌ๋์ผ๋ก๋ถํฐ ๋ฌธ์ ์ค์ง๋ฅผ ๋ฐ์๋ค๋ ์๋ฏธ์ ๋๋ค. ์์ ์์ฒด๋ ์์ง์์ ๋ฉ์ถ์ง ์์ต๋๋ค. ์ด ๊ฒฐ๊ณผ๋ ๊ทํ์ ๋ํฐ ์ฌ์ดํด ์กฐ๊ฑด์์ ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
- ์์ ๋ง์ ๋ด ์ค์ ์ด ํ์ํฉ๋๋ค. ์์ ๋ ๋ก์ปฌ ํ ์คํธ ๋ต๋ณ์ผ๋ก ํ ์คํธ๋ฉ๋๋ค. ์ค์ ์ฌ์ฉ์์๊ฒ ์ ์ก๋์ง ์์์ต๋๋ค.
return RunScenario();
object? RunScenario()
{
var bot = UO.Messenger("discord");
using (var resource = bot)
{
bot.ConnectFromFile("discord-token.txt");
bot.WatchChannel("123456789012345678");
var messages = bot.Receive(5);
foreach (var message in messages)
{
if (Truth(message.SenderId() == "987654321098765432") && Truth(Convert.ToString(TrimText(message.Text())) == "stop"))
{
return true;
}
}
return false;
}
return null;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
string TrimText(object? value) => (Convert.ToString(value) ?? "").Trim();๋งค๊ฐ๋ณ์์ ์คํ ํ๋ฆ:
- System.Text.Json์ ๋ก์ปฌ ํฌํธ/publicUrl๋ฅผ ์ฝ์ต๋๋ค. ํ ํฐ์ ๋ณ๋์ ๋ก์ปฌ ํ์ผ์ ์ ์ฅ๋ฉ๋๋ค. ์ด ์์์๋ ์ค์ ๋์คํจ์น๊ฐ ์ํ๋์ง ์์ต๋๋ค. ์์์ ์์ ํ ์คํธ๊ฐ ์๋ ์ ๋ขฐํ ์ ์๋ SenderId์ด ํ์ธ๋์์ต๋๋ค.
return new ScriptScenario(UO, WaitAsync, Args, Cancellation, Checkpoint).RunScenario();
class ScriptScenario
{
private readonly global::ClassicUO.CSharp.CSharpGameApi UO;
private readonly Func<int, Task> WaitAsync;
private readonly string[] Args;
private readonly CancellationToken Cancellation;
private readonly Action Checkpoint;
public ScriptScenario(global::ClassicUO.CSharp.CSharpGameApi api, Func<int, Task> wait, string[] args, CancellationToken cancellation, Action checkpoint)
{
UO = api;
WaitAsync = wait;
Args = args;
Cancellation = cancellation;
Checkpoint = checkpoint;
}
public object? RunScenario()
{
var settingsDocument = System.Text.Json.JsonDocument.Parse(System.IO.File.ReadAllText("viber-settings.json"));
using (settingsDocument)
{
var settings = settingsDocument.RootElement;
var bot = UO.Messenger("viber");
using (var resource = bot)
{
bot.ConnectFromFile("viber-token.txt");
bot.StartReceiver(settings.GetProperty("port").GetInt32(), settings.GetProperty("publicUrl").GetString());
var messages = bot.Receive(5);
foreach (var message in messages)
{
if (Truth(message.SenderId() == "trusted-subscriber-id"))
{
return message.Text();
}
}
return "";
}
}
return null;
}
bool Truth(object? value) => value is bool flag ? flag : value is string text ? !string.IsNullOrEmpty(text) : value != null && Convert.ToDouble(value) != 0;
}C#์ ๋์๋ฌธ์๋ฅผ ๊ตฌ๋ถํฉ๋๋ค. ์ ํํ UO ์ด๋ฆ์ ์ฌ์ฉํ์ธ์. ์ซ์ ํ๋๊ทธ๋ 0๊ณผ ๋น๊ตํ๊ณ ๋ฐํ ํ์์ด bool์ผ ๋๋ง bool์ ์ฌ์ฉํ์ธ์.
๋งค๊ฐ๋ณ์: provider (String)
๊ฒฐ๊ณผ: dynamic / Object.
ํธ์ถ ์:
๋ด๋ถ ๊ตฌํ ์ฝ๋์ด๋ฉฐ ๋ ๋ฆฝ ์คํฌ๋ฆฝํธ๋ก ์คํํ ์ ์์ต๋๋ค.
private InjectionObject CreateMessenger(string provider)
{
var owner=NativeScriptResourceScope.Current??throw new StatementFailedException("Create messenger objects inside an active C# script execution.");owner.Checkpoint();
var client=MessengerFactory!=null?MessengerFactory(provider,()=>owner.Cancellation,owner.Checkpoint):new Messaging.MessengerClient(provider,()=>owner.Cancellation,owner.Checkpoint);
var resource=new MessengerObject(client,owner.Forget,file=>Path.GetFullPath(Path.Combine(paths.ScriptPath??string.Empty,file)));owner.Track(resource);return resource;
}