This commit is contained in:
yaoyanwei
2025-08-04 16:45:48 +08:00
parent 565aa16389
commit 2f2a601227
2296 changed files with 522745 additions and 93 deletions

View File

@@ -0,0 +1,310 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TcgEngine
{
/// <summary>
/// Main audio script, allow to play sounds by channel
/// </summary>
public class AudioTool : MonoBehaviour
{
private static AudioTool instance;
private Dictionary<string, AudioSource> channels_sfx = new Dictionary<string, AudioSource>();
private Dictionary<string, AudioSource> channels_music = new Dictionary<string, AudioSource>();
private Dictionary<string, float> channels_volume = new Dictionary<string, float>();
private Dictionary<string, float> tchannels_volume = new Dictionary<string, float>();
[HideInInspector] public float master_vol = 1f;
[HideInInspector] public float sfx_vol = 1f;
[HideInInspector] public float music_vol = 1f;
private void Awake()
{
LoadPrefs();
RefreshVolume();
}
private void Update()
{
foreach (KeyValuePair<string, AudioSource> pair in channels_music)
{
if (pair.Value.isPlaying)
{
float tvol = tchannels_volume[pair.Key];
float vol = channels_volume[pair.Key];
vol = Mathf.MoveTowards(vol, tvol, 0.5f * Time.deltaTime);
channels_volume[pair.Key] = vol;
pair.Value.volume = vol * music_vol;
if (vol < 0.01f && tvol < 0.01f)
StopMusic(pair.Key);
}
}
foreach (KeyValuePair<string, AudioSource> pair in channels_sfx)
{
if (pair.Value.isPlaying)
{
float tvol = tchannels_volume[pair.Key];
float vol = channels_volume[pair.Key];
vol = Mathf.MoveTowards(vol, tvol, 0.5f * Time.deltaTime);
channels_volume[pair.Key] = vol;
pair.Value.volume = vol * sfx_vol;
if (vol < 0.01f && tvol < 0.01f)
StopSFX(pair.Key);
}
}
}
//channel: Two sounds on the same channel will never play at the same time, sounds on different channel will play at the same time.
//priority: if false, will not play if a sound is already playing on the channel, if true, will replace current sound playing on channel
public void PlaySFX(string channel, AudioClip sound, float vol = 0.6f, bool priority = true, bool loop = false)
{
if (string.IsNullOrEmpty(channel) || sound == null)
return;
AudioSource source = GetChannel(channel);
channels_volume[channel] = vol;
tchannels_volume[channel] = vol;
if (source == null)
{
source = CreateChannel(channel);
channels_sfx[channel] = source;
}
if (source != null)
{
if (priority || !source.isPlaying)
{
source.clip = sound;
source.volume = vol * sfx_vol;
source.loop = loop;
source.Play();
}
}
}
//channel: Two sounds on the same channel will never play at the same time, sounds on different channel will play at the same time.
//If music is already playing on the same channel, new music will be played unless its the same one.(Won't restart in that case)
public void PlayMusic(string channel, AudioClip music, float vol = 0.3f, bool loop = true)
{
if (string.IsNullOrEmpty(channel) || music == null)
return;
AudioSource source = GetMusicChannel(channel);
channels_volume[channel] = vol;
tchannels_volume[channel] = vol;
if (source == null)
{
source = CreateChannel(channel);
channels_music[channel] = source;
}
if (source != null)
{
if (!source.isPlaying || source.clip != music)
{
source.clip = music;
source.volume = vol * music_vol;
source.loop = loop;
source.Play();
}
}
}
//Same as PlaySFX but takes random audio in array
public void PlaySFX(string channel, AudioClip[] sounds, float vol = 0.6f, bool priority = true, bool loop = false)
{
if (sounds != null && sounds.Length > 0)
{
AudioClip sound = sounds[Random.Range(0, sounds.Length)];
PlaySFX(channel, sound, vol, priority, loop);
}
}
//Same as PlayMusic but takes random audio in array
public void PlayMusic(string channel, AudioClip[] musics, float vol = 0.6f, bool loop = false)
{
if (musics != null && musics.Length > 0)
{
AudioClip music = musics[Random.Range(0, musics.Length)];
PlayMusic(channel, music, vol, loop);
}
}
public void StopSFX(string channel)
{
if (string.IsNullOrEmpty(channel))
return;
AudioSource source = GetChannel(channel);
if (source)
{
source.Stop();
}
}
public void StopMusic(string channel)
{
if (string.IsNullOrEmpty(channel))
return;
AudioSource source = GetMusicChannel(channel);
if (source)
{
source.Stop();
}
}
public void FadeOutMusic(string channel)
{
if (tchannels_volume.ContainsKey(channel))
tchannels_volume[channel] = 0f;
}
public void FadeOutSFX(string channel)
{
if (tchannels_volume.ContainsKey(channel))
tchannels_volume[channel] = 0f;
}
public void SetMasterVolume(float value)
{
master_vol = value;
RefreshVolume();
SavePrefs();
}
public void SetMusicVolume(float value)
{
music_vol = value;
RefreshVolume();
SavePrefs();
}
public void SetSFXVolume(float value)
{
sfx_vol = value;
RefreshVolume();
SavePrefs();
}
public void LoadPrefs()
{
master_vol = PlayerPrefs.GetFloat("audio_master_volume", 1f);
music_vol = PlayerPrefs.GetFloat("audio_music_volume", 1f);
sfx_vol = PlayerPrefs.GetFloat("audio_sfx_volume", 1f);
}
public void SavePrefs()
{
PlayerPrefs.SetFloat("audio_master_volume", master_vol);
PlayerPrefs.SetFloat("audio_music_volume", music_vol);
PlayerPrefs.SetFloat("audio_sfx_volume", sfx_vol);
}
public void RefreshVolume()
{
AudioListener.volume = master_vol;
foreach (KeyValuePair<string, AudioSource> pair in channels_sfx)
{
if (pair.Value != null)
{
float vol = channels_volume.ContainsKey(pair.Key) ? channels_volume[pair.Key] : 0.8f;
pair.Value.volume = vol * sfx_vol;
}
}
foreach (KeyValuePair<string, AudioSource> pair in channels_music)
{
if (pair.Value != null)
{
float vol = channels_volume.ContainsKey(pair.Key) ? channels_volume[pair.Key] : 0.4f;
pair.Value.volume = vol * music_vol;
}
}
}
public bool IsMusicPlaying(string channel)
{
AudioSource source = GetMusicChannel(channel);
if (source != null)
return source.isPlaying;
return false;
}
public AudioSource CreateChannel(string channel, int priority = 128)
{
if (string.IsNullOrEmpty(channel))
return null;
GameObject cobj = new GameObject("AudioChannel-" + channel);
cobj.transform.SetParent(transform);
AudioSource caudio = cobj.AddComponent<AudioSource>();
caudio.playOnAwake = false;
caudio.loop = false;
caudio.priority = priority;
return caudio;
}
public AudioSource GetChannel(string channel)
{
if (channels_sfx.ContainsKey(channel))
return channels_sfx[channel];
return null;
}
public AudioSource GetMusicChannel(string channel)
{
if (channels_music.ContainsKey(channel))
return channels_music[channel];
return null;
}
public bool DoesChannelExist(string channel)
{
return channels_sfx.ContainsKey(channel);
}
public bool DoesMusicChannelExist(string channel)
{
return channels_music.ContainsKey(channel);
}
public float GetMasterVolume()
{
return master_vol;
}
public float GetSFXVolume()
{
return sfx_vol;
}
public float GetMusicVolume()
{
return music_vol;
}
public static AudioTool Get()
{
if (instance == null)
{
GameObject audio_system = new GameObject("AudioSystem");
instance = audio_system.AddComponent<AudioTool>();
DontDestroyOnLoad(audio_system);
}
return instance;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3ec345907b756324a859656ac2445bb1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,118 @@
using UnityEngine;
namespace TcgEngine
{
/// <summary>
/// Script that will resize the camera frame to a supported aspect ratio
/// By default: only 16/9 and 16/10 are supported
/// Black bars will appear on the side if the window is different
/// </summary>
[RequireComponent(typeof(Camera))]
public class CameraResize : MonoBehaviour
{
private Camera cam;
private int sheight;
private int swidth;
void Start()
{
cam = GetComponent<Camera>();
sheight = Screen.height;
swidth = Screen.width;
UpdateSize();
}
private void Update()
{
if (sheight != Screen.height || swidth != Screen.width)
{
sheight = Screen.height;
swidth = Screen.width;
UpdateSize();
}
}
public void UpdateSize()
{
float screenRatio = Screen.width / (float)Screen.height;
float targetRatio = GetAspectRatio();
if (Mathf.Approximately(screenRatio, targetRatio))
{
// Screen or window is the target aspect ratio: use the whole area.
cam.rect = new Rect(0, 0, 1, 1);
}
else if (screenRatio > targetRatio)
{
// Screen or window is wider than the target: pillarbox.
float normalizedWidth = targetRatio / screenRatio;
float barThickness = (1f - normalizedWidth) / 2f;
cam.rect = new Rect(barThickness, 0, normalizedWidth, 1);
}
else
{
// Screen or window is narrower than the target: letterbox.
float normalizedHeight = screenRatio / targetRatio;
float barThickness = (1f - normalizedHeight) / 2f;
cam.rect = new Rect(0, barThickness, 1, normalizedHeight);
}
/*if (TheGame.IsMobile())
{
float size_min = GetCamSizeMin();
float size_max = GetCamSizeMax();
float value = GetAspectValue();
float cam_size = value * size_min + (1f - value) * size_max;
cam.orthographicSize = cam_size;
}*/
}
public static float GetAspectMin()
{
float min = 16f / 10f;
return min;
}
public static float GetAspectMax()
{
//bool allow_wide = TheGame.IsMobile() && TheGame.Get() != null;
//float max = allow_wide ? 16f / 8f : 16f / 9f;
float max = 16f / 9f;
return max;
}
public static float GetCamSizeMin()
{
//bool allow_wide = TheGame.IsMobile() && TheGame.Get() != null;
//float max = allow_wide ? 4.2f : 4.5f;
float max = 4.5f;
return max;
}
public static float GetCamSizeMax()
{
return 5f;
}
public static float GetAspectRatio()
{
float max = GetAspectMax();
float min = GetAspectMin();
float screenRatio = Screen.width / (float)Screen.height;
float targetRatio = Mathf.Clamp(screenRatio, min, max);
return targetRatio;
}
public static float GetAspectValue()
{
float max = GetAspectMax();
float min = GetAspectMin();
float aspect = GetAspectRatio();
float value = (aspect - min) / (max - min);
return value;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0c9675c727e674447b6539e68147881e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,86 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using TcgEngine.UI;
namespace TcgEngine
{
/// <summary>
/// Use this export all your cards to png images (so they have the stats/ui on top of the card)
/// </summary>
public class CardExporter : MonoBehaviour
{
public string export_path = "C:/CardsExport";
public int width = 856;
public int height = 1200;
public VariantData variant;
[Header("References")]
public Camera render_cam;
public CardUI card_ui;
private RenderTexture texture;
private Texture2D export_texture;
void Start()
{
if (variant == null)
variant = VariantData.GetDefault();
GenerateAll();
}
private async void GenerateAll()
{
QualitySettings.SetQualityLevel(QualitySettings.names.Length -1); //Set Max Quality level
texture = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32);
export_texture = new Texture2D(width, height, TextureFormat.ARGB32, false);
texture.filterMode = FilterMode.Point;
export_texture.filterMode = FilterMode.Point;
render_cam.targetTexture = texture;
render_cam.orthographicSize = height / 2;
List<CardData> cards = CardData.GetAll();
for (int i = 0; i < cards.Count; i++)
{
CardData card = cards[i];
if (card.deckbuilding)
{
ShowText("Exporting: " + card.id);
GenerateCard(card);
await TimeTool.Delay(1);
ExportCard(card);
await TimeTool.Delay(2);
}
}
ShowText("Completed!");
}
private void GenerateCard(CardData card)
{
card_ui.SetCard(card, variant);
render_cam.Render();
}
private void ExportCard(CardData card)
{
RenderTexture.active = texture;
export_texture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
byte[] bytes = export_texture.EncodeToPNG();
string file = card.id + ".png";
File.WriteAllBytes(export_path + "/" + file, bytes);
RenderTexture.active = null;
}
private void ShowText(string txt)
{
Debug.Log(txt);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 39f2a5200b7a2ba43a1233b77905c246
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,489 @@
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
namespace TcgEngine
{
/// <summary>
/// Use this tool to upload your cards, packs and rewards to the Mongo Database (it will overwrite existing data)
/// </summary>
public class CardUploader : MonoBehaviour
{
public string username = "admin";
[Header("References")]
public InputField username_txt;
public InputField password_txt;
public Text msg_text;
[Header("Upload")]
public bool upload_cards = true;
public bool upload_packs = true;
public bool upload_decks = true;
public bool upload_variants = true;
public bool upload_rewards = true;
void Start()
{
username_txt.text = username;
msg_text.text = "";
}
private async void Login()
{
LoginResponse res = await ApiClient.Get().Login(username_txt.text, password_txt.text);
if (res.success && res.permission_level >= 10)
{
UploadAll();
}
else
{
ShowText("Admin Login Failed");
}
}
private async void UploadAll()
{
//Delete previous data
ShowText("Deleting previous data...");
if(upload_packs)
await DeleteAllPacks();
if (upload_cards)
await DeleteAllCards();
if (upload_variants)
await DeleteAllVariants();
if (upload_decks)
await DeleteAllDecks();
if (upload_rewards)
await DeleteAllRewards();
//Packs
if (upload_packs)
{
List<PackData> packs = PackData.GetAll();
for (int i = 0; i < packs.Count; i++)
{
PackData pack = packs[i];
if (pack.available)
{
ShowText("Uploading Packs: " + pack.id);
UploadPack(pack);
await TimeTool.Delay(100);
}
}
}
//Cards
if (upload_cards)
{
List<CardData> cards = CardData.GetAll();
for (int i = 0; i < cards.Count; i += 100)
{
List<CardData> list = GetCardGroup(cards, i, 100);
ShowText("Uploading Cards: " + i + "-" + (i + 100 - 1));
UploadCardList(list);
await TimeTool.Delay(200);
}
}
//Variants
if (upload_variants)
{
List<VariantData> variants = VariantData.GetAll();
for (int i = 0; i < variants.Count; i++)
{
VariantData variant = variants[i];
ShowText("Uploading Variant: " + variant.id);
UploadVariant(variant);
await TimeTool.Delay(100);
}
}
//Starter Decks
if (upload_decks)
{
DeckData[] decks = GameplayData.Get().starter_decks;
for (int i = 0; i < decks.Length; i++)
{
DeckData deck = decks[i];
ShowText("Uploading Deck: " + deck.id);
UploadDeck(deck);
UploadDeckReward(deck);
await TimeTool.Delay(100);
}
}
//Solo rewards
if (upload_rewards)
{
List<LevelData> levels = LevelData.GetAll();
for (int i = 0; i < levels.Count; i++)
{
LevelData level = levels[i];
ShowText("Uploading Reward: " + level.id);
UploadLevelReward(level);
if (level.reward_decks != null)
{
foreach (DeckData deck in level.reward_decks)
UploadDeck(deck);
}
await TimeTool.Delay(100);
}
}
//Custom rewards
if (upload_rewards)
{
List<RewardData> rewards = RewardData.GetAll();
for (int i = 0; i < rewards.Count; i++)
{
RewardData reward = rewards[i];
ShowText("Uploading Reward: " + reward.id);
UploadReward(reward);
foreach (DeckData deck in reward.decks)
UploadDeck(deck);
await TimeTool.Delay(100);
}
}
ShowText("Completed!");
ApiClient.Get().Logout();
}
private async Task DeleteAllPacks()
{
string url = ApiClient.ServerURL + "/packs";
await ApiClient.Get().SendRequest(url, WebRequest.METHOD_DELETE);
}
private async Task DeleteAllCards()
{
string url = ApiClient.ServerURL + "/cards";
await ApiClient.Get().SendRequest(url, WebRequest.METHOD_DELETE);
}
private async Task DeleteAllVariants()
{
string url = ApiClient.ServerURL + "/variants";
await ApiClient.Get().SendRequest(url, WebRequest.METHOD_DELETE);
}
private async Task DeleteAllDecks()
{
string url = ApiClient.ServerURL + "/decks";
await ApiClient.Get().SendRequest(url, WebRequest.METHOD_DELETE);
}
private async Task DeleteAllRewards()
{
string url = ApiClient.ServerURL + "/rewards";
await ApiClient.Get().SendRequest(url, WebRequest.METHOD_DELETE);
}
private async void UploadPack(PackData pack)
{
PackAddRequest req = new PackAddRequest();
req.tid = pack.id;
req.cards = pack.cards;
req.cost = pack.cost;
req.random = pack.type == PackType.Random;
req.rarities_1st = new PackAddProbability[pack.rarities_1st.Length];
req.rarities = new PackAddProbability[pack.rarities.Length];
req.variants = new PackAddProbability[pack.variants.Length];
for (int i = 0; i < req.rarities_1st.Length; i++)
req.rarities_1st[i] = AddPackRarity(pack.rarities_1st[i]);
for (int i = 0; i < req.rarities.Length; i++)
req.rarities[i] = AddPackRarity(pack.rarities[i]);
for (int i = 0; i < req.variants.Length; i++)
req.variants[i] = AddPackVariant(pack.variants[i]);
string url = ApiClient.ServerURL + "/packs/add";
string json = ApiTool.ToJson(req);
await ApiClient.Get().SendPostRequest(url, json);
}
private PackAddProbability AddPackRarity(PackRarity rarity)
{
PackAddProbability add = new PackAddProbability();
add.tid = rarity.rarity.id;
add.value = rarity.probability;
return add;
}
private PackAddProbability AddPackVariant(PackVariant rarity)
{
PackAddProbability add = new PackAddProbability();
add.tid = rarity.variant.id;
add.value = rarity.probability;
return add;
}
private async void UploadCard(CardData card)
{
CardAddRequest req = new CardAddRequest();
req.tid = card.id;
req.type = card.GetTypeId();
req.team = card.team.id;
req.rarity = card.rarity.id;
req.mana = card.mana;
req.attack = card.attack;
req.hp = card.hp;
req.cost = card.cost;
req.packs = new string[card.packs.Length];
for (int i = 0; i < req.packs.Length; i++)
{
req.packs[i] = card.packs[i].id;
}
string url = ApiClient.ServerURL + "/cards/add";
string json = ApiTool.ToJson(req);
await ApiClient.Get().SendPostRequest(url, json);
}
private async void UploadCardList(List<CardData> cards)
{
CardAddListRequest req = new CardAddListRequest();
req.cards = new CardAddRequest[cards.Count];
for(int i=0; i<cards.Count; i++)
{
CardData card = cards[i];
CardAddRequest rcard = new CardAddRequest();
rcard.tid = card.id;
rcard.type = card.GetTypeId();
rcard.team = card.team.id;
rcard.rarity = card.rarity.id;
rcard.mana = card.mana;
rcard.attack = card.attack;
rcard.hp = card.hp;
rcard.cost = card.cost;
rcard.packs = new string[card.packs.Length];
for (int p = 0; p < card.packs.Length; p++)
{
rcard.packs[p] = card.packs[p].id;
}
req.cards[i] = rcard;
}
string url = ApiClient.ServerURL + "/cards/add/list";
string json = ApiTool.ToJson(req);
await ApiClient.Get().SendPostRequest(url, json);
}
private async void UploadVariant(VariantData variant)
{
VariantAddRequest req = new VariantAddRequest();
req.tid = variant.id;
req.cost_factor = variant.cost_factor;
req.is_default = variant.is_default;
string url = ApiClient.ServerURL + "/variants/add";
string json = ApiTool.ToJson(req);
await ApiClient.Get().SendPostRequest(url, json);
}
private async void UploadDeckReward(DeckData deck)
{
RewardAddRequest req = new RewardAddRequest();
req.tid = deck.id;
req.group = "starter_deck";
req.decks = new string[1] { deck.id };
string url = ApiClient.ServerURL + "/rewards/add";
string json = ApiTool.ToJson(req);
await ApiClient.Get().SendPostRequest(url, json);
}
private async void UploadDeck(DeckData deck)
{
UserDeckData req = new UserDeckData(deck);
string url = ApiClient.ServerURL + "/decks/add";
string json = ApiTool.ToJson(req);
await ApiClient.Get().SendPostRequest(url, json);
}
private async void UploadReward(RewardData reward)
{
RewardAddRequest req = new RewardAddRequest();
req.tid = reward.id;
req.group = "";
req.coins = reward.coins;
req.xp = reward.xp;
req.repeat = reward.repeat;
if (reward.cards != null)
{
req.cards = new string[reward.cards.Length];
for (int i = 0; i < reward.cards.Length; i++)
{
req.cards[i] = reward.cards[i].id;
}
}
if (reward.decks != null)
{
req.decks = new string[reward.decks.Length];
for (int i = 0; i < reward.decks.Length; i++)
{
req.decks[i] = reward.decks[i].id;
}
}
if (reward.packs != null)
{
req.packs = new string[reward.packs.Length];
for (int i = 0; i < reward.packs.Length; i++)
{
req.packs[i] = reward.packs[i].id;
}
}
string url = ApiClient.ServerURL + "/rewards/add";
string json = ApiTool.ToJson(req);
await ApiClient.Get().SendPostRequest(url, json);
}
private async void UploadLevelReward(LevelData level)
{
RewardAddRequest req = new RewardAddRequest();
req.tid = level.id;
req.group = "";
req.coins = level.reward_coins;
req.xp = level.reward_xp;
req.repeat = false;
if (level.reward_cards != null)
{
req.cards = new string[level.reward_cards.Length];
for (int i = 0; i < level.reward_cards.Length; i++)
{
req.cards[i] = level.reward_cards[i].id;
}
}
if (level.reward_packs != null)
{
req.packs = new string[level.reward_packs.Length];
for (int i = 0; i < level.reward_packs.Length; i++)
{
req.packs[i] = level.reward_packs[i].id;
}
}
if (level.reward_decks != null)
{
req.decks = new string[level.reward_decks.Length];
for (int i = 0; i < level.reward_decks.Length; i++)
{
req.decks[i] = level.reward_decks[i].id;
}
}
string url = ApiClient.ServerURL + "/rewards/add";
string json = ApiTool.ToJson(req);
await ApiClient.Get().SendPostRequest(url, json);
}
private List<CardData> GetCardGroup(List<CardData> all_cards, int start, int count)
{
List<CardData> list = new List<CardData>();
for (int i = 0; i < count; i++)
{
int index = start + i;
if (index < all_cards.Count)
{
CardData card = all_cards[index];
if (card.deckbuilding)
{
list.Add(card);
}
}
}
return list;
}
private void ShowText(string txt)
{
msg_text.text = txt;
Debug.Log(txt);
}
public void OnClickStart()
{
msg_text.text = "";
Login();
}
}
[System.Serializable]
public class CardAddListRequest
{
public CardAddRequest[] cards;
}
[System.Serializable]
public class CardAddRequest
{
public string tid;
public string type;
public string team;
public string rarity;
public int mana;
public int attack;
public int hp;
public int cost;
public string[] packs;
}
[System.Serializable]
public class PackAddRequest
{
public string tid;
public int cards;
public int cost;
public bool random;
public PackAddProbability[] rarities_1st;
public PackAddProbability[] rarities;
public PackAddProbability[] variants;
}
[System.Serializable]
public class PackAddProbability
{
public string tid;
public int value;
}
[System.Serializable]
public class VariantAddRequest
{
public string tid;
public int cost_factor;
public bool is_default;
}
[System.Serializable]
public class RewardAddRequest
{
public string tid;
public string group;
public int coins;
public int xp;
public string[] packs;
public string[] cards;
public string[] decks;
public bool repeat;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 651d9a7ec841fde44b1cae9b97dfe0cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,127 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using TcgEngine.UI;
namespace TcgEngine
{
/// <summary>
/// Use this tool to upload your cards and packs to the Mongo Database (it will overwrite existing data)
/// </summary>
public class ChangePermission : MonoBehaviour
{
public string username = "admin";
[Header("Login")]
public InputField username_txt;
public InputField password_txt;
[Header("Change Permission")]
public UIPanel permission_panel;
public InputField target_user_txt;
public InputField target_perm_txt;
public Text error;
private string logged_user;
void Start()
{
username_txt.text = username;
error.text = "";
}
private async void Login(string user, string pass)
{
LoginResponse res = await ApiClient.Get().Login(user, pass);
if (res.success && res.permission_level >= 10)
{
logged_user = user;
permission_panel.Show();
}
else if (res.success)
{
error.text = "Not an admin user";
}
else
{
error.text = res.error;
}
}
private async Task<string> GetUserID(string tuser)
{
string url = ApiClient.ServerURL + "/users/" + tuser;
WebResponse res = await ApiClient.Get().SendGetRequest(url);
UserData udata = ApiTool.JsonToObject<UserData>(res.data);
if (!res.success)
error.text = res.error;
return res.success ? udata.id : null;
}
private async void SetPermission(string tuser, int permission)
{
string user_id = await GetUserID(tuser);
if (user_id == null)
return;
ChangePermissionRequest req = new ChangePermissionRequest();
req.permission_level = permission;
string url = ApiClient.ServerURL + "/users/permission/edit/" + user_id;
string json = ApiTool.ToJson(req);
WebResponse res = await ApiClient.Get().SendPostRequest(url, json);
if (!res.success)
error.text = res.error;
if (res.success)
{
error.text = "Success!";
error.color = Color.green;
}
}
public void OnClickLogin()
{
if (string.IsNullOrEmpty(username_txt.text))
return;
if (string.IsNullOrEmpty(password_txt.text))
return;
error.text = "";
error.color = Color.red;
Login(username_txt.text, password_txt.text);
}
public void OnClickUpdate()
{
if (string.IsNullOrEmpty(target_user_txt.text))
return;
bool success = int.TryParse(target_perm_txt.text, out int perm);
if (!success)
return;
if (logged_user == target_user_txt.text)
return; //Prevent changing yourself
error.text = "";
error.color = Color.red;
SetPermission(target_user_txt.text, perm);
}
}
[System.Serializable]
public class ChangePermissionRequest
{
public int permission_level;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 94523a4b844f81847b531581dcaa4976
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TcgEngine.UI
{
/// <summary>
/// Add to any UI component to make it visible or invisible based on the device
/// </summary>
public class DeviceVisibility : MonoBehaviour
{
public bool desktop = true;
public bool mobile = true;
void Start()
{
bool ismobile = GameTool.IsMobile();
if (ismobile && !mobile)
gameObject.SetActive(false);
else if (!ismobile && !desktop)
gameObject.SetActive(false);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a63a5ee9a4546c45a76f94f44ce2411
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,72 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TcgEngine.FX;
using TcgEngine.Client;
namespace TcgEngine
{
/// <summary>
/// Static functions to spawn FX prefabs
/// </summary>
public class FXTool : MonoBehaviour
{
public static GameObject DoFX(GameObject fx_prefab, Vector3 pos, float duration = 5f)
{
if (fx_prefab != null)
{
GameObject fx = Instantiate(fx_prefab, pos, GetFXRotation());
Destroy(fx, duration);
return fx;
}
return null;
}
public static GameObject DoSnapFX(GameObject fx_prefab, Transform snap_target)
{
return DoSnapFX(fx_prefab, snap_target, Vector3.zero);
}
public static GameObject DoSnapFX(GameObject fx_prefab, Transform snap_target, Vector3 offset)
{
if (fx_prefab != null && snap_target != null)
{
GameObject fx = Instantiate(fx_prefab, snap_target.transform.position + offset, GetFXRotation());
SnapFX snap = fx.AddComponent<SnapFX>();
snap.target = snap_target;
snap.offset = offset;
Destroy(fx, 5f);
return fx;
}
return null;
}
public static GameObject DoProjectileFX(GameObject fx_prefab, Transform source, Transform target, int damage)
{
if (fx_prefab != null && source != null && target != null)
{
GameObject fx = Instantiate(fx_prefab, source.position, GetFXRotation());
Projectile projectile = fx.GetComponent<Projectile>();
if (projectile == null)
projectile = fx.AddComponent<Projectile>();
projectile.SetSource(source);
projectile.SetTarget(target);
projectile.damage = damage;
projectile.DelayDamage();
Destroy(fx, projectile.duration);
return fx;
}
return null;
}
private static Quaternion GetFXRotation()
{
GameBoard board = GameBoard.Get();
Vector3 facing = board != null ? board.transform.forward : Vector3.forward;
return Quaternion.LookRotation(facing, Vector3.up);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8a7b1c65356269246bec79e006ee6565
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,133 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace TcgEngine
{
/// <summary>
/// Generic static functions for TcgEngine
/// </summary>
public static class GameTool
{
private const string uid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static System.Random random = new System.Random();
//Generate a random string to use as UID
public static string GenerateRandomID(int min = 9, int max = 15)
{
int length = random.Next(min, max);
string unique_id = "";
for (int i = 0; i < length; i++)
{
unique_id += uid_chars[random.Next(uid_chars.Length - 1)];
}
return unique_id;
}
//Generate a random int
public static int GenerateRandomInt()
{
return random.Next(int.MinValue, int.MaxValue);
}
//Generate a random ulong
public static ulong GenerateRandomUInt64()
{
ulong id = (uint)random.Next(int.MinValue, int.MaxValue); //Cast to uint before casting to ulong
uint bid = (uint)random.Next(int.MinValue, int.MaxValue);
id = id << 32;
id = id | bid;
return id;
}
//Pick X random elements in a list (same cant be picked twice, unless it appears twice or more in the list)
public static List<T> PickXRandom<T>(List<T> source, List<T> dest, int x)
{
if (source.Count <= x || x <= 0)
return source; //No need to pick anything
if (dest.Count > 0)
dest.Clear();
for (int i = 0; i < x; i++)
{
int r = random.Next(source.Count);
dest.Add(source[r]);
source.RemoveAt(r);
}
return dest;
}
//Clone a list of string in most optimized way (avoiding as many Add/Remove as possible)
public static void CloneList(List<string> source, List<string> dest)
{
for (int i = 0; i < source.Count; i++)
{
if (i < dest.Count)
dest[i] = source[i];
else
dest.Add(source[i]);
}
if (dest.Count > source.Count)
dest.RemoveRange(source.Count, dest.Count - source.Count);
}
//Clone a list in most optimized way, only the list is cloned, elements references are preserved
public static void CloneListRef<T>(List<T> source, List<T> dest) where T : class
{
for (int i = 0; i < source.Count; i++)
{
if (i < dest.Count)
dest[i] = source[i];
else
dest.Add(source[i]);
}
if (dest.Count > source.Count)
dest.RemoveRange(source.Count, dest.Count - source.Count);
}
//Same a previous function, but elements could be null
public static void CloneListRefNull<T>(List<T> source, ref List<T> dest) where T : class
{
//Source is null, set destination null
if (source == null)
{
dest = null;
return;
}
//Dest is null
if (dest == null)
dest = new List<T>();
//Both arent null, clone
CloneListRef(source, dest);
}
//Check if current device is mobile device
public static bool IsMobile()
{
#if UNITY_ANDROID || UNITY_IOS || UNITY_TIZEN
return true;
#else
return UnityEngine.Device.Application.isMobilePlatform;
#endif
}
//Check if using Universal Render Pipeline
//If this function return compile error (because URP isnt installed and you dont want it, you can simply comment the code and return false
public static bool IsURP()
{
if (GraphicsSettings.renderPipelineAsset is UniversalRenderPipelineAsset)
return true;
return false;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dfd2a611578d9e041a1be0c56f069c80
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,42 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TcgEngine
{
/// <summary>
/// Useful optimization tool, let you use arrays without instantiating new ones
/// </summary>
public class ListSwap<T>
{
public List<T> swap1 = new List<T>();
public List<T> swap2 = new List<T>();
//Return any array
public List<T> Get()
{
swap1.Clear(); //Clear before using
return swap1;
}
//Return the OTHER array (because skip is already in use)
public List<T> GetOther(List<T> skip)
{
if (skip == swap1)
{
swap2.Clear(); //Clear before using
return swap2;
}
swap1.Clear(); //Clear before using
return swap1;
}
//Clear both
public void Clear()
{
swap1.Clear();
swap2.Clear();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a33a9fa01d21c1e45bd72957e559fde2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,26 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TcgEngine.UI
{
/// <summary>
/// Add to any UI element to make it resize on mobile (some buttons should be bigger on mobile)
/// </summary>
public class MobileResizeUI : MonoBehaviour
{
public Vector2 position_offset;
public float size = 1f;
void Start()
{
if (GameTool.IsMobile())
{
RectTransform rect = GetComponent<RectTransform>();
rect.anchoredPosition += position_offset;
transform.localScale = transform.localScale * size;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1dc7e6d14aa7ae14fa896b16dd1de55e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,552 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using Unity.Netcode;
using UnityEngine;
using Unity.Collections;
using System.Threading.Tasks;
namespace TcgEngine
{
/// <summary>
/// Useful network static function
/// </summary>
public class NetworkTool
{
//Serialize a [System.Serializable] into bytes
public static byte[] Serialize<T>(T obj) where T : class
{
try
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, obj);
byte[] bytes = ms.ToArray();
ms.Close();
return bytes;
}
catch (Exception e)
{
Debug.LogError("Serialization error: " + e.Message);
return new byte[0];
}
}
//Deserialize a [System.Serializable] from bytes
public static T Deserialize<T>(byte[] bytes) where T : class
{
try
{
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
ms.Write(bytes, 0, bytes.Length);
ms.Seek(0, SeekOrigin.Begin);
T obj = (T)bf.Deserialize(ms);
ms.Close();
return obj;
}
catch (Exception e)
{
Debug.LogError("Deserialization error: " + e.Message);
return null;
}
}
//Serialize a INetworkSerializable to bytes
public static byte[] NetSerialize<T>(T obj, int size = 128) where T : INetworkSerializable, new()
{
if (obj == null)
return new byte[0];
try
{
FastBufferWriter writer = new FastBufferWriter(size, Allocator.Temp, TcgNetwork.MsgSizeMax);
writer.WriteNetworkSerializable(obj);
byte[] bytes = writer.ToArray();
writer.Dispose();
return bytes;
}
catch (Exception e)
{
Debug.LogError("Serialization error: " + e.Message);
return new byte[0];
}
}
//Deserialize a INetworkSerializable from bytes
public static T NetDeserialize<T>(byte[] bytes) where T : INetworkSerializable, new()
{
if (bytes == null || bytes.Length == 0)
return default(T);
try
{
FastBufferReader reader = new FastBufferReader(bytes, Allocator.Temp);
reader.ReadNetworkSerializable(out T obj);
reader.Dispose();
return obj;
}
catch (Exception e)
{
Debug.LogError("Deserialization error: " + e.Message);
return default(T);
}
}
//Serialize an array using Netcode
public static void NetSerializeArray<TS>(BufferSerializer<TS> serializer, ref string[] array) where TS : IReaderWriter
{
if (serializer.IsReader)
{
int size = 0;
serializer.SerializeValue(ref size);
array = new string[size];
for (int i = 0; i < size; i++)
{
string val = "";
serializer.SerializeValue(ref val);
array[i] = val;
}
}
if (serializer.IsWriter)
{
int size = array.Length;
serializer.SerializeValue(ref size);
for (int i = 0; i < size; i++)
serializer.SerializeValue(ref array[i]);
}
}
//Serialize an array using Netcode
public static void NetSerializeArray<T, TS>(BufferSerializer<TS> serializer, ref T[] array) where T : INetworkSerializable, new() where TS : IReaderWriter
{
if (serializer.IsReader)
{
int size = 0;
serializer.SerializeValue(ref size);
array = new T[size];
for(int i=0; i<size; i++)
{
T val = new T();
serializer.SerializeValue(ref val);
array[i] = val;
}
}
if (serializer.IsWriter)
{
int size = array.Length;
serializer.SerializeValue(ref size);
for (int i = 0; i < size; i++)
serializer.SerializeValue(ref array[i]);
}
}
public static byte[] SerializeInt32(int data)
{
return System.BitConverter.GetBytes(data);
}
public static int DeserializeInt32(byte[] bytes)
{
if (bytes != null && bytes.Length > 0)
return System.BitConverter.ToInt32(bytes, 0);
return 0;
}
public static byte[] SerializeUInt64(ulong data)
{
return System.BitConverter.GetBytes(data);
}
public static ulong DeserializeUInt64(byte[] bytes)
{
if (bytes != null && bytes.Length > 0)
return System.BitConverter.ToUInt64(bytes, 0);
return 0;
}
public static byte[] SerializeString(string data)
{
if(data != null)
return System.Text.Encoding.UTF8.GetBytes(data);
return new byte[0];
}
public static string DeserializeString(byte[] bytes)
{
if (bytes != null)
return System.Text.Encoding.UTF8.GetString(bytes);
return null;
}
public static string SerializeToString<T>(T obj) where T : class
{
byte[] bytes = Serialize<T>(obj);
return Convert.ToBase64String(bytes);
}
public static T DeserializeFromString<T>(string str) where T : class
{
byte[] bytes = Convert.FromBase64String(str);
return Deserialize<T>(bytes);
}
public static void SerializeObject<T, T1>(BufferSerializer<T> serializer, ref T1 data) where T : IReaderWriter where T1 : class
{
string sdata = "";
if (serializer.IsWriter)
{
sdata = SerializeToString(data);
}
serializer.SerializeValue(ref sdata, true);
if (serializer.IsReader)
{
data = DeserializeFromString<T1>(sdata);
}
}
public static void SerializeDictionary<T, T1, T2>(BufferSerializer<T> serializer, ref Dictionary<T1, T2> data)
where T : IReaderWriter where T1 : unmanaged, IComparable, IConvertible, IComparable<T1>, IEquatable<T1> where T2 : unmanaged, IComparable, IConvertible, IComparable<T2>, IEquatable<T2>
{
int count = data != null ? data.Count : 0;
serializer.SerializeValue(ref count);
if (serializer.IsWriter)
{
foreach (KeyValuePair<T1, T2> pair in data)
{
T1 key = pair.Key;
T2 val = pair.Value;
serializer.SerializeValue(ref key);
serializer.SerializeValue(ref val);
}
}
if (serializer.IsReader)
{
data = new Dictionary<T1, T2>();
for (int i = 0; i < count; i++)
{
T1 key = new T1();
T2 val = new T2();
serializer.SerializeValue(ref key);
serializer.SerializeValue(ref val);
data.Add(key, val);
}
}
}
public static void SerializeDictionaryEnum<T, T1, T2>(BufferSerializer<T> serializer, ref Dictionary<T1, T2> data)
where T : IReaderWriter where T1 : unmanaged, Enum where T2 : unmanaged, IComparable, IConvertible, IComparable<T2>, IEquatable<T2>
{
int count = data != null ? data.Count : 0;
serializer.SerializeValue(ref count);
if (serializer.IsWriter)
{
foreach (KeyValuePair<T1, T2> pair in data)
{
T1 key = pair.Key;
T2 val = pair.Value;
serializer.SerializeValue(ref key);
serializer.SerializeValue(ref val);
}
}
if (serializer.IsReader)
{
data = new Dictionary<T1, T2>();
for (int i = 0; i < count; i++)
{
T1 key = new T1();
T2 val = new T2();
serializer.SerializeValue(ref key);
serializer.SerializeValue(ref val);
data.Add(key, val);
}
}
}
public static void SerializeDictionary<T, T2>(BufferSerializer<T> serializer, ref Dictionary<string, T2> data)
where T : IReaderWriter where T2 : unmanaged, IComparable, IConvertible, IComparable<T2>, IEquatable<T2>
{
int count = data != null ? data.Count : 0;
serializer.SerializeValue(ref count);
if (serializer.IsWriter)
{
foreach (KeyValuePair<string, T2> pair in data)
{
string key = pair.Key;
T2 val = pair.Value;
serializer.SerializeValue(ref key);
serializer.SerializeValue(ref val);
}
}
if (serializer.IsReader)
{
data = new Dictionary<string, T2>();
for (int i = 0; i < count; i++)
{
string key = "";
T2 val = new T2();
serializer.SerializeValue(ref key);
serializer.SerializeValue(ref val);
data.Add(key, val);
}
}
}
public static void SerializeDictionary<T>(BufferSerializer<T> serializer, ref Dictionary<string, string> data)
where T : IReaderWriter
{
int count = data != null ? data.Count : 0;
serializer.SerializeValue(ref count);
if (serializer.IsWriter)
{
foreach (KeyValuePair<string, string> pair in data)
{
string key = pair.Key;
string val = pair.Value;
serializer.SerializeValue(ref key);
serializer.SerializeValue(ref val);
}
}
if (serializer.IsReader)
{
data = new Dictionary<string, string>();
for (int i = 0; i < count; i++)
{
string key = "";
string val = "";
serializer.SerializeValue(ref key);
serializer.SerializeValue(ref val);
data.Add(key, val);
}
}
}
public static void SerializeDictionaryNetObject<T, T2>(BufferSerializer<T> serializer, ref Dictionary<string, T2> data)
where T : IReaderWriter where T2 : INetworkSerializable, new()
{
int count = data != null ? data.Count : 0;
serializer.SerializeValue(ref count);
if (serializer.IsWriter)
{
foreach (KeyValuePair<string, T2> pair in data)
{
string key = pair.Key;
T2 val = pair.Value;
serializer.SerializeValue(ref key);
serializer.SerializeNetworkSerializable(ref val);
}
}
if (serializer.IsReader)
{
data = new Dictionary<string, T2>();
for (int i = 0; i < count; i++)
{
string key = "";
T2 val = new T2();
serializer.SerializeValue(ref key);
serializer.SerializeNetworkSerializable(ref val);
data.Add(key, val);
}
}
}
public static void SerializeDictionaryNetObject<T, T1, T2>(BufferSerializer<T> serializer, ref Dictionary<T1, T2> data)
where T : IReaderWriter where T1 : unmanaged, IComparable, IConvertible, IComparable<T1>, IEquatable<T1> where T2 : INetworkSerializable, new()
{
int count = data != null ? data.Count : 0;
serializer.SerializeValue(ref count);
if (serializer.IsWriter)
{
foreach (KeyValuePair<T1, T2> pair in data)
{
T1 key = pair.Key;
T2 val = pair.Value;
serializer.SerializeValue(ref key);
serializer.SerializeNetworkSerializable(ref val);
}
}
if (serializer.IsReader)
{
data = new Dictionary<T1, T2>();
for (int i = 0; i < count; i++)
{
T1 key = new T1();
T2 val = new T2();
serializer.SerializeValue(ref key);
serializer.SerializeNetworkSerializable(ref val);
data.Add(key, val);
}
}
}
public static void SerializeDictionaryObject<T, T2>(BufferSerializer<T> serializer, ref Dictionary<string, T2> data)
where T : IReaderWriter where T2 : class, new()
{
int count = data != null ? data.Count : 0;
serializer.SerializeValue(ref count);
if (serializer.IsWriter)
{
foreach (KeyValuePair<string, T2> pair in data)
{
string key = pair.Key;
T2 val = pair.Value;
serializer.SerializeValue(ref key);
SerializeObject(serializer, ref val);
}
}
if (serializer.IsReader)
{
data = new Dictionary<string, T2>();
for (int i = 0; i < count; i++)
{
string key = "";
T2 val = new T2();
serializer.SerializeValue(ref key);
SerializeObject(serializer, ref val);
data.Add(key, val);
}
}
}
public static void SerializeDictionaryObject<T, T1, T2>(BufferSerializer<T> serializer, ref Dictionary<T1, T2> data)
where T : IReaderWriter where T1 : unmanaged, IComparable, IConvertible, IComparable<T1>, IEquatable<T1> where T2 : class, new()
{
int count = data != null ? data.Count : 0;
serializer.SerializeValue(ref count);
if (serializer.IsWriter)
{
foreach (KeyValuePair<T1, T2> pair in data)
{
T1 key = pair.Key;
T2 val = pair.Value;
serializer.SerializeValue(ref key);
SerializeObject(serializer, ref val);
}
}
if (serializer.IsReader)
{
data = new Dictionary<T1, T2>();
for (int i = 0; i < count; i++)
{
T1 key = new T1();
T2 val = new T2();
serializer.SerializeValue(ref key);
SerializeObject(serializer, ref val);
data.Add(key, val);
}
}
}
public static void SerializeDictionaryEnumObject<T, T1, T2>(BufferSerializer<T> serializer, ref Dictionary<T1, T2> data)
where T : IReaderWriter where T1 : unmanaged, Enum where T2 : class, new()
{
int count = data != null ? data.Count : 0;
serializer.SerializeValue(ref count);
if (serializer.IsWriter)
{
foreach (KeyValuePair<T1, T2> pair in data)
{
T1 key = pair.Key;
T2 val = pair.Value;
serializer.SerializeValue(ref key);
SerializeObject(serializer, ref val);
}
}
if (serializer.IsReader)
{
data = new Dictionary<T1, T2>();
for (int i = 0; i < count; i++)
{
T1 key = new T1();
T2 val = new T2();
serializer.SerializeValue(ref key);
SerializeObject(serializer, ref val);
data.Add(key, val);
}
}
}
public static ushort Hash16(string string_id)
{
return (ushort) string_id.GetHashCode();
}
public static uint Hash32(string string_id)
{
return (uint) string_id.GetHashCode();
}
public static ulong Hash64(string string_id)
{
string s1 = string_id.Substring(0, string_id.Length / 2);
string s2 = string_id.Substring(string_id.Length / 2);
ulong id = (uint)s1.GetHashCode();
id = id << 32;
id = id | (uint)s2.GetHashCode();
return id;
}
public static IPAddress ResolveDns(string url)
{
#if !UNITY_WEBGL
IPAddress[] ips = Dns.GetHostAddresses(url);
if (ips != null && ips.Length > 0)
return ips[0];
#else
Debug.LogWarning("Dns.GetHostAddresses not working on WebGL, try using direct IP address instead of host url");
#endif
return null;
}
//Converts a host (either domain or IP) into an IP
public static string HostToIP(string host)
{
bool success = IPAddress.TryParse(host, out IPAddress address);
if (success)
return address.ToString(); //Already an IP
IPAddress ip = ResolveDns(host); //Not an IP, resolve DNS
if (ip != null)
return ip.ToString();
return "";
}
public static string GetLocalIp()
{
//Get Internal IP
IPHostEntry hostEntry = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in hostEntry.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString();
}
}
return "";
}
public static async Task<string> GetOnlineIp()
{
//Get External IP
WebResponse res = await WebTool.SendRequest("https://api.ipify.org");
if (res.success)
return res.data;
else
return null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3ecdd15b88c2b1747b0d1942b9efc825
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,68 @@
using System.Collections;
using System.Collections.Generic;
namespace TcgEngine
{
/// <summary>
/// A pool reuses Memory for objects that are constantly created/destroyed, to prevent always allocating more memory
/// Makes the AI much much much faster
/// </summary>
public class Pool<T> where T : new()
{
private HashSet<T> in_use = new HashSet<T>();
private Stack<T> available = new Stack<T>();
public T Create()
{
if (available.Count > 0)
{
T elem = available.Pop();
in_use.Add(elem);
return elem;
}
T new_obj = new T();
in_use.Add(new_obj);
return new_obj;
}
public void Dispose(T elem)
{
in_use.Remove(elem);
available.Push(elem);
}
public void DisposeAll()
{
foreach (T obj in in_use)
available.Push(obj);
in_use.Clear();
}
public void Clear()
{
in_use.Clear();
available.Clear();
}
public HashSet<T> GetAllActive()
{
return in_use;
}
public int Count
{
get { return in_use.Count; }
}
public int CountAvailable
{
get { return available.Count; }
}
public int CountCapacity
{
get { return in_use.Count + available.Count; }
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8671537f63a2a0a44bff3e6f1defd7e1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace TcgEngine
{
/// <summary>
/// Change material based on Render Pipeline
/// </summary>
public class RPMat : MonoBehaviour
{
public Material mat_urp;
private SpriteRenderer render;
private Image image;
void Start()
{
render = GetComponent<SpriteRenderer>();
image = GetComponent<Image>();
if (render != null && GameTool.IsURP())
render.material = mat_urp;
if (image != null && GameTool.IsURP())
image.material = mat_urp;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d98a4654f52ab40419eed3ad7fb6fb77
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,255 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace TcgEngine
{
/// <summary>
/// Resolve abilties and actions one by one, with an optional delay in between each
/// </summary>
public class ResolveQueue
{
private Pool<AbilityQueueElement> ability_elem_pool = new Pool<AbilityQueueElement>();
private Pool<SecretQueueElement> secret_elem_pool = new Pool<SecretQueueElement>();
private Pool<AttackQueueElement> attack_elem_pool = new Pool<AttackQueueElement>();
private Pool<CallbackQueueElement> callback_elem_pool = new Pool<CallbackQueueElement>();
private Queue<AbilityQueueElement> ability_queue = new Queue<AbilityQueueElement>();
private Queue<SecretQueueElement> secret_queue = new Queue<SecretQueueElement>();
private Queue<AttackQueueElement> attack_queue = new Queue<AttackQueueElement>();
private Queue<CallbackQueueElement> callback_queue = new Queue<CallbackQueueElement>();
private Game game_data;
private bool is_resolving = false;
private float resolve_delay = 0f;
private bool skip_delay = false;
public ResolveQueue(Game data, bool skip)
{
game_data = data;
skip_delay = skip;
}
public void SetData(Game data)
{
game_data = data;
}
public virtual void Update(float delta)
{
if (resolve_delay > 0f)
{
resolve_delay -= delta;
if (resolve_delay <= 0f)
ResolveAll();
}
}
public virtual void AddAbility(AbilityData ability, Card caster, Card triggerer, Action<AbilityData, Card, Card> callback)
{
if (ability != null && caster != null)
{
AbilityQueueElement elem = ability_elem_pool.Create();
elem.caster = caster;
elem.triggerer = triggerer;
elem.ability = ability;
elem.callback = callback;
ability_queue.Enqueue(elem);
}
}
public virtual void AddAttack(Card attacker, Card target, Action<Card, Card, bool> callback, bool skip_cost = false)
{
if (attacker != null && target != null)
{
AttackQueueElement elem = attack_elem_pool.Create();
elem.attacker = attacker;
elem.target = target;
elem.ptarget = null;
elem.skip_cost = skip_cost;
elem.callback = callback;
attack_queue.Enqueue(elem);
}
}
public virtual void AddAttack(Card attacker, Player target, Action<Card, Player, bool> callback, bool skip_cost = false)
{
if (attacker != null && target != null)
{
AttackQueueElement elem = attack_elem_pool.Create();
elem.attacker = attacker;
elem.target = null;
elem.ptarget = target;
elem.skip_cost = skip_cost;
elem.pcallback = callback;
attack_queue.Enqueue(elem);
}
}
public virtual void AddSecret(AbilityTrigger secret_trigger, Card secret, Card trigger, Action<AbilityTrigger, Card, Card> callback)
{
if (secret != null && trigger != null)
{
SecretQueueElement elem = secret_elem_pool.Create();
elem.secret_trigger = secret_trigger;
elem.secret = secret;
elem.triggerer = trigger;
elem.callback = callback;
secret_queue.Enqueue(elem);
}
}
public virtual void AddCallback(Action callback)
{
if (callback != null)
{
CallbackQueueElement elem = callback_elem_pool.Create();
elem.callback = callback;
callback_queue.Enqueue(elem);
}
}
public virtual void Resolve()
{
if (ability_queue.Count > 0)
{
//Resolve Ability
AbilityQueueElement elem = ability_queue.Dequeue();
ability_elem_pool.Dispose(elem);
elem.callback?.Invoke(elem.ability, elem.caster, elem.triggerer);
}
else if (secret_queue.Count > 0)
{
//Resolve Secret
SecretQueueElement elem = secret_queue.Dequeue();
secret_elem_pool.Dispose(elem);
elem.callback?.Invoke(elem.secret_trigger, elem.secret, elem.triggerer);
}
else if (attack_queue.Count > 0)
{
//Resolve Attack
AttackQueueElement elem = attack_queue.Dequeue();
attack_elem_pool.Dispose(elem);
if (elem.ptarget != null)
elem.pcallback?.Invoke(elem.attacker, elem.ptarget, elem.skip_cost);
else
elem.callback?.Invoke(elem.attacker, elem.target, elem.skip_cost);
}
else if (callback_queue.Count > 0)
{
CallbackQueueElement elem = callback_queue.Dequeue();
callback_elem_pool.Dispose(elem);
elem.callback.Invoke();
}
}
public virtual void ResolveAll(float delay)
{
SetDelay(delay);
ResolveAll(); //Resolve now if no delay
}
public virtual void ResolveAll()
{
if (is_resolving)
return;
is_resolving = true;
while (CanResolve())
{
Resolve();
}
is_resolving = false;
}
public virtual void SetDelay(float delay)
{
if (!skip_delay)
{
resolve_delay = Mathf.Max(resolve_delay, delay);
}
}
public virtual bool CanResolve()
{
if (resolve_delay > 0f)
return false; //Is waiting delay
if (game_data.state == GameState.GameEnded)
return false; //Cant execute anymore when game is ended
if (game_data.selector != SelectorType.None)
return false; //Waiting for player input, in the middle of resolve loop
return attack_queue.Count > 0 || ability_queue.Count > 0 || secret_queue.Count > 0 || callback_queue.Count > 0;
}
public virtual bool IsResolving()
{
return is_resolving || resolve_delay > 0f;
}
public virtual void Clear()
{
attack_elem_pool.DisposeAll();
ability_elem_pool.DisposeAll();
secret_elem_pool.DisposeAll();
callback_elem_pool.DisposeAll();
attack_queue.Clear();
ability_queue.Clear();
secret_queue.Clear();
callback_queue.Clear();
}
public Queue<AttackQueueElement> GetAttackQueue()
{
return attack_queue;
}
public Queue<AbilityQueueElement> GetAbilityQueue()
{
return ability_queue;
}
public Queue<SecretQueueElement> GetSecretQueue()
{
return secret_queue;
}
public Queue<CallbackQueueElement> GetCallbackQueue()
{
return callback_queue;
}
}
public class AbilityQueueElement
{
public AbilityData ability;
public Card caster;
public Card triggerer;
public Action<AbilityData, Card, Card> callback;
}
public class AttackQueueElement
{
public Card attacker;
public Card target;
public Player ptarget;
public bool skip_cost;
public Action<Card, Card, bool> callback;
public Action<Card, Player, bool> pcallback;
}
public class SecretQueueElement
{
public AbilityTrigger secret_trigger;
public Card secret;
public Card triggerer;
public Action<AbilityTrigger, Card, Card> callback;
}
public class CallbackQueueElement
{
public Action callback;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: afa420d55af82614bb984510550d0b55
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
namespace TcgEngine
{
/// <summary>
/// Script to write a class to the disk, or to read a file containing class from the disk
/// </summary>
[System.Serializable]
public class SaveTool
{
//Load any file to a class, make sure the class is marked with [System.Serializable]
public static T LoadFile<T>(string filename) where T : class
{
T data = null;
string fullpath = Application.persistentDataPath + "/" + filename;
if (IsValidFilename(filename) && File.Exists(fullpath))
{
FileStream file = null;
try
{
BinaryFormatter bf = new BinaryFormatter();
file = File.Open(fullpath, FileMode.Open);
data = (T)bf.Deserialize(file);
file.Close();
}
catch (System.Exception e) { Debug.Log("Error Loading Data " + e); if (file != null) file.Close(); }
}
return data;
}
//Save any class to a file, make sure the class is marked with [System.Serializable]
public static void SaveFile<T>(string filename, T data) where T : class
{
if (IsValidFilename(filename))
{
FileStream file = null;
try
{
BinaryFormatter bf = new BinaryFormatter();
string fullpath = Application.persistentDataPath + "/" + filename;
file = File.Create(fullpath);
bf.Serialize(file, data);
file.Close();
}
catch (System.Exception e) { Debug.Log("Error Saving Data " + e); if (file != null) file.Close(); }
}
}
public static void DeleteFile(string filename)
{
string fullpath = Application.persistentDataPath + "/" + filename;
if (File.Exists(fullpath))
File.Delete(fullpath);
}
//Return all save files
public static List<string> GetAllSave(string extension = "")
{
List<string> saves = new List<string>();
string[] files = Directory.GetFiles(Application.persistentDataPath);
foreach (string file in files)
{
if (file.EndsWith(extension))
{
string filename = Path.GetFileName(file);
if (!saves.Contains(filename))
saves.Add(filename);
}
}
return saves;
}
public static bool DoesFileExist(string filename)
{
string fullpath = Application.persistentDataPath + "/" + filename;
return IsValidFilename(filename) && File.Exists(fullpath);
}
public static bool IsValidFilename(string filename)
{
if (string.IsNullOrWhiteSpace(filename))
return false; //Filename cant be blank
foreach (char c in Path.GetInvalidFileNameChars())
{
if (filename.Contains(c.ToString()))
return false; //Dont allow any special characters
}
return true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2dbbb87db1e098c41847b4715abd92a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace TcgEngine
{
//Script to manage transitions between scenes
public class SceneNav
{
public static void RestartLevel()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
public static void GoTo(string scene)
{
SceneManager.LoadScene(scene);
}
public static string GetCurrentScene()
{
return SceneManager.GetActiveScene().name;
}
public static bool DoSceneExist(string scene)
{
return Application.CanStreamedLevelBeLoaded(scene);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 933adfda5408a474e8936d703933b7ae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
namespace TcgEngine
{
/// <summary>
/// Class that simplifies the code for waiting for X seconds or waiting for condition
/// Also allows to call coroutines outside of a MonoBehaviour
/// </summary>
public class TimeTool
{
//--- Coroutine Code ----
public static void WaitFor(float time, Action callback)
{
StartCoroutine(WaitForRun(time, callback));
}
public static void WaitUntil(Func<bool> condition, Action callback)
{
StartCoroutine(WaitUntilRun(condition, callback));
}
private static IEnumerator WaitForRun(float time, Action callback) { yield return new WaitForSeconds(time); callback?.Invoke(); }
private static IEnumerator WaitUntilRun(Func<bool> condition, Action callback) { yield return new WaitUntil(condition); callback?.Invoke(); }
public static Coroutine StartCoroutine(IEnumerator routine)
{
return TimeToolMono.Inst.StartCoroutine(routine);
}
public static void StopCoroutine(Coroutine routine)
{
TimeToolMono.Inst.StopCoroutine(routine);
}
//--- Tasks Code ----
//Do not use Task.Delay since its broken on some platform (like WebGl), use this instead
public static async Task Delay(int miliseconds)
{
#if UNITY_WEBGL
//WebGL Task.Delay is broken
float seconds = miliseconds / 1000f;
float start_time = Time.time;
while (Time.time < start_time + seconds)
await Task.Yield();
#else
//More performant on desktop/mobile
await Task.Delay(miliseconds);
#endif
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 70c48b4b7b41aad449e94747a355299b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TcgEngine
{
public class TimeToolMono : MonoBehaviour
{
private static TimeToolMono _instance;
public Coroutine StartRoutine(IEnumerator routine)
{
return StartCoroutine(routine);
}
public void StopRoutine(Coroutine routine)
{
StopCoroutine(routine);
}
public static TimeToolMono Inst
{
get
{
if (_instance == null)
{
GameObject ntool = new GameObject("TimeTool");
_instance = ntool.AddComponent<TimeToolMono>();
}
return _instance;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8dc0cf85047b7af41a6a18095ff0b14a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,415 @@
using System.Collections.Generic;
using System.Text;
using UnityEngine.Networking;
using System;
using UnityEngine;
using System.Net;
using System.IO;
using System.Collections;
using System.Threading.Tasks;
namespace TcgEngine
{
/// <summary>
/// Tool to send HTTP web resquests
/// </summary>
public class WebRequest
{
public const string METHOD_GET = "GET";
public const string METHOD_POST = "POST";
public const string METHOD_PATCH = "PATCH";
public const string METHOD_DELETE = "DELETE";
public const int timeout = 10;
public static UnityWebRequest Create(string url)
{
UnityWebRequest request = new UnityWebRequest(url, METHOD_GET);
request.SetRequestHeader("Content-Type", "application/json");
request.downloadHandler = new DownloadHandlerBuffer();
request.timeout = timeout;
return request;
}
public static UnityWebRequest Create(string url, string method, string json_data, string token)
{
UnityWebRequest request = new UnityWebRequest(url, method);
request.SetRequestHeader("Content-Type", "application/json");
if(token != null)
request.SetRequestHeader("Authorization", token);
request.downloadHandler = new DownloadHandlerBuffer();
request.timeout = timeout;
if (method != METHOD_GET && !string.IsNullOrEmpty(json_data))
{
UploadHandler uploader = new UploadHandlerRaw(Encoding.UTF8.GetBytes(json_data));
uploader.contentType = "application/json";
request.uploadHandler = uploader;
}
return request;
}
public static UnityWebRequest CreateRaw(string url, string method, string contentType, byte[] data, string token)
{
UnityWebRequest request = new UnityWebRequest(url, method);
request.SetRequestHeader("Content-Type", contentType);
if (token != null)
request.SetRequestHeader("Authorization", token);
request.downloadHandler = new DownloadHandlerBuffer();
request.timeout = timeout;
if (method != METHOD_GET && !string.IsNullOrEmpty(contentType))
{
UploadHandler uploader = new UploadHandlerRaw(data);
uploader.contentType = contentType;
request.uploadHandler = uploader;
}
return request;
}
public static UnityWebRequest CreateHeader(string url)
{
UnityWebRequest request = UnityWebRequest.Head(url);
return request;
}
public static UnityWebRequest CreateTexture(string url)
{
UnityWebRequest request = UnityWebRequestTexture.GetTexture(url);
request.SetRequestHeader("Content-Type", "image/png");
return request;
}
public static UnityWebRequest CreateImageUploadForm(string url, string path, byte[] data, string token)
{
List<IMultipartFormSection> requestData = new List<IMultipartFormSection>();
requestData.Add(new MultipartFormDataSection("path", path, "text"));
requestData.Add(new MultipartFormFileSection("data", data, "file.png", "image/png"));
UnityWebRequest request = UnityWebRequest.Post(url, requestData);
if (token != null)
request.SetRequestHeader("Authorization", token);
request.timeout = 200;
return request;
}
public static WebResponse GetResponse(UnityWebRequest request)
{
WebResponse res = new WebResponse();
res.success = request.responseCode >= 200 && request.responseCode < 300;
res.status = request.responseCode;
res.error = request.error;
res.data = "";
if (request.downloadHandler != null)
res.data = request.downloadHandler.text;
return res;
}
public static HeadResponse GetHeadResponse(UnityWebRequest request)
{
HeadResponse res = new HeadResponse();
res.success = request.responseCode >= 200 && request.responseCode < 300;
res.status = request.responseCode;
string type = request.GetResponseHeader("Content-Type");
DateTime.TryParse(request.GetResponseHeader("Last-Modified"), out DateTime date);
int.TryParse(request.GetResponseHeader("Content-Length"), out int size);
res.content_type = type;
res.last_edit = date;
res.size = size;
return res;
}
}
public class WebTool
{
public static T JsonToObject<T>(string json)
{
T value = (T)Activator.CreateInstance(typeof(T));
try
{
value = JsonUtility.FromJson<T>(json);
}
catch (Exception) { }
return value;
}
public static T[] JsonToArray<T>(string json)
{
ListJson<T> list = new ListJson<T>();
list.list = new T[0];
try
{
string wrap_json = "{ \"list\": " + json + "}";
list = JsonUtility.FromJson<ListJson<T>>(wrap_json);
return list.list;
}
catch (Exception) { }
return new T[0];
}
public static string ToJson(object data)
{
return JsonUtility.ToJson(data);
}
public static int Parse(string int_str, int default_val = 0)
{
bool success = int.TryParse(int_str, out int val);
return success ? val : default_val;
}
public static async Task<WebResponse> SendRequest(string url)
{
UnityWebRequest req = WebRequest.Create(url);
return await SendRequest(req);
}
public static async Task<WebResponse> SendRequest(UnityWebRequest request)
{
try
{
var asyncOp = request.SendWebRequest();
while (!asyncOp.isDone)
await TimeTool.Delay(200);
}
catch (Exception) {}
if (request.result != UnityWebRequest.Result.Success)
Debug.Log(request.error);
WebResponse res = WebRequest.GetResponse(request);
request.Dispose();
return res;
}
}
public class WebContext
{
public HttpListenerContext http;
public string method;
public string token;
public string path;
public string data;
public void SendResponse<T>(T value)
{
string val = WebTool.ToJson(value);
SendResponse(val);
}
public void SendResponse(ulong value)
{
SendResponse(value.ToString());
}
public void SendResponse(int value)
{
SendResponse(value.ToString());
}
public void SendResponse(bool value)
{
SendResponse(value.ToString());
}
public void SendResponse(string value)
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(value);
SendResponse(bytes, 200);
}
public void SendError(string value)
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(value);
SendResponse(bytes, 400);
}
public void SendResponse()
{
try
{
WriteHeader();
http.Response.StatusCode = 200;
http.Response.Close();
}
catch (Exception e) { Debug.Log(e); }
}
public void SendResponse(byte[] bytes, int code)
{
try
{
WriteHeader();
http.Response.StatusCode = code;
http.Response.OutputStream.Write(bytes, 0, bytes.Length);
http.Response.Close();
}
catch (Exception e) { Debug.Log(e); }
}
private void WriteHeader()
{
http.Response.Headers.Add("Access-Control-Allow-Origin", "*");
http.Response.Headers.Add("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
http.Response.Headers.Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
}
public T GetData<T>()
{
return WebTool.JsonToObject<T>(data);
}
public ulong GetInt64()
{
bool valid = ulong.TryParse(data, out ulong val);
return valid ? val : 0;
}
public int GetInt()
{
bool valid = int.TryParse(data, out int val);
return valid ? val : 0;
}
public bool GetBool()
{
bool valid = bool.TryParse(data, out bool val);
return valid ? val : false;
}
public ulong GetClientID()
{
bool valid = ulong.TryParse(token, out ulong val);
return valid ? val : 0;
}
public string GetIP()
{
return http.Request.RemoteEndPoint.Address.ToString();
}
public string GetKey()
{
return token;
}
public bool IsKeyValid(string key)
{
return token == key;
}
public string GetQuery(string key)
{
try
{
return http.Request.QueryString.Get(key);
}
catch (Exception e) { Debug.Log(e); }
return "";
}
public void Close()
{
try
{
http.Response.Close();
}
catch (Exception e) { Debug.Log(e); }
}
public static WebContext Create(HttpListenerContext http)
{
WebContext req = new WebContext();
req.http = http;
req.path = "";
req.data = "";
try
{
req.method = http.Request.HttpMethod;
req.path = http.Request.RawUrl.Remove(0, 1);
req.token = http.Request.Headers.Get("Authorization");
if (http.Request.InputStream != null)
{
StreamReader reader = new StreamReader(http.Request.InputStream, http.Request.ContentEncoding);
req.data = reader.ReadToEnd();
}
}
catch (Exception e) { Debug.Log(e); }
return req;
}
}
public struct WebResponse
{
public bool success;
public long status;
public string data;
public string error;
public ulong GetInt64()
{
bool valid = ulong.TryParse(data, out ulong val);
return valid ? val : 0;
}
public int GetInt()
{
bool valid = int.TryParse(data, out int val);
return valid ? val : 0;
}
public bool GetBool()
{
bool valid = bool.TryParse(data, out bool val);
return valid ? val : false;
}
public T GetData<T>()
{
return WebTool.JsonToObject<T>(data);
}
public string GetError()
{
ErrorResponse err = WebTool.JsonToObject<ErrorResponse>(data);
if(err != null)
return err.error;
return error;
}
}
public class HeadResponse
{
public bool success;
public long status;
public DateTime last_edit;
public int size;
public string content_type;
}
[Serializable]
public class ErrorResponse
{
public string error;
}
[Serializable]
public class ListJson<T>
{
public T[] list;
public string error;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b6db2a236e57b06458f732737ff1afc3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: