cursor ai 가 내가 원하는 스크립트 언어을 만들어줌, 아직 수정할께 많은데 이러면 최적의 스크립트 언어을 만들어 쓰는게 유리할수도 있음

using UnityEngine;
using System.Collections.Generic;
using System.Linq;

public class ScriptLanguage
{
    private Dictionary<string, object> variables = new Dictionary<string, object>();
    private Dictionary<string, List<string>> functions = new Dictionary<string, List<string>>();
    private Dictionary<string, ScriptLanguage> modules = new Dictionary<string, ScriptLanguage>();
    
    public void ExecuteScript(string script)
    {
        string[] lines = script.Split('\n');
        int currentLine = 0;
        
        while (currentLine < lines.Length)
        {
            string line = lines[currentLine].Trim();
            if (!string.IsNullOrEmpty(line) && !line.StartsWith("--"))
            {
                currentLine = ExecuteLine(line, lines, currentLine);
            }
            currentLine++;
        }
    }
    
    private int ExecuteLine(string line, string[] lines, int currentLine)
    {
        if (line.StartsWith("function"))
        {
            string funcName = line.Split(' ')[1].Split('(')[0].Trim();
            List<string> funcBody = new List<string>();
            currentLine++;
            
            while (currentLine < lines.Length && !lines[currentLine].Trim().StartsWith("end"))
            {
                funcBody.Add(lines[currentLine].Trim());
                currentLine++;
            }
            functions[funcName] = funcBody;
            return currentLine;
        }
        else if (line.StartsWith("if"))
        {
            string condition = line.Substring(2).Trim();
            bool result = EvaluateCondition(condition);
            if (!result)
            {
                while (currentLine < lines.Length && !lines[currentLine].Trim().StartsWith("end"))
                {
                    currentLine++;
                }
            }
            return currentLine;
        }
        else if (line.StartsWith("for"))
        {
            string[] parts = line.Substring(3).Split('=');
            string varName = parts[0].Trim();
            string[] range = parts[1].Split(' ');
            int start = int.Parse(range[0]);
            int end = int.Parse(range[2]);
            
            for (int i = start; i <= end; i++)
            {
                variables[varName] = i;
                int tempLine = currentLine + 1;
                while (tempLine < lines.Length && !lines[tempLine].Trim().StartsWith("end"))
                {
                    ExecuteLine(lines[tempLine].Trim(), lines, tempLine);
                    tempLine++;
                }
            }
            
            while (currentLine < lines.Length && !lines[currentLine].Trim().StartsWith("end"))
            {
                currentLine++;
            }
            return currentLine;
        }
        else if (line.StartsWith("import"))
        {
            string moduleName = line.Substring(6).Trim();
            ScriptLanguage module = new ScriptLanguage();
            modules[moduleName] = module;
            return currentLine;
        }
        else if (line.Contains("="))
        {
            string[] parts = line.Split('=');
            string varName = parts[0].Trim();
            string value = parts[1].Trim();
            
            if (value.Contains("+") || value.Contains("-") || value.Contains("*") || value.Contains("/"))
            {
                variables[varName] = EvaluateExpression(value);
            }
            else if (value.StartsWith("\"") && value.EndsWith("\""))
            {
                variables[varName] = value.Trim('"');
            }
            else if (float.TryParse(value, out float numValue))
            {
                variables[varName] = numValue;
            }
        }
        else if (line.StartsWith("print"))
        {
            string content = line.Substring(5).Trim();
            content = content.Trim('"');
            Debug.Log(content);
        }
        else if (functions.ContainsKey(line.Split('(')[0].Trim()))
        {
            string funcName = line.Split('(')[0].Trim();
            foreach (string funcLine in functions[funcName])
            {
                ExecuteLine(funcLine, new string[] { funcLine }, 0);
            }
        }
        
        return currentLine;
    }
    
    private float EvaluateExpression(string expression)
    {
        expression = expression.Replace(" ", "");
        if (expression.Contains("+"))
        {
            string[] parts = expression.Split('+');
            return float.Parse(parts[0]) + float.Parse(parts[1]);
        }
        else if (expression.Contains("-"))
        {
            string[] parts = expression.Split('-');
            return float.Parse(parts[0]) - float.Parse(parts[1]);
        }
        else if (expression.Contains("*"))
        {
            string[] parts = expression.Split('*');
            return float.Parse(parts[0]) * float.Parse(parts[1]);
        }
        else if (expression.Contains("/"))
        {
            string[] parts = expression.Split('/');
            return float.Parse(parts[0]) / float.Parse(parts[1]);
        }
        return 0;
    }
    
    private bool EvaluateCondition(string condition)
    {
        if (condition.Contains("=="))
        {
            string[] parts = condition.Split(new[] { "==" }, System.StringSplitOptions.None);
            return float.Parse(parts[0].Trim()) == float.Parse(parts[1].Trim());
        }
        else if (condition.Contains(">"))
        {
            string[] parts = condition.Split('>');
            return float.Parse(parts[0].Trim()) > float.Parse(parts[1].Trim());
        }
        else if (condition.Contains("<"))
        {
            string[] parts = condition.Split('<');
            return float.Parse(parts[0].Trim()) < float.Parse(parts[1].Trim());
        }
        return false;
    }
    
    public object GetVariable(string name)
    {
        return variables.ContainsKey(name) ? variables[name] : null;
    }
    
    public ScriptLanguage GetModule(string name)
    {
        return modules.ContainsKey(name) ? modules[name] : null;
    }
}

 

 

-- 수학 연산자 예제
a = 10
b = 5
result = a + b
print "덧셈 결과: " + result
result = a * b
print "곱셈 결과: " + result

-- 조건문 예제
if a > b
    print "a가 b보다 큽니다"
end

-- 반복문 예제
for i = 1 5
    print "반복 횟수: " + i
end

-- 함수 정의와 호출 예제
function greet(name)
    print "안녕하세요, " + name + "님!"
end
greet("플레이어")

-- 모듈 예제
import math
math.a = 100
math.b = 200
print "모듈 변수 a: " + math.a
print "모듈 변수 b: " + math.b
Posted by 아기곰푸우
,

https://mvnrepository.com/ 

 

 

안드로이드 라이브러리 다운받기

Posted by 아기곰푸우
,

using System;
using System.Text;
using NATS.Client;
using NATS.Net;
using Systehttp://m.Threading.Tasks;
using NATS.Client.Core;
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;

public class NatSample : MonoBehaviour
{
    private NatsClient client;
    private const string NATS_URL = "ws://35.208.138.76:8282"; // NATS 서버 주소
    private Dictionary<string, IAsyncSubscription<string>> subscriptions = new Dictionary<string, IAsyncSubscription<string>>();

    async void Start()
    {
        await ConnectToNats();
    }

    async Task ConnectToNats()
    {
        try
        {
            client = new NatsClient(new NatsOpts { Url = NATS_URL });
            Debug.Log("Connected to NATS server");
        }
        catch (Exception e)
        {
            Debug.LogError($"NATS Connection Error: {e.Message}");
        }
    }

    public async Task AddSubject(string subject)
    {
        if (client == null || subscriptions.ContainsKey(subject))
            return;

        try
        {
            var subscription = client.SubscribeAsync<string>(subject);
            subscriptions[subject] = subscription;

            _ = Task.Run(async () =>
            {
                await foreach (var msg in subscription)
                {
                    Debug.Log($"Received on {subject}: {msg.Data}");
                    UpdateChatDisplay($"{subject}: {msg.Data}");
                }
            });

            Debug.Log($"Added subscription to subject: {subject}");
        }
        catch (Exception e)
        {
            Debug.LogError($"Error adding subject {subject}: {e.Message}");
        }
    }

    public async Task RemoveSubject(string subject)
    {
        if (client == null || !subscriptions.ContainsKey(subject))
            return;

        try
        {
            await subscriptions[subject].DisposeAsync();
            subscriptions.Remove(subject);
            Debug.Log($"Removed subscription from subject: {subject}");
        }
        catch (Exception e)
        {
            Debug.LogError($"Error removing subject {subject}: {e.Message}");
        }
    }

    public async Task SendMessage(string subject, string message)
    {
        if (client == null) return;

        try
        {
            await client.PublishAsync(subject, message);
            Debug.Log($"Sent to {subject}: {message}");
        }
        catch (Exception e)
        {
            Debug.LogError($"Error sending message: {e.Message}");
        }
    }

    void UpdateChatDisplay(string message)
    {
        Debug.Log("msg:" + message);
    }

    async void OnApplicationQuit()
    {
        if (client != null)
        {
            foreach (var subscription in subscriptions.Values)
            {
                await subscription.DisposeAsync();
            }
            await client.DisposeAsync();
        }
    }
}

Posted by 아기곰푸우
,
using System;
using System.Text;
using NATS.Client;
using NATS.Net;
using System.Threading.Tasks;
using NATS.Client.Core;
using UnityEngine;
using UnityEngine.UI;

public class NatSample : MonoBehaviour
{
    private NatsClient client;
    //private const string NATS_URL = "nats://localhost:4222"; // NATS 서버 주소
    private const string NATS_URL = "ws://localhost:8282"; // NATS 서버 주소

    private const string SUBJECT = "test"; // 채팅 채널
    async void Start()
    {
        await ConnectToNats();
    }

    async Task ConnectToNats()
    {
        try
        {
            client = new NatsClient(new NatsOpts { Url = NATS_URL });
            await foreach (var msg in client.SubscribeAsync<string>(SUBJECT))
            {
                Debug.Log($"Received: {msg}");
                UpdateChatDisplay(msg.Data);
            }
        }
        catch (Exception e)
        {
            Debug.LogError($"NATS Connection Error: {e.Message}");
        }
    }
    float t = 0.0f;
    private void Update()
    {
        t += Time.deltaTime;
        if (t>3)
        {
            t = 0;
            SendMessage2();
        }
    }
    public async void SendMessage2()
    {
        if (client == null ) return;
        
        await client.PublishAsync(SUBJECT, "1a2a");
        
    }
    void UpdateChatDisplay(string message)
    {
        Debug.Log("msg:"+ message);
    }

    async void OnApplicationQuit()
    {
        if (client != null)
        {
            await client.DisposeAsync();
        }
    }
}
Posted by 아기곰푸우
,

import yt_dlp

def download_video(url, output_path="downloads/%(title)s.%(ext)s"):
    ydl_opts = {
        "outtmpl": output_path,  # 파일 저장 경로 및 이름 설정
        "format": "bv*[ext=mp4]+ba[ext=m4a]/b[ext=mp4]",  # 최고 화질 비디오+오디오 조합
        "noplaylist": True,  # 개별 비디오만 다운로드
        "merge_output_format": "mp4",  # 병합 시 MP4로 저장
    }

    with yt_dlp.YoutubeDL(ydl_opts) as ydl:
        ydl.download([url])

# 예제 실행
video_url = "https://www.youtube.com/watch?v="
download_video(video_url)

Posted by 아기곰푸우
,

NATS 설정

카테고리 없음 2025. 3. 11. 10:48

websocket을 사용하려면 따로 설정파일 세팅해야함

 

websocket {
# Specify a host and port to listen for websocket connections
    #
    # listen: "host:port"

    # It can also be configured with individual parameters,
    # namely host and port.
    #
    # host: "hostname"
    # port: 443
port: 8282

    # This will optionally specify what host:port for websocket
    # connections to be advertised in the cluster.
    #
    # advertise: "host:port"

    # TLS configuration is required by default
    #
    #tls {
      #cert_file: "/path/to/cert.pem"
      #key_file: "/path/to/key.pem"
    #}

    # For test environments, you can disable the need for TLS
    # by explicitly setting this option to `true`
    #
    no_tls: true

    # [Cross-origin resource sharing option](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).
    #
    # IMPORTANT! This option is used only when the http request presents an Origin
    # header, which is the case for web browsers. If no Origin header is present,
    # this check will not be performed.
    #
    # When set to `true`, the HTTP origin header must match the request’s hostname.
    # The default is `false`.
    #
    #same_origin: true

    # [Cross-origin resource sharing option](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).
    #
    # IMPORTANT! This option is used only when the http request presents an Origin
    # header, which is the case for web browsers. If no Origin header is present,
    # this check will not be performed.
    #
    # List of accepted origins. When empty, and `same_origin` is `false`, clients from any origin are allowed to connect.
    # This list specifies the only accepted values for the client's request Origin header. The scheme,
    # host and port must match. By convention, the absence of TCP port in the URL will be port 80
    # for an "http://" scheme, and 443 for "https://".
    #
    # allowed_origins [
    #    "http://www.example.com"
    #    "https://www.other-example.com"
    # ]

    # This enables support for compressed websocket frames
    # in the server. For compression to be used, both server
    # and client have to support it.
    #
    # compression: true

    # This is the total time allowed for the server to
    # read the client request and write the response back
    # to the client. This includes the time needed for the
    # TLS handshake.
    #
    # handshake_timeout: "2s"

    # Name for an HTTP cookie, that if present will be used as a client JWT.
    # If the client specifies a JWT in the CONNECT protocol, this option is ignored.
    # The cookie should be set by the HTTP server as described [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies).
    # This setting is useful when generating NATS `Bearer` client JWTs as the
    # result of some authentication mechanism. The HTTP server after correct
    # authentication can issue a JWT for the user, that is set securely preventing
    # access by unintended scripts. Note these JWTs must be [NATS JWTs](https://docs.nats.io/nats-server/configuration/securing_nats/jwt).
    #
    # jwt_cookie: "my_jwt_cookie_name"

    # If no user name is provided when a websocket client connects, will default
    # this user name in the authentication phase. If specified, this will
    # override, for websocket clients, any `no_auth_user` value defined in the
    # main configuration file.
    # Note that this is not compatible with running the server in operator mode.
    #
    # no_auth_user: "my_username_for_apps_not_providing_credentials"

    # See below to know what is the normal way of limiting websocket clients
    # to specific users.
    # If there are no users specified in the configuration, this simple authorization
    # block allows you to override the values that would be configured in the
    # equivalent block in the main section.
    #
    # authorization {
    #     # If this is specified, the client has to provide the same username
    #     # and password to be able to connect.
    #     # username: "my_user_name"
    #     # password: "my_password"
    #
    #     # If this is specified, the password field in the CONNECT has to
    #     # match this token.
    #     # token: "my_token"
    #
    #     # This overrides the main's authorization timeout. For consistency
    #     # with the main's authorization configuration block, this is expressed
    #     # as a number of seconds.
    #     # timeout: 2.0
    #}
}

 

 

html 소스

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>NATS WebSocket Client</title>
    <style>
        body { font-family: Arial, sans-serif; text-align: center; }
        input, button { margin: 5px; padding: 10px; }
        #messages { border: 1px solid #ccc; padding: 10px; width: 300px; margin: auto; height: 200px; overflow-y: scroll; }
    </style>
</head>

<body>

    <h2>NATS WebSocket Client</h2>

    <div>
        <input type="text" id="messageInput" placeholder="Enter message">
        <button id="sendButton">Send</button> </div>

    <h3>Received Messages</h3>
    <div id="messages"></div>

<script type="module">
    import { connect, StringCodec, JSONCodec } from "https://unpkg.com/nats.ws@latest/esm/nats.js";

    const nc = await connect({ servers: "ws://localhost:8282" });
    console.log("NATS에 연결됨");

    const sc = StringCodec();
    const jc = JSONCodec();
    const subject = "test";
    const sub = nc.subscribe(subject);

    (async () => {
        for await (const m of sub) {
            try {
                // Assuming the message is a string
                const decodedString = sc.decode(m.data);
                displayMessage(decodedString);
            } catch (err){
                //if can't decode as string it will be decoded as json
                const decodedJson = jc.decode(m.data)
                displayMessage(JSON.stringify(decodedJson))
            }
        }
    })();

    async function sendMessage() {
        let message = document.getElementById("messageInput").value;
        if (!message) return;

        try {
           //nc.publish(subject, sc.encode(message))
            nc.publish(subject, jc.encode({data: message}))
            displayMessage(`(Sent) ${message}`, true);
            document.getElementById("messageInput").value = "";
        } catch (err) {
          console.error("Message send error", err);
        }
    }
     // Get the button element
    const sendButton = document.getElementById("sendButton");

    // Add an event listener to the button
    sendButton.addEventListener("click", sendMessage);

    function displayMessage(msg, isSent = false) {
        let msgDiv = document.getElementById("messages");
        let newMessage = document.createElement("div");
        newMessage.textContent = isSent ? `📤 ${msg}` : `📩 ${msg}`;
        msgDiv.appendChild(newMessage);
        msgDiv.scrollTop = msgDiv.scrollHeight;
    }
    // Handle connection close
    nc.closed()
        .then(() => {
            console.log("NATS connection closed.");
        })
        .catch((err) => {
            console.error("NATS connection closed with error:", err);
        });

</script>
</body>
</html>

Posted by 아기곰푸우
,

WebSocket을 기본적으로 지원하는 메시지 큐(Message Queue) 시스템은 많지 않지만, WebSocket과 쉽게 통합할 수 있는 몇 가지 메시지 브로커와 솔루션이 있습니다

1. NATS

  • WebSocket 지원: 기본적으로 WebSocket 지원 추가됨 (공식 문서)
  • 사용 방법:
    • WebSocket을 직접 사용하여 메시지를 송수신 가능

2. EMQX (MQTT Broker)

  • WebSocket 지원: 기본적으로 WebSocket을 지원
  • 사용 방법:
    • MQTT 프로토콜을 WebSocket과 함께 사용하여 메시지 큐 기능 구현 가능

3. Mosquitto (MQTT Broker)

  • WebSocket 지원: 직접 지원
  • 사용 방법:
    • mosquitto.conf에서 WebSocket 리스너 설정 후 사용 가능

 

Posted by 아기곰푸우
,
import os  
import chardet  

def convert\_to\_utf8(folder\_path):  
    for root, \_, files in os.walk(folder\_path):  
        for file in files:  
            if file.endswith(".cs"):  # .cs 파일만 선택  
                file\_path = os.path.join(root, file)  
                with open(file\_path, 'rb') as f:  
                    raw\_data = f.read()  
                    detected = chardet.detect(raw\_data)  # 인코딩 감지  
                    encoding = detected\['encoding'\] if detected\['encoding'\] else 'utf-8'  

                if encoding.lower() != 'utf-8':  
                    try:  
                        text = raw\_data.decode(encoding)  
                        with open(file\_path, 'w', encoding='utf-8') as f:  
                            f.write(text)  
                        print(f"Converted: {file\_path} from {encoding} to UTF-8")  
                    except Exception as e:  
                        print(f"Failed to convert {file\_path}: {e}")  
                else:  
                    print(f"Skipped (already UTF-8): {file\_path}")  

# 사용 예시  
folder\_path = "C:/your/folder/path"  # 변경 필요  
convert\_to\_utf8(folder\_path)
Posted by 아기곰푸우
,

 

 

기존 소스을 변경시

Task 은 UniTask로 변경

async Task  => async UniTask 로

async void => async UniTaskVoid 로

 

Forget() 처리가 가능할 경우 로 async UniTaskVoid 로 처리

testA.Forget();

async UniTaskVoid testA()

{


}

 

async 가 필요없는 삭제할것

UniTask SomeFunction() { // 아무것도 하지 않음 return UniTask.CompletedTask; }

 

 

UniTaskVoid는 await할 수 없음

UniTaskVoid는 일반적인 UniTask와 다르게 await할 수 없습니다.
만약 비동기적으로 호출해야 한다면, UniTaskVoid 대신 UniTask를 사용하세요.

 

async UniTaskVoid Test() { await UniTask.Delay(500); Debug.Log("완료"); } // ❌ 잘못된 코드 (await 불가능) // await Test(); // 컴파일 에러 발생!

 

 

 

기존 함수  Get;Set; 으로 되었는건 await 함수로 만들것

 

 

UniTaskVoid 정리

특징설명

리턴값 없음 return;을 명시적으로 쓰지 않아도 됨
자동 실행됨 Forget() 없이도 실행됨
await 필수 await이 없으면 경고 발생
예외 전파됨 try-catch로 예외를 직접 처리해야 함
await 불가능 UniTaskVoid는 await할 수 없음 → UniTask를 사용해야 함

 

 

추천: UniTaskVoid는 주로 Unity의 이벤트 기반 코드(Update, OnTriggerEnter 등)에서 사용하고, 일반적인 비동기 함수에서는 UniTask를 사용하는 것이 더 안전합니다.

 

 

 

코루틴 -> To.Coroutine()

Forget() 사용시 이후 코드와 동시혹은 늦게 되어도 상관없는 코드일경우에 적용하고 

문제 발생하면 상위 단계로 올라가서 Forget() 처리

 

 

 

 

 

webgl 빌드시

  • UniTask.RunOnThreadPool() ❌ → WebGL에서는 사용 불가
  • await Task.Delay(1000); ❌ → 대신 UniTask.Delay() 사용
  • UniTask.Yield(PlayerLoopTiming.Background) ❌ → 대신 Update 사용
  • async void ❌ → async UniTask 또는 async Task 사용
  • UnityWebRequest 사용 시 CORS 문제 주의

 

 

Posted by 아기곰푸우
,

글 – 글로벌 꿈을 향해
로 – 로켓처럼 빠르게
벌 - 벌처럼 날아서
사 – 사로잡은 미래를 향해
이 – 이룰 수 있어, 내가 해
버 – 버텨내며 뛰어가고
대 – 대박을 꿈꾸며
학 – 학습은 나의 무기
교 – 교훈 속에서 빛나네

Posted by 아기곰푸우
,