This commit is contained in:
2024-09-29 16:52:10 +08:00
parent b2133d8463
commit 16be225768
19 changed files with 1860 additions and 180 deletions

View File

@@ -27,6 +27,12 @@ function L_drawMainCustomUI_All() {
L_Cmd("cmd.exe /c del Yosin_Game_Reloading.Sign");
//清空窗口
L_Windows_List = [];
//清空所有注册包
Pack_Control = {};
PushDamageFontDataFuncTab <- {};
PushDamageFontFuncTab <- {};
//清空活动图标窗口
getroottable().rawdelete("EventList_Obj");
//清空插件初始化状态
@@ -50,6 +56,10 @@ function L_drawMainCustomUI_All() {
getroottable().rawdelete("OnilneSign_Obj");
//全服竞拍
getroottable().rawdelete("ServerAuction_Obj");
//秒伤统计
getroottable().rawdelete("DamagePerSecond_Obj");
//皮肤仓库
getroottable().rawdelete("SkinHub_Obj");
} catch (exception) {
if (exception != "cannot open the file")
@@ -108,6 +118,7 @@ function L_drawMainCustomUI_All() {
});
}
// if (Clock() - getroottable().Lsnzz >= 50) {
// getroottable().Lsnzz = Clock();
// local T = {

View File

@@ -7,21 +7,8 @@
function L_getCurrentModuleDamageRate(obj) {
if (!obj)
return 1.0;
local rate;
if (getroottable().rawin("LenheartCurrentModuleDamageRate")) {
rate = 1.0 + getroottable()["LenheartCurrentModuleDamageRate"];
} else {
rate = 1.0;
}
local rate = 1.0;
//超时空伤害
if (getroottable().rawin("LenheartFiendModuleDamageRate")) {
rate *= getroottable()["LenheartFiendModuleDamageRate"];
} else {
rate *= 1.0;
}
//pvf伤害
local ClientRat = 1.0;
try {
ClientRat = getCurrentModuleDamageRate(obj).tofloat();
@@ -29,44 +16,5 @@ function L_getCurrentModuleDamageRate(obj) {
ClientRat = 1.0;
}
//副本伤害控制
try {
local stage = sq_GetGlobaludpModuleStage();
local dungeon = sq_GetDungeonByStage(stage);
local dungeonIndex = sq_GetDuegonIndex(dungeon);
local fbsh = 100;
foreach(id in DungeonIndex) {
if (dungeonIndex == id[0]) {
fbsh = id[1];
}
}
local nrate = fbsh.tofloat() / 100.0;
rate = rate.tofloat() * nrate;
} catch (exception) {
}
//职业伤害控制
try {
local LLJob = sq_getJob(obj);
local LLGrowT = sq_getGrowType(obj);
local LLLen = GrowType.len();
for (local i = 0; i< 11; ++i) {
if (i == LLLen) break;
if (LLJob == i) {
foreach(GR in GrowType[i]) {
if (LLGrowT == GR[0])
rate = rate.tofloat() * GR[1].tofloat();
}
}
}
} catch (exception) {
}
return (rate * ClientRat);
}

View File

@@ -19,14 +19,7 @@ function Sq_PushDamageData(ObjAddress, MySelfAddress, Value) {
}
function Sq_PushDamageFontData(ObjAddress, X, Y, Z, Value, Type, A1, A2) {
// print("MyCharacter: " + format("%02x", L_sq_RA(0x1AB7CDC)));
// print("ObjAddress: " + format("%02x", ObjAddress));
// print("A1: " + format("%02x", A1));
// print("A2: " + format("%02x", A2));
// print(" ");
// if (A2)
// print(format("%02x", L_Sq_GetObjectIsCharacter(A2)));
local Flag = true;
foreach(Func in PushDamageFontDataFuncTab) {
local Ret = Func(ObjAddress, X, Y, Z, Value, Type, A1, A2);

View File

@@ -24,7 +24,9 @@ function Sq_Pack_Control(Chunk) {
function Sq_Pack_ControlLocal(Chunk) {
local Pack_Json = Json.Decode(Chunk);
if (Pack_Control.rawin(Pack_Json.op)) Pack_Control[Pack_Json.op](Chunk);
if (Pack_Control.rawin(Pack_Json.op)) {
Pack_Control[Pack_Json.op](Chunk);
}
}

View File

@@ -290,6 +290,8 @@ class LenheartNewUI_Windows extends LenheartNewUI_BaseWindow {
ItemInfoDrawS = L_Sq_CallFunc(0xE6E070, "int", FFI_THISCALL, ["int", "int", "int", "int"], L_sq_RA(0x1A5FB20), 275, Rindro_ItemInfoObject[Id], 41);
//校准道具信息窗口位置
L_Sq_CallFunc(0xF3B3B0, "int", FFI_THISCALL, ["int", "int", "int", "int", "int"], ItemInfoDrawS, IMouse.GetXPos(), IMouse.GetYPos(), 28, 28);
//我自己UI打开的道具信息窗口需要把渲染队列改为下层 以显示我打开的道具
getroottable().WindowsShowABFlag <- false;
}
} else {
if (ItemInfoDrawS) {
@@ -454,13 +456,19 @@ function CheackMouseInOldWindows() {
local WindowAddress = L_sq_RA(0x1B474D4);
if (WindowAddress) {
local Flag = L_sq_RA(WindowAddress);
// print(format("%02X", Flag));
foreach(value in OldBaseWindowArr) {
if (Flag == value) {
// if ((L_sq_RA(WindowAddress + 0x14) == 0 && L_sq_RA(WindowAddress + 0x18) == 0) || Flag == 0x184D0C4) {
// print(false);
return false;
// }
//空地
if (Flag == 0x184D0C4 || Flag == 0x0184CF6C) {
if ((L_sq_RA(WindowAddress + 0x14) == 0 && L_sq_RA(WindowAddress + 0x18) == 0)) {
return false;
}
} else return false;
}
}
}
@@ -476,7 +484,7 @@ function RunMouseLogic(MousePos_X, MousePos_Y) {
//还原鼠标
R_Mouse.Restore();
}
//在任何老窗口上 并且渲染层A层 也就是下层渲染
//在任何老窗口上 并且渲染层A层 也就是下层渲染
else if (CheackMouseInOldWindows() && !getroottable().WindowsShowABFlag) {
//还原鼠标
R_Mouse.Restore();
@@ -528,11 +536,15 @@ function L_MouseCallBack(MouseState, MouseFlag, MousePos_X, MousePos_Y) {
//判断是否悬停活动图标
if (getroottable().rawin("EventList_Obj")) EventList_Obj.CheckInEvent(MousePos_X, MousePos_Y);
//如果渲染层级在下级 即A层 或者是 鼠标没有悬停在任何新窗口上时 执行判断 如果悬停在原生窗口 就解除鼠标锁定 如果点击 就改变渲染层级
if (!getroottable().WindowsShowABFlag || !CheackMouseInNewWindows(MousePos_X, MousePos_Y)) {
if (CheackMouseInOldWindows()) {
//如果点击了原生窗口 或者使用了滚轮 就把渲染队列改成下
if (MouseState == 0x201 || MouseState == 0x20a) getroottable().WindowsShowABFlag <- false;
if (MouseState == 0x201 || MouseState == 0x20a) {
getroottable().WindowsShowABFlag <- false;
}
if (MouseState != 0x20a) return;
}
}
@@ -554,8 +566,6 @@ function L_MouseCallBack(MouseState, MouseFlag, MousePos_X, MousePos_Y) {
case 0x201: {
//如果点击了新窗口就把渲染队列改成上
getroottable().WindowsShowABFlag <- true;
//点击动画
if (getroottable().WindowsShowABFlag) L_sq_WA(0x1B46874, 1);
Window.OnMouseLbDown(MousePos_X, MousePos_Y);
break;
@@ -589,7 +599,7 @@ function L_MouseCallBack(MouseState, MouseFlag, MousePos_X, MousePos_Y) {
//打开原生窗口回调
function L_OpenOldWindowCallBack(WindowIndex) {
//将新窗口渲染队列改为下层 抵消窗口 Esc窗口 登录可能显示的任务窗口
if (WindowIndex != 170 && WindowIndex != 176) {
if (WindowIndex != 170 && WindowIndex != 176 && WindowIndex != 276 && WindowIndex != 275 && WindowIndex != 278 && WindowIndex != 283) {
getroottable().WindowsShowABFlag <- false;
}
}
@@ -636,9 +646,11 @@ function L_WindowsLogic(obj) {
}
}
if (Flag) {
getroottable().WindowsShowABFlag <- false;
//还原鼠标
R_Mouse.Restore();
L_sq_MouseClick();
L_Sq_CallFunc(0x11A8B60, "void", FFI_MS_CDECL, []);
// L_sq_MouseClick();
Rindro_MouseClickFlag = 5;
}
}
@@ -682,6 +694,7 @@ class LenheartNewUI_CommonUi extends LenheartNewUI_BaseWindow {
isInRect = false;
OnClick = null;
OnClickEx = null;
OnClickSound = null;
ObjectId = null;
@@ -689,6 +702,8 @@ class LenheartNewUI_CommonUi extends LenheartNewUI_BaseWindow {
TopCallBackFunc = null;
Data = null;
constructor(x, y, width, height) {
this.Localtion_X = x;
this.Localtion_Y = y;
@@ -722,8 +737,9 @@ class LenheartNewUI_CommonUi extends LenheartNewUI_BaseWindow {
}
//鼠标左键弹起回调
function OnMouseLbUp(MousePos_X, MousePos_Y) {
if (isLBDown && OnClick) {
OnClick();
if (isLBDown) {
if (OnClick) OnClick();
if (OnClickEx) OnClickEx(this);
}
isLBDown = false;
}

View File

@@ -41,10 +41,13 @@ class Json {
}
function Decode(Str) {
Str = L_sq_DecondeJson(Str);
local Str = "local _M = " + Str + ";\n return _M;\n";
local Func = compilestring(Str);
return Func();
// Str = L_sq_DecondeJson(Str);
// local Str = "local _M = " + Str + ";\n return _M;\n";
// local Func = compilestring(Str);
// return Func();
local JsonObj = JSONParser();
return JsonObj.parse(Str);
}
}
//Key 键盘按键类

661
Base/_Tool/Json_Class.nut Normal file
View File

@@ -0,0 +1,661 @@
/*
文件名:Json_Class.nut
路径:Base/_Tool/Json_Class.nut
创建日期:2024-09-27 23:54
文件用途:Json类
*/
class JSONParser {
static version = "1.0.1";
state = "";
stack = null;
container = null;
key = "";
value = "";
converter = null;
constructor() {
stack = [];
container = {};
}
function parse(str, ...) {
if (vargc > 0) converter = vargc[0];
// actions for string tokens
local string = {
go = function() {
state = "ok";
}.bindenv(this),
firstokey = function() {
key = value;
state = "colon";
}.bindenv(this),
okey = function() {
key = value;
state = "colon";
}.bindenv(this),
ovalue = function() {
value = this._convert(value, "string", converter);
state = "ocomma";
}.bindenv(this),
firstavalue = function() {
value = this._convert(value, "string", converter);
state = "acomma";
}.bindenv(this),
avalue = function() {
value = value;
this._convert(value, "string", converter);
state = "acomma";
}.bindenv(this)
};
// the actions for number tokens
local number = {
go = function() {
state = "ok";
}.bindenv(this),
ovalue = function() {
value = this._convert(value, "number", converter);
state = "ocomma";
}.bindenv(this),
firstavalue = function() {
value = this._convert(value, "number", converter);
state = "acomma";
}.bindenv(this),
avalue = function() {
value = this._convert(value, "number", converter);
state = "acomma";
}.bindenv(this)
};
// action table
// describes where the state machine will go from each given state
local action = {};
action["{"] <- {
go = function() {
stack.push({
state = "ok"
});
container = {};
state = "firstokey";
}.bindenv(this),
ovalue = function() {
stack.push({
container = container,
state = "ocomma",
key = key
});
container = {};
state = "firstokey";
}.bindenv(this),
firstavalue = function() {
stack.push({
container = container,
state = "acomma"
});
container = {};
state = "firstokey";
}.bindenv(this),
avalue = function() {
stack.push({
container = container,
state = "acomma"
});
container = {};
state = "firstokey";
}.bindenv(this)
},
action["}"] <- {
firstokey = function() {
local pop = stack.pop();
value = container;
container = ("container" in pop) ? pop.container : null;
key = ("key" in pop) ? pop.key : null;
state = pop.state;
}.bindenv(this),
ocomma = function() {
local pop = stack.pop();
container[key] <- value;
value = container;
container = ("container" in pop) ? pop.container : null;
key = ("key" in pop) ? pop.key : null;
state = pop.state;
}.bindenv(this)
},
action["["] <- {
go = function() {
stack.push({
state = "ok"
});
container = [];
state = "firstavalue";
}.bindenv(this),
ovalue = function() {
stack.push({
container = container,
state = "ocomma",
key = key
});
container = [];
state = "firstavalue";
}.bindenv(this),
firstavalue = function() {
stack.push({
container = container,
state = "acomma"
});
container = [];
state = "firstavalue";
}.bindenv(this),
avalue = function() {
stack.push({
container = container,
state = "acomma"
});
container = [];
state = "firstavalue";
}.bindenv(this)
},
action["]"] <- {
firstavalue = function() {
local pop = stack.pop();
value = container;
container = ("container" in pop) ? pop.container : null;
key = ("key" in pop) ? pop.key : null;
state = pop.state;
}.bindenv(this),
acomma = function() {
local pop = stack.pop();
container.push(value);
value = container;
container = ("container" in pop) ? pop.container : null;
key = ("key" in pop) ? pop.key : null;
state = pop.state;
}.bindenv(this)
},
action[":"] <- {
colon = function() {
// Check if the key already exists
// NOTE previous code used 'if (key in container)...'
// but this finds table ('container') member methods too
local err = false;
foreach(akey, avalue in container) {
if (akey == key) err = true;
break
}
if (err) throw "Duplicate key \"" + key + "\"";
state = "ovalue";
}.bindenv(this)
},
action[","] <- {
ocomma = function() {
container[key] <- value;
state = "okey";
}.bindenv(this),
acomma = function() {
container.push(value);
state = "avalue";
}.bindenv(this)
},
action["true"] <- {
go = function() {
value = true;
state = "ok";
}.bindenv(this),
ovalue = function() {
value = true;
state = "ocomma";
}.bindenv(this),
firstavalue = function() {
value = true;
state = "acomma";
}.bindenv(this),
avalue = function() {
value = true;
state = "acomma";
}.bindenv(this)
},
action["false"] <- {
go = function() {
value = false;
state = "ok";
}.bindenv(this),
ovalue = function() {
value = false;
state = "ocomma";
}.bindenv(this),
firstavalue = function() {
value = false;
state = "acomma";
}.bindenv(this),
avalue = function() {
value = false;
state = "acomma";
}.bindenv(this)
},
action["null"] <- {
go = function() {
value = null;
state = "ok";
}.bindenv(this),
ovalue = function() {
value = null;
state = "ocomma";
}.bindenv(this),
firstavalue = function() {
value = null;
state = "acomma";
}.bindenv(this),
avalue = function() {
value = null;
state = "acomma";
}.bindenv(this)
}
//
state = "go";
stack = [];
// current tokenizeing position
local start = 0;
try {
local result, token, tokenizer = _JSONTokenizer();
while (token = tokenizer.nextToken(str, start)) {
if ("ptfn" == token.type) {
// punctuation/true/false/null
action[token.value][state]();
} else if ("number" == token.type) {
// number
value = token.value;
number[state]();
} else if ("string" == token.type) {
// string
value = tokenizer.unescape(token.value);
string[state]();
}
start += token.length;
}
} catch (e) {
state = e;
}
if (state != "ok" || regexp("[^\\s]").capture(str, start)) {
local near = str.slice(start, GetMin(str.len(), start + 10));
throw "JSON Syntax Error near `" + near + "`";
}
return value;
}
function GetMin(a, b) {
return a< b ? a : b;
}
function _convert(value, type, converter) {
if ("function" == typeof converter) {
// # of params for converter function
local parametercCount = 2;
// .getinfos() is missing on ei platform
if ("getinfos" in converter) {
parametercCount = converter.getinfos().parameters.len() -
1;
}
if (parametercCount == 1) {
return converter(value);
} else if (parametercCount == 2) {
return converter(value, type);
} else {
throw "Error: converter function must take 1 or 2 parameters"
}
} else if ("number" == type) {
local Ret = (value.find(".") == null && value.find("e") == null && value.find("E") == null) ? value.tointeger() : value.tofloat();
return Ret;
} else {
return value;
}
}
}
class _JSONTokenizer {
_ptfnRegex = null;
_numberRegex = null;
_stringRegex = null;
_ltrimRegex = null;
_unescapeRegex = null;
constructor() {
// punctuation/true/false/null
this._ptfnRegex = regexp("^(?:\\,|\\:|\\[|\\]|\\{|\\}|true|false|null)");
// numbers
this._numberRegex = regexp("^(?:\\-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)");
// strings
this._stringRegex = regexp("^(?:\\\"((?:[^\\r\\n\\t\\\\\\\"]|\\\\(?:[\"\\\\\\/trnfb]|u[0-9a-fA-F]{4}))*)\\\")");
// ltrim pattern
this._ltrimRegex = regexp("^[\\s\\t\\n\\r]*");
// string unescaper tokenizer pattern
this._unescapeRegex = regexp("\\\\(?:(?:u\\d{4})|[\\\"\\\\/bfnrt])");
}
function nextToken(str, ...) {
local start = 0;
if (vargc > 0) start = vargv[0];
local
m,
type,
token,
value,
length,
whitespaces;
// count # of left-side whitespace chars
whitespaces = this._leadingWhitespaces(str, start);
start += whitespaces;
if (m = this._ptfnRegex.capture(str, start)) {
// punctuation/true/false/null
value = str.slice(m[0].begin, m[0].end);
type = "ptfn";
} else if (m = this._numberRegex.capture(str, start)) {
// number
value = str.slice(m[0].begin, m[0].end);
type = "number";
} else if (m = this._stringRegex.capture(str, start)) {
// string
value = str.slice(m[1].begin, m[1].end);
type = "string";
} else {
return null;
}
token = {
type = type,
value = value,
length = m[0].end - m[0].begin + whitespaces
};
return token;
}
function _leadingWhitespaces(str, start) {
local r = this._ltrimRegex.capture(str, start);
if (r) {
return r[0].end - r[0].begin;
} else {
return 0;
}
}
// unesacape() replacements table
_unescapeReplacements = {
b = "\b",
f = "\f",
n = "\n",
r = "\r",
t = "\t"
};
function unescape(str) {
local start = 0;
local res = "";
while (start< str.len()) {
local m = this._unescapeRegex.capture(str, start);
if (m) {
local token = str.slice(m[0].begin, m[0].end);
// append chars before match
local pre = str.slice(start, m[0].begin);
res += pre;
if (token.len() == 6) {
res += token;
} else {
local char = token.slice(1);
if (char in this._unescapeReplacements) {
res += this._unescapeReplacements[char];
} else {
res += char;
}
}
} else {
res += str.slice(start);
break;
}
start = m[0].end;
}
return res;
}
}
class JSONEncoder {
static VERSION = "2.0.0";
// max structure depth
// anything above probably has a cyclic ref
static _maxDepth = 32;
function encode(value) {
return this._encode(value);
}
function _encode(val, ...) {
local depth = 0;
if (vargc > 0) depth = vargv[0];
// detect cyclic reference
if (depth > this._maxDepth) {
throw "Possible cyclic reference";
}
local
r = "",
s = "",
i = 0;
switch (typeof val) {
case "table":
case "class":
s = "";
// serialize properties, but not functions
foreach(k, v in val) {
if (typeof v != "function") {
s += ",\"" + k + "\":" + this._encode(v, depth + 1);
}
}
s = s.len() > 0 ? s.slice(1) : s;
r += "{" + s + "}";
break;
case "array":
s = "";
for (i = 0; i< val.len(); i++) {
s += "," + this._encode(val[i], depth + 1);
}
s = (i > 0) ? s.slice(1) : s;
r += "[" + s + "]";
break;
case "integer":
case "float":
case "bool":
r += val;
break;
case "null":
r += "null";
break;
case "instance":
if ("_serializeRaw" in val && typeof val._serializeRaw == "function") {
// include value produced by _serializeRaw()
r += val._serializeRaw().tostring();
} else if ("_serialize" in val && typeof val._serialize == "function") {
// serialize instances by calling _serialize method
r += this._encode(val._serialize(), depth + 1);
} else {
s = "";
try {
// iterate through instances which implement _nexti meta-method
foreach(k, v in val) {
s += ",\"" + k + "\":" + this._encode(v, depth + 1);
}
} catch (e) {
// iterate through instances w/o _nexti
// serialize properties, but not functions
foreach(k, v in val.getclass()) {
if (typeof v != "function") {
s += ",\"" + k + "\":" + this._encode(val[k], depth + 1);
}
}
}
s = s.len() > 0 ? s.slice(1) : s;
r += "{" + s + "}";
}
break;
case "blob":
// This is a workaround for a known bug:
// on device side Blob.tostring() returns null
// (instaead of an empty string)
r += "\"" + (val.len() ? this._escape(val.tostring()) : "") + "\"";
break;
// strings and all other
default:
r += "\"" + this._escape(val.tostring()) + "\"";
break;
}
return r;
}
function _escape(str) {
local res = "";
for (local i = 0; i< str.len(); i++) {
local ch1 = (str[i] & 0xFF);
if ((ch1 & 0x80) == 0x00) {
// 7-bit Ascii
ch1 = format("%c", ch1);
if (ch1 == "\"") {
res += "\\\"";
} else if (ch1 == "\\") {
res += "\\\\";
} else if (ch1 == "/") {
res += "\\/";
} else if (ch1 == "\b") {
res += "\\b";
} else if (ch1 == "\f") {
res += "\\f";
} else if (ch1 == "\n") {
res += "\\n";
} else if (ch1 == "\r") {
res += "\\r";
} else if (ch1 == "\t") {
res += "\\t";
} else if (ch1 == "\0") {
res += "\\u0000";
} else {
res += ch1;
}
} else {
if ((ch1 & 0xE0) == 0xC0) {
// 110xxxxx = 2-byte unicode
local ch2 = (str[++i] & 0xFF);
res += format("%c%c", ch1, ch2);
} else if ((ch1 & 0xF0) == 0xE0) {
// 1110xxxx = 3-byte unicode
local ch2 = (str[++i] & 0xFF);
local ch3 = (str[++i] & 0xFF);
res += format("%c%c%c", ch1, ch2, ch3);
} else if ((ch1 & 0xF8) == 0xF0) {
// 11110xxx = 4 byte unicode
local ch2 = (str[++i] & 0xFF);
local ch3 = (str[++i] & 0xFF);
local ch4 = (str[++i] & 0xFF);
res += format("%c%c%c%c", ch1, ch2, ch3, ch4);
}
}
}
return res;
}
}

View File

@@ -114,7 +114,10 @@ class NativePointer {
function read(type) {
local Buf = Sq_Point2Blob(this.C_Object, 4);
local Buf = Sq_Point2Blob(L_sq_P2I(this.C_Object), 4);
foreach(value in Buf) {
print(value);
}
return Buf.readn(type);
}

View File

@@ -299,8 +299,13 @@ class ItemInfoClass {
}
}
// print(L_sq_P2I(Memory.allocUtf8String("interface2/event/chn_event_2016/160927_joustmatches/joustmatches_ui.img").C_Object));
// local Npk = L_Sq_CallFunc(0x11C0410, "int", FFI_THISCALL, ["int", "int", "int"], L_sq_RA(0x1B4684C), 0, L_sq_P2I(Memory.allocUtf8String("interface2/event/chn_event_2016/160927_joustmatches/joustmatches_ui.img").C_Object));
// print(Npk);
// local Img = L_Sq_CallFunc(0x11AA190, "int", FFI_THISCALL, ["int", "int"], Npk, 0);
// print(format("%02x", Img));
// print("width: " + NativePointer(Img).add(0x1C).readShort());
// print("height: " + NativePointer(Img).add(0x20).readShort());
// local ReadPath = L_sq_P2I(Memory.allocUtf8String("etc/rindro/horseguessing/horseguessing.dat").C_Object);
// print(format("%02x", ReadPath));
@@ -403,4 +408,18 @@ class ItemInfoClass {
// // print(args.pop());
// // print(">>>>>>");
// return null;
// });
// });
// local Str = "{\"stringValue\":\"thisiszifuchuan\",\"numberValue\":123.45,\"integerValue\":42,\"booleanValue\":true,\"arrayValue\":[1,\"two\",true,{\"key\":\"value\"}],\"objectValue\":{\"name\":\"John Doe\",\"age\":30,\"address\":{\"street\":\"123 Main St\",\"city\":\"Anytown\",\"state\":\"CA\",\"zip\":\"12345\"}}}";
// print("***********************");
// print(Str);
// print(Str.len());
// local JsonObj = JSONParser();
// local T = JsonObj.parse(Str);
// print(">>>>>>>>>>>>>>");
// print(T);
// print(">>>>>>>>>>>>>>");
// local Str2 = Json.Encode(T);
// print("***********************");
// print(Str2);
// print(Str2.len());