From 0d341a13625385d720a22221cd08c620688ce248 Mon Sep 17 00:00:00 2001 From: gnembon Date: Mon, 1 Jun 2020 03:27:34 -0300 Subject: [PATCH 1/7] overlay fixes --- src/main/resources/assets/carpet/scripts/overlay.sc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/resources/assets/carpet/scripts/overlay.sc b/src/main/resources/assets/carpet/scripts/overlay.sc index 3adebc96..366d0a7a 100644 --- a/src/main/resources/assets/carpet/scripts/overlay.sc +++ b/src/main/resources/assets/carpet/scripts/overlay.sc @@ -138,12 +138,12 @@ __chunk_renderer(player_name) -> b = 30; a = max(0, 255-player_distance); color = a+256*(b+256*(g+256*r)); - draw_shape('box', 15, 'from', top_00, 'to', top_10, 'color', color); - draw_shape('box', 15, 'from', top_10, 'to', top_11, 'color', color); - draw_shape('box', 15, 'from', top_11, 'to', top_01, 'color', color); - draw_shape('box', 15, 'from', top_01, 'to', top_00, 'color', color); - draw_shape('box', 15, 'from', top_00, 'to', top_11, 'color', color); - draw_shape('box', 15, 'from', top_01, 'to', top_10, 'color', color); + draw_shape('line', 15, 'from', top_00, 'to', top_10, 'color', color); + draw_shape('line', 15, 'from', top_10, 'to', top_11, 'color', color); + draw_shape('line', 15, 'from', top_11, 'to', top_01, 'color', color); + draw_shape('line', 15, 'from', top_01, 'to', top_00, 'color', color); + draw_shape('line', 15, 'from', top_00, 'to', top_11, 'color', color); + draw_shape('line', 15, 'from', top_01, 'to', top_10, 'color', color); //part = 'dust 0.2 0.8 0.2 2'; //density = 2+player_distance/2; From 59be8b3fb4d44fed4438098a4b2bb17665c52eeb Mon Sep 17 00:00:00 2001 From: gnembon Date: Mon, 1 Jun 2020 12:05:01 -0300 Subject: [PATCH 2/7] redocced to draw_shape --- docs/scarpet/api/Auxiliary.md | 42 ++++++++++++++----- .../java/carpet/script/CarpetExpression.java | 2 +- .../carpet/script/utils/ShapeDispatcher.java | 10 ++--- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/docs/scarpet/api/Auxiliary.md b/docs/scarpet/api/Auxiliary.md index 7d9da627..a8b097dc 100644 --- a/docs/scarpet/api/Auxiliary.md +++ b/docs/scarpet/api/Auxiliary.md @@ -36,19 +36,41 @@ supplied, only that player will receive particles. ## Markers -### `marker_box(from, to, duration?, color?, player?)` +### `draw_shape(shape, duration, key?, value?, ... )`, `draw_shape(shape, duration, l(key?, value?, ... ))`, `draw_shape(shape, duration, attribute_map)` -Draws a box with `from` and `to` corners in the box. The boxes will dissipate after `duration` ticks (defaults to 10). -The color is an integer that indicate red, green, blue and alpha components in the form of `0xRRGGBBAA`, with the -default of `-1`, so white opaque, or `0xFFFFFFFF`. If player is specified, only displays for that player, otherwise all -players will see them. `marker_box` requires proper client synchronization to display these, and on non-supported -clients, the box will be replaced with close matching dust particles, so using of `marker_box` is safe to use for -scripts regardless who is targeted. The only consideration is that with vanilla clients, duration of particles cannot -be controlled, and last whatever the original particles do. +Draws a shape in the world that will expire in `duration` ticks. Other attributes of the shape should be provided as +consecutive key - value argument pairs, either as next arguments, or packed in a list, or supplied as a proper key-value +`map`. Arguments may include shared shape attributes, which are all optional, as well as shape-specific attributes, that +could be either optional or required. Shapes will draw properly on all carpet clients. Other connected players that don't +have carpet installed will still be able to see the required shapes in the form of dust particles. Replacement shapes +are not required to follow all attributes precisely, but will allow vanilla clients to receive some experience of your +apps. One of the attributes that will definitely not be honored is the duration - particles will be send once +per shape and last whatever they typically last in the game. -### `marker_line(from, to, duration?, color?, player?)` +Shapes will fail to draw and raise a runtime error if not all its required parameters +are specified and all available shapes have some parameters that are required, so make sure to have them in place: -Draws a marker line on client's screen. Uses similar setup as `marker_box`. +On the client, shapes can recognize that they are being redrawn again with the same parameters, disregarding the +duration parameter. This updates the expiry on the drawn shape to the new value, instead of adding new shape in its +place. This can be used for toggling the shapes on and off that has been send previously with very large durations, +or simply refresh the shapes periodically in more dynamic applications. + +Optional shared shape attributes: + * `color` - integer value indicating the main color of the shape in the form of red, green, blue and alpha components + in the form of `0xRRGGBBAA`, with the default of `-1`, so white opaque, or `0xFFFFFFFF`. + * `player` - name or player entity to send the shape to. If specified, the shapes will appear only for the specified + player, otherwise it will be send to all players in the dimension. + +Available shapes: + * `'line'` - draws a straight line between two points + * Required attributes: + * `from` - triple coordinates, entity, or block value indicating one end of the line + * `to` - other end of the line, same format as `from` + + * `'box'` - draws a box with corners in specified points + * Required attributes: + * `from` - triple coordinates, entity, or block value indicating one corner of the box + * `to` - other corner, same format as `from` ### `create_marker(text, pos, rotation?, block?)` diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index d9198cb1..e14eeb8b 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -2685,7 +2685,7 @@ public class CarpetExpression ServerPlayerEntity player = null; if (params.containsKey("player")) { - player = (ServerPlayerEntity) ((EntityValue)params.get("player")).getEntity(); + player = (ServerPlayerEntity)((EntityValue)params.get("player")).getEntity(); } ShapeDispatcher.sendShape( (player==null)?cc.s.getWorld().getPlayers():Collections.singletonList(player), diff --git a/src/main/java/carpet/script/utils/ShapeDispatcher.java b/src/main/java/carpet/script/utils/ShapeDispatcher.java index e37e5245..0aaadb12 100644 --- a/src/main/java/carpet/script/utils/ShapeDispatcher.java +++ b/src/main/java/carpet/script/utils/ShapeDispatcher.java @@ -103,16 +103,14 @@ public class ShapeDispatcher public static ExpiringShape create(CarpetContext cc, String shapeType, Map userParams) { userParams.put("shape", new StringValue(shapeType)); - Map validatedParams = new HashMap<>(); - userParams.forEach((key, value) -> - { + userParams.keySet().forEach(key -> { Param param = Param.coders.get(key); if (param==null) throw new InternalExpressionException("Unknown feature for shape: "+key); - validatedParams.put(key, param.validate(cc, value)); + userParams.put(key, param.validate(cc, userParams.get(key))); }); Function,ExpiringShape> factory = ExpiringShape.shapeProviders.get(shapeType); if (factory == null) throw new InternalExpressionException("Unknown shape: "+shapeType); - return factory.apply(validatedParams); + return factory.apply(userParams); } // client @@ -227,7 +225,7 @@ public class ShapeDispatcher } // list of params that need to be there private final Set required = ImmutableSet.of("duration", "shape", "dim"); - private final Map optional = ImmutableMap.of("color", new NumericValue(-1)); + private final Map optional = ImmutableMap.of("color", new NumericValue(-1), "player", Value.NULL); protected Set requiredParams() {return required;} // list of params that can be there, with defaults protected Set optionalParams() {return optional.keySet();} From 78e7d9618dcaab89cf505f58798cecec0e201060 Mon Sep 17 00:00:00 2001 From: whats2000 <60466660+whats2000@users.noreply.github.com> Date: Tue, 2 Jun 2020 03:39:08 +0800 Subject: [PATCH 3/7] Create zh_tw.json (#302) * Create zh_tw.json A traslate for traditonal Chinese * Update zh_tw.json Fixed some words is in wrong grammar * Update CarpetSettings.java --- src/main/java/carpet/CarpetSettings.java | 2 +- .../resources/assets/carpet/lang/zh_tw.json | 234 ++++++++++++++++++ 2 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/assets/carpet/lang/zh_tw.json diff --git a/src/main/java/carpet/CarpetSettings.java b/src/main/java/carpet/CarpetSettings.java index a198b438..b66c7838 100644 --- a/src/main/java/carpet/CarpetSettings.java +++ b/src/main/java/carpet/CarpetSettings.java @@ -61,7 +61,7 @@ public class CarpetSettings @Rule( desc = "sets the language for carpet", category = FEATURE, - options = {"none", "zh_cn"}, + options = {"none", "zh_cn", "zh_tw"}, strict = false, validate = LanguageValidator.class ) diff --git a/src/main/resources/assets/carpet/lang/zh_tw.json b/src/main/resources/assets/carpet/lang/zh_tw.json new file mode 100644 index 00000000..a3ede4a1 --- /dev/null +++ b/src/main/resources/assets/carpet/lang/zh_tw.json @@ -0,0 +1,234 @@ +{ + "rule.antiCheatDisabled.name": "關閉伺服器作弊檢測", + "rule.antiCheatDisabled.desc": "防止玩家因為“本伺服器不允許飛行”,“移動速度過快”等原因被請出伺服器", + + "rule.carpets.name": "放置地毯顯示進階數據", + "rule.carpets.desc": "通過把地毯放置在地上取得更進階信息", + + "rule.combineXPOrbs.name": "合併小經驗球", + "rule.combineXPOrbs.desc": "會將大量的小經驗球合併成等效的大經驗球", + + "rule.commandCameramode.name": "旁觀者模式", + "rule.commandCameramode.desc": "允許玩家使用/c切換成旁觀者模式,利用/s切換回生存模式", + "rule.commandCameramode.extra.0": "/c及/s不需要op權限也可使用", + + "rule.commandDistance.name": "距離測定", + "rule.commandDistance.desc": "使用/distance指令測定兩點的距離", + "rule.commandDistance.extra.0": "可以使用放置棕色地毯來使用此功能,前提是“放置地毯顯示進階數據”已啟用", + + "rule.commandDraw.name": "繪製圖形", + "rule.commandDraw.desc": "使用/draw指令以允許繪製一些簡易圖形", + + "rule.commandInfo.name": "獲取方塊進階資訊", + "rule.commandInfo.desc": "允許使用/info指令以獲得方塊進階資訊", + "rule.commandInfo.extra.0": "可以使用放置灰色地毯來使用此功能,前提是“放置地毯顯示進階數據”已啟用", + + "rule.commandLog.name": "遊戲數據追蹤器", + "rule.commandLog.desc": "允許使用/log指令使在Tab欄位追蹤遊戲部分數據", + + "rule.commandPerimeterInfo.name": "刷怪區域追蹤器", + "rule.commandPerimeterInfo.desc": "允許使用/perimeterinfo指令以探查周圍可生怪區域", + + "rule.commandPlayer.name": "機器人控制", + "rule.commandPlayer.desc": "允許使用/player指令以控制/召喚已存在的玩家id作為機器人", + + "rule.commandScript.name": "地毯腳本控制器", + "rule.commandScript.desc": "允許使用/script相關指令", + "rule.commandScript.extra.0": "一個Scarpet程式語言的遊戲內API", + + "rule.commandSpawn.name": "刷怪追蹤器", + "rule.commandSpawn.desc": "允許使用/spawn指令用於怪物生成追蹤", + + "rule.commandTick.name": "遊戲時鐘控制器", + "rule.commandTick.desc": "允許使用/tick指令控制遊戲內的伺服器端運行速度", + + "rule.commandTrackAI.name": "AI追蹤器", + "rule.commandTrackAI.desc": "允許使用/track指令以追蹤生物的AI", + + "rule.ctrlQCraftingFix.name": "ctrlQ合成修復", + "rule.ctrlQCraftingFix.desc": "在合成時允許使用ctrl+Q快捷鍵扔出結果格內所有物品", + + "rule.customMOTD.name": "MOTD更改", + "rule.customMOTD.desc": "設置一個不同的MOTD信息", + "rule.customMOTD.extra.0": "設置成'_'時將採用默認的MOTD(從server.properties中讀取的)", + + "rule.defaultLoggers.name": "默認開啟的遊戲數據追蹤器", + "rule.defaultLoggers.desc": "為所有新加入的玩家設置部分遊戲數據追蹤器默認為開啟狀態", + "rule.defaultLoggers.extra.0": "比如設置'tps,mobcaps'最為默認遊戲數據追蹤", + + "rule.desertShrubs.name": "樹苗在沙漠中乾枯", + "rule.desertShrubs.desc": "樹苗將在附近無水源狀態的沙漠生態群系變成枯灌木", + + "rule.disableSpawnChunks.name": "允許出生點區塊被卸載", + "rule.disableSpawnChunks.desc": "允許出生點區塊被卸載", + + "rule.explosionNoBlockDamage.name": "爆炸不破壞方塊", + "rule.explosionNoBlockDamage.desc": "任何形式的爆炸都無法摧毀方塊", + + "rule.extremeBehaviours.name": "隨機參數極端化", + "rule.extremeBehaviours.desc": "大幅度提升極端情況出現的概率,僅用於測試", + "rule.extremeBehaviours.extra.0": "發射器和投擲器將使用最大隨機刻", + + "rule.fastRedstoneDust.name": "紅石粉卡頓優化", + "rule.fastRedstoneDust.desc": "紅石粉卡頓優化 作者 Theosib", + + "rule.fillLimit.name": "fill/clone上限更改", + "rule.fillLimit.desc": "將fill/clone上限更改為自己設定的值", + "rule.fillLimit.extra.0": "你必須在1-2千萬之間取一個整數值", + + "rule.fillUpdates.name": "fill更新設置", + "rule.fillUpdates.desc": "fill/clone/setblock指令以及結構方塊執行時是否產生更新", + "rule.fillUpdates.extra.0": "設置為true時有更新 設置為false時為無更新", + + "rule.flatWorldStructureSpawning.name": "特定建築怪在超平坦世界生成", + "rule.flatWorldStructureSpawning.desc": "允許特定建築的怪物在超平坦世界生成", + + "rule.flippinCactus.name": "仙人掌扳手", + "rule.flippinCactus.desc": "允許使用仙人掌調整方塊朝向,並且不會造成更新", + + "rule.hardcodeTNTangle.name": "強制TNT角度", + "rule.hardcodeTNTangle.desc": "把TNT水平隨機角度設定為固定值,可用於測試機器", + "rule.hardcodeTNTangle.extra.0": "默認為-1,必須在0與360之間,或者-1", + + "rule.hopperCounters.name": "漏斗計數器", + "rule.hopperCounters.desc": "漏斗指向的羊毛方塊會計算吸收的物品並清除", + "rule.hopperCounters.extra.0": "在羊毛方塊上放置紅色或綠色地毯,使用/counter指令可啟用", + "rule.hopperCounters.extra.1": "使用 /counter reset重置計數器,使用/counter 查詢資訊", + "rule.hopperCounters.extra.2": "在生存模式,在同色羊毛上放置綠色地毯可以查詢,放紅色地毯重置", + "rule.hopperCounters.extra.3": "數據是全伺服器玩家共享的,並且有16色可以使用", + "rule.hopperCounters.extra.4": "物品會被銷毀,每個漏斗每tick銷毀一組物品", + + "rule.huskSpawningInTemples.name": "屍殼在沙漠神殿裡生成", + "rule.huskSpawningInTemples.desc": "只有屍殼會在沙漠神殿生成", + + "rule.lagFreeSpawning.name": "延遲自然生成", + "rule.lagFreeSpawning.desc": "生物生成需要更少的CPU和RAM", + + "rule.leadFix.name": "栓繩修復", + "rule.leadFix.desc": "修復栓繩在未加載區塊中,變得不可見的問題", + + "rule.maxEntityCollisions.name": "最大實體擠壓數量", + "rule.maxEntityCollisions.desc": "設定最大實體擠壓限制,0表示無限大", + + "rule.mergeTNT.name": "合併TNT", + "rule.mergeTNT.desc": "合併靜止的點燃的tnt實體", + + "rule.missingTools.name": "工具缺失修復", + "rule.missingTools.desc": "活塞,玻璃和海綿可以使用合適的工具更快地破壞", + + "rule.movableBlockEntities.name": "容器方塊移動", + "rule.movableBlockEntities.desc": "活塞可以推動具有容器標籤的方塊,比如箱子,漏斗", + + "rule.onePlayerSleeping.name": "單個玩家睡覺跳過夜晚", + "rule.onePlayerSleeping.desc": "只要伺服器中其中一人睡覺即可跳過全伺服器夜晚", + + "rule.optimizedTNT.name": "TNT優化", + "rule.optimizedTNT.desc": "tnt在相同位置或者在流體裡,爆炸將造成更低延遲", + + "rule.persistentParrots.name": "鸚鵡停留", + "rule.persistentParrots.desc": "鸚鵡不會離開你的肩膀,除非你受到傷害", + + "rule.placementRotationFix.name": "放置旋轉問題修復", + "rule.placementRotationFix.desc": "修復玩家放置方塊時快速轉身造成的問題", + + "rule.pushLimit.name": "自訂義推動上限", + "rule.pushLimit.desc": "自訂義活塞推動上限", + "rule.pushLimit.extra.0": "你必須在1-1024中選取一個值,預設是12", + + "rule.quasiConnectivity.name": "半連接激活開關", + "rule.quasiConnectivity.desc": "活塞,發射器和投擲器在他們上方方塊激活時是否響應", + "rule.quasiConnectivity.extra.0": "設置為true為開啟 設置為false為禁用", + + "rule.railPowerLimit.name": "自訂義動力鐵軌激活距離", + "rule.railPowerLimit.desc": "動力鐵軌激活距離能在此更改", + "rule.railPowerLimit.extra.0": "你必須在1-1024中選取一個數值", + + "rule.renewableCoral.name": "可再生珊瑚", + "rule.renewableCoral.desc": "使用骨粉可催熟珊瑚以長成珊瑚方塊結構", + + "rule.renewableSponges.name": "可再生海綿", + "rule.renewableSponges.desc": "深海守衛將在被雷擊後變成遠古深海守衛", + + "rule.rotatorBlock.name": "仙人掌扳手發射器版", + "rule.rotatorBlock.desc": "發射器中的仙人掌可以旋轉方塊(盡可能以逆時針)", + + "rule.scriptsAutoload.name": "Scarpet腳本自動加載", + "rule.scriptsAutoload.desc": "在伺服器/世界加載的時候將會自動從世界文件中加載Scarpet腳本文件", + "rule.scriptsAutoload.extra.0": "/script指令必須為啟用狀態", + + "rule.shulkerSpawningInEndCities.name": "可重生界伏蚌", + "rule.shulkerSpawningInEndCities.desc": "界伏蚌將會在終界城市中重生", + + "rule.silverFishDropGravel.name": "蠹魚鑽出放塊掉落礫石", + "rule.silverFishDropGravel.desc": "蠹魚鑽出放塊時會掉落礫石", + + "rule.smoothClientAnimations.name": "更平暢玩家端動畫", + "rule.smoothClientAnimations.desc": "降低TPS設置時可以使玩家端動畫更加平暢", + "rule.smoothClientAnimations.extra.0": "僅在單人模式中生效,並且會降低玩家端運行速度", + + "rule.stackableShulkerBoxes.name": "可堆疊界伏盒", + "rule.stackableShulkerBoxes.desc": "空的界伏盒扔在地上時將會自動堆疊,直到堆疊為1組", + "rule.stackableShulkerBoxes.extra.0": "在物品GUI中,請使用shift鍵+單擊以移動整組界伏盒", + + "rule.summonNaturalLightning.name": "召喚閃電自然化", + "rule.summonNaturalLightning.desc": "召喚的閃電將具有自然生成時的特性", + + "rule.tntDoNotUpdate.name": "TNT放置時不會被更新", + "rule.tntDoNotUpdate.desc": "TNT在放置時不會產生任何方塊更新(不會激活)", + + "rule.tntPrimerMomentumRemoved.name": "移除TNT點燃時隨機動量", + "rule.tntPrimerMomentumRemoved.desc": "TNT點燃時的隨機動量將被移除", + + "rule.tntRandomRange.name": "TNT爆炸範圍設置", + "rule.tntRandomRange.desc": "設置TNT隨機爆炸範圍為一個固定的值,設為-1以禁用", + "rule.tntRandomRange.extra.0": "必須啟用optimizedTNT功能", + "rule.tntRandomRange.extra.1": "不能設置為負數,除了-1", + + "rule.unloadedEntityFix.name": "未加載實體修復", + "rule.unloadedEntityFix.desc": "進入或者被推入未加載區塊的實體不會消失", + + "rule.viewDistance.name": "自訂義視野", + "rule.viewDistance.desc": "改變伺服器端視野距離,設置為0以使用默認值", + "rule.viewDistance.extra.0": "你必須在0(使用伺服器默認設置)-32取一個整數", + + "rule.xpNoCooldown.name": "經驗球吸收無冷卻", + "rule.xpNoCooldown.desc": "玩家吸收經驗球不會有冷卻時間", + + "rule.portalSuffocationFix.name": "傳送門窒息修復", + "rule.portalSuffocationFix.desc": "使地獄傳送門正確地傳送實體", + "rule.portalSuffocationFix.extra.0": "傳送的實體將不再卡在黑曜石裡", + + "rule.portalCreativeDelay.name": "創造模式玩家地獄門傳送延遲", + "rule.portalCreativeDelay.desc": "創造模式下使用地獄傳送門將同生存時產生延遲", + + + "category.bugfix": "BUG修復", + "category.survival": "生存用", + "category.creative": "創造用", + "category.experimental": "實驗用", + "category.optimization": "優化", + "category.feature": "特性", + "category.command": "指令", + "category.tnt": "TNT", + "category.dispenser": "發射器", + "category.scarpet": "scarpet腳本程式語言", + "category.client": "玩家端", + + "ui.browse_categories": "瀏覽分類", + "ui.list_all_%(cat)s_settings": "列出所有 %s 選項", + "ui.version": "版本", + "ui.current_%(mod)s_settings": "目前啟用的 %s 選項", + "ui.switch_to": "切換至", + "ui.settings_are_locked": "選項被鎖定", + "ui.is_set_to": "被設置為", + "ui.unknown_rule": "未知的規則選項", + "ui.current_%(mod)s_startup_settings_from_%(conf)s": "目前啟用的%s選項,從%s中讀取得", + "ui.%(mod)s_settings_matching_'%(query)s'": "%s中符合\"%s\"的選項:", + "ui.all_%(mod)s_settings": "所有的%s選項", + "ui.tags": "分類", + "ui.change_permanently": "設為預設", + "ui.click_to_keep_the_settings_in_%(conf)s_to_save_across_restarts": "點擊此按鈕以使此選項保存於%s,重啟後依舊生效", + "ui.rule_%(rule)s_will_now_default_to_%(value)s": "規則%s將會被默認設置為%s", + "ui.current_value": "當前的值" + +} From 01a2d9ea6e231087b12fddfb0e89eb86f1dda7d1 Mon Sep 17 00:00:00 2001 From: gnembon Date: Mon, 1 Jun 2020 21:10:42 -0300 Subject: [PATCH 4/7] removed potential ConcurrentModificationException chance, part one for 304 --- src/main/java/carpet/script/CarpetEventServer.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/carpet/script/CarpetEventServer.java b/src/main/java/carpet/script/CarpetEventServer.java index 10ca5210..cd5d027d 100644 --- a/src/main/java/carpet/script/CarpetEventServer.java +++ b/src/main/java/carpet/script/CarpetEventServer.java @@ -126,7 +126,13 @@ public class CarpetEventServer List argv = argumentSupplier.get(); // empty for onTickDone ServerCommandSource source = cmdSourceSupplier.get(); assert argv.size() == reqArgs; - callList.removeIf(call -> !CarpetServer.scriptServer.runas(source, call.host, call.function, argv)); // this actually does the calls + List fails = new ArrayList<>(); + for (Callback call: callList) + { + if (!CarpetServer.scriptServer.runas(source, call.host, call.function, argv)) + fails.add(call); + } + for (Callback call : fails) callList.remove(call); } } public boolean addEventCall(ServerCommandSource source, String hostName, String funName, Function verifier) From 4271aa3a8ee453ab1be27c7063a723300e8f569c Mon Sep 17 00:00:00 2001 From: gnembon Date: Mon, 1 Jun 2020 22:11:37 -0300 Subject: [PATCH 5/7] removed ability to automatically register events by running imports code, part two for 304 --- src/main/java/carpet/script/CarpetScriptHost.java | 2 +- src/main/java/carpet/script/value/FunctionValue.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/carpet/script/CarpetScriptHost.java b/src/main/java/carpet/script/CarpetScriptHost.java index bd2b669e..94f3b2fc 100644 --- a/src/main/java/carpet/script/CarpetScriptHost.java +++ b/src/main/java/carpet/script/CarpetScriptHost.java @@ -96,7 +96,7 @@ public class CarpetScriptHost extends ScriptHost public void addUserDefinedFunction(Context ctx, Module module, String funName, FunctionValue function) { super.addUserDefinedFunction(ctx, module, funName, function); - // mcarpet + if (ctx.host.main != module) return; // not dealing with automatic imports / exports /configs / apps from imports if (funName.startsWith("__")) // potential fishy activity { if (funName.startsWith("__on_")) // here we can make a determination if we want to only accept events from main module. diff --git a/src/main/java/carpet/script/value/FunctionValue.java b/src/main/java/carpet/script/value/FunctionValue.java index 14f6498d..3b872ccf 100644 --- a/src/main/java/carpet/script/value/FunctionValue.java +++ b/src/main/java/carpet/script/value/FunctionValue.java @@ -5,6 +5,7 @@ import carpet.script.Expression; import carpet.script.Fluff; import carpet.script.LazyValue; import carpet.script.Tokenizer; +import carpet.script.bundled.Module; import carpet.script.exception.BreakStatement; import carpet.script.exception.ContinueStatement; import carpet.script.exception.ExitStatement; @@ -58,6 +59,8 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction return name; } + public Module getModule() {return expression.module;} + @Override public String getPrettyString() { From 46409c8daa348bee5a4574d9a0c47c2fed18d016 Mon Sep 17 00:00:00 2001 From: gnembon Date: Tue, 2 Jun 2020 11:58:14 -0300 Subject: [PATCH 6/7] added optional options for draw_shape and fixed docs --- docs/scarpet/Full.md | 64 +++++++++++++-- docs/scarpet/api/Auxiliary.md | 5 ++ docs/scarpet/resources/editors/idea/2.txt | 1 + .../scarpet/resources/editors/npp/scarpet.xml | 4 +- .../carpet/network/ClientNetworkHandler.java | 2 +- .../carpet/script/utils/ShapeDispatcher.java | 78 +++++++++++++++---- .../carpet/script/utils/ShapesRenderer.java | 12 ++- 7 files changed, 136 insertions(+), 30 deletions(-) diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index 99523a4f..a8ab3b82 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -906,8 +906,11 @@ sleep(50) ### `time()` -Returns the number of milliseconds since 'some point', like Java's `System.nanoTime()`. -It returns a float, which has 1 microsecond precision (0.001 ms) +Returns the number of milliseconds since 'some point', like Java's `System.nanoTime()`, which varies from system to +system and from Java to Java. This measure should NOT be used to determine the current (date)time, but to measure +durations of things. +it returns a float with time in milliseconds (ms) for convenience and microsecond (μs) resolution for sanity. +
 start_time = time();
@@ -1513,7 +1516,7 @@ range(5,10)  => [5, 6, 7, 8, 9]
 range(20, 10, -2)  => [20, 18, 16, 14, 12]
 
-### `element(list, index)` (deprecated) +### `element(list, index)(deprecated)` Legacy support for older method that worked only on lists. Please use `get(...)` for equivalent support, or `.` operator. Also previous unique behaviours with `put` on lists has been removed to support all type of @@ -3103,24 +3106,69 @@ and `voice`. `pos` can be either a block, triple of coords, or a list of thee nu ## Particles -### `particle(name, pos, count?. spread?, speed?, playername?)` +### `particle(name, pos, count?. spread?, speed?, player?)` Renders a cloud of particles `name` centered around `pos` position, by default `count` 10 of them, default `speed` of 0, and to all players nearby, but these options can be changed via optional arguments. Follow vanilla `/particle` command on details on those options. Valid particle names are for example `'angry_villager', 'item diamond', 'block stone', 'dust 0.8 0.1 0.1 4'`. -### `particle_line(name, pos, pos2, density?)` +### `particle_line(name, pos, pos2, density?, player?)` Renders a line of particles from point `pos` to `pos2` with supplied density (defaults to 1), which indicates how far -apart you would want particles to appear, so `0.1` means one every 10cm. +apart you would want particles to appear, so `0.1` means one every 10cm. If a player (or player name) is supplied, only +that player will receive particles. -### `particle_rect(name, pos, pos2, density?)` -Renders a cuboid of particles between points `pos` and `pos2` with supplied density. +### `particle_box(name, pos, pos2, density?, player?)` +### `particle_rect` (deprecated) + +Renders a cuboid of particles between points `pos` and `pos2` with supplied density. If a player (or player name) is +supplied, only that player will receive particles. ## Markers +### `draw_shape(shape, duration, key?, value?, ... )`, `draw_shape(shape, duration, l(key?, value?, ... ))`, `draw_shape(shape, duration, attribute_map)` + +Draws a shape in the world that will expire in `duration` ticks. Other attributes of the shape should be provided as +consecutive key - value argument pairs, either as next arguments, or packed in a list, or supplied as a proper key-value +`map`. Arguments may include shared shape attributes, which are all optional, as well as shape-specific attributes, that +could be either optional or required. Shapes will draw properly on all carpet clients. Other connected players that don't +have carpet installed will still be able to see the required shapes in the form of dust particles. Replacement shapes +are not required to follow all attributes precisely, but will allow vanilla clients to receive some experience of your +apps. One of the attributes that will definitely not be honored is the duration - particles will be send once +per shape and last whatever they typically last in the game. + +Shapes will fail to draw and raise a runtime error if not all its required parameters +are specified and all available shapes have some parameters that are required, so make sure to have them in place: + +On the client, shapes can recognize that they are being redrawn again with the same parameters, disregarding the +duration parameter. This updates the expiry on the drawn shape to the new value, instead of adding new shape in its +place. This can be used for toggling the shapes on and off that has been send previously with very large durations, +or simply refresh the shapes periodically in more dynamic applications. + +Optional shared shape attributes: + * `color` - integer value indicating the main color of the shape in the form of red, green, blue and alpha components + in the form of `0xRRGGBBAA`, with the default of `-1`, so white opaque, or `0xFFFFFFFF`. + * `player` - name or player entity to send the shape to. If specified, the shapes will appear only for the specified + player, otherwise it will be send to all players in the dimension. + +Available shapes: + * `'line'` - draws a straight line between two points + * Required attributes: + * `from` - triple coordinates, entity, or block value indicating one end of the line + * `to` - other end of the line, same format as `from` + * Optional attributes: + * `width` - line thickness, defaults to 2.0pt + + * `'box'` - draws a box with corners in specified points + * Required attributes: + * `from` - triple coordinates, entity, or block value indicating one corner of the box + * `to` - other corner, same format as `from` + * Optional attributes: + * `width` - mesh line thickness, defaults to 2.0pt + * `fill` - color for the box faces, defaults to no fill, use shared color attribute format + ### `create_marker(text, pos, rotation?, block?)` Spawns a (permanent) marker entity with text or block at position. Returns that entity for further manipulations. diff --git a/docs/scarpet/api/Auxiliary.md b/docs/scarpet/api/Auxiliary.md index a8b097dc..993620f7 100644 --- a/docs/scarpet/api/Auxiliary.md +++ b/docs/scarpet/api/Auxiliary.md @@ -66,11 +66,16 @@ Available shapes: * Required attributes: * `from` - triple coordinates, entity, or block value indicating one end of the line * `to` - other end of the line, same format as `from` + * Optional attributes: + * `width` - line thickness, defaults to 2.0pt * `'box'` - draws a box with corners in specified points * Required attributes: * `from` - triple coordinates, entity, or block value indicating one corner of the box * `to` - other corner, same format as `from` + * Optional attributes: + * `width` - mesh line thickness, defaults to 2.0pt + * `fill` - color for the box faces, defaults to no fill, use shared color attribute format ### `create_marker(text, pos, rotation?, block?)` diff --git a/docs/scarpet/resources/editors/idea/2.txt b/docs/scarpet/resources/editors/idea/2.txt index 81803965..279adc94 100644 --- a/docs/scarpet/resources/editors/idea/2.txt +++ b/docs/scarpet/resources/editors/idea/2.txt @@ -17,6 +17,7 @@ current_dimension day_time destroy diamond +draw_shape drop_item emitted_light entity_area diff --git a/docs/scarpet/resources/editors/npp/scarpet.xml b/docs/scarpet/resources/editors/npp/scarpet.xml index c17b3811..64158b61 100644 --- a/docs/scarpet/resources/editors/npp/scarpet.xml +++ b/docs/scarpet/resources/editors/npp/scarpet.xml @@ -70,7 +70,9 @@ run save tick_time world_time day_time last_tick_times game_tick seed current_dimension in_dimension - plop harvest destroy schedule nbt create_marker remove_all_markers load_app_data store_app_data escape_nbt statistic + plop harvest destroy schedule nbt draw_shape create_marker remove_all_markers + + load_app_data store_app_data escape_nbt statistic euler pi null true false x y z p diff --git a/src/main/java/carpet/network/ClientNetworkHandler.java b/src/main/java/carpet/network/ClientNetworkHandler.java index 96524117..07ec99df 100644 --- a/src/main/java/carpet/network/ClientNetworkHandler.java +++ b/src/main/java/carpet/network/ClientNetworkHandler.java @@ -35,7 +35,7 @@ public class ClientNetworkHandler } }); put("TickRate", (p, t) -> TickSpeed.tickrate(((AbstractNumberTag)t).getFloat(), false)); - put("renderShape", (p, t) -> { + put("scShape", (p, t) -> { if (CarpetClient.shapes != null) CarpetClient.shapes.addShape((CompoundTag)t); }); diff --git a/src/main/java/carpet/script/utils/ShapeDispatcher.java b/src/main/java/carpet/script/utils/ShapeDispatcher.java index 0aaadb12..a1d1f071 100644 --- a/src/main/java/carpet/script/utils/ShapeDispatcher.java +++ b/src/main/java/carpet/script/utils/ShapeDispatcher.java @@ -19,6 +19,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.command.arguments.ParticleArgumentType; import net.minecraft.entity.Entity; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.FloatTag; import net.minecraft.nbt.IntTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; @@ -57,7 +58,7 @@ public class ShapeDispatcher if (ServerNetworkHandler.validCarpetPlayers.contains(player)) { if (tag == null) tag = ExpiringShape.toTag(params); - ServerNetworkHandler.sendCustomCommand(player,"renderShape", tag); + ServerNetworkHandler.sendCustomCommand(player,"scShape", tag); } else { @@ -122,7 +123,7 @@ public class ShapeDispatcher Function decoder = Param.decoders.get(key); if (decoder==null) { - CarpetSettings.LOG.error("Unknown parameter for shape: "+key); + CarpetSettings.LOG.info("Unknown parameter for shape: "+key); return null; } Value decodedValue = decoder.apply(tag.get(key)); @@ -131,13 +132,13 @@ public class ShapeDispatcher Value shapeValue = options.get("shape"); if (shapeValue == null) { - CarpetSettings.LOG.error("Shape id missing in "+ String.join(", ", tag.getKeys())); + CarpetSettings.LOG.info("Shape id missing in "+ String.join(", ", tag.getKeys())); return null; } Function,ExpiringShape> factory = ExpiringShape.shapeProviders.get(shapeValue.getString()); if (factory == null) { - CarpetSettings.LOG.error("Unknown shape: "+shapeValue.getString()); + CarpetSettings.LOG.info("Unknown shape: "+shapeValue.getString()); return null; } try @@ -146,7 +147,7 @@ public class ShapeDispatcher } catch (InternalExpressionException exc) { - CarpetSettings.LOG.error(exc.getMessage()); + CarpetSettings.LOG.info(exc.getMessage()); } return null; } @@ -225,7 +226,10 @@ public class ShapeDispatcher } // list of params that need to be there private final Set required = ImmutableSet.of("duration", "shape", "dim"); - private final Map optional = ImmutableMap.of("color", new NumericValue(-1), "player", Value.NULL); + private final Map optional = ImmutableMap.of( + "color", new NumericValue(-1), + "player", Value.NULL + ); protected Set requiredParams() {return required;} // list of params that can be there, with defaults protected Set optionalParams() {return optional.keySet();} @@ -234,7 +238,10 @@ public class ShapeDispatcher public static class Box extends ExpiringShape { private final Set required = ImmutableSet.of("from", "to"); - private final Map optional = ImmutableMap.of(); + private final Map optional = ImmutableMap.of( + "width", new NumericValue(2.0), + "fill", new NumericValue(0xffffff00) + ); @Override protected Set requiredParams() { return Sets.union(super.requiredParams(), required); } @Override @@ -243,6 +250,10 @@ public class ShapeDispatcher float x1, y1, z1; float x2, y2, z2; + float lineWidth; + + protected float fr, fg, fb, fa; + protected int fillColor; @Override protected void init(Map options) @@ -256,6 +267,12 @@ public class ShapeDispatcher x2 = NumericValue.asNumber(to.get(0)).getFloat(); y2 = NumericValue.asNumber(to.get(1)).getFloat(); z2 = NumericValue.asNumber(to.get(2)).getFloat(); + lineWidth = NumericValue.asNumber(options.getOrDefault("width", optional.get("width"))).getFloat(); + fillColor = NumericValue.asNumber(options.getOrDefault("fill", optional.get("fill"))).getInt(); + this.fr = (float)(fillColor >> 24 & 0xFF) / 255.0F; + this.fg = (float)(fillColor >> 16 & 0xFF) / 255.0F; + this.fb = (float)(fillColor >> 8 & 0xFF) / 255.0F; + this.fa = (float)(fillColor & 0xFF) / 255.0F; } @Override @@ -281,6 +298,8 @@ public class ShapeDispatcher hash = 31*hash + Float.hashCode(x2); hash = 31*hash + Float.hashCode(y2); hash = 31*hash + Float.hashCode(z2); + hash = 31*hash + Float.hashCode(lineWidth); + if (fa != 0.0) hash = 31*hash + fillColor; return hash; } @@ -308,7 +327,7 @@ public class ShapeDispatcher public static class Line extends ExpiringShape { private final Set required = ImmutableSet.of("from", "to"); - private final Map optional = ImmutableMap.of(); + private final Map optional = ImmutableMap.of("width", new NumericValue(2.0)); @Override protected Set requiredParams() { return Sets.union(super.requiredParams(), required); } @Override @@ -321,6 +340,7 @@ public class ShapeDispatcher float x1, y1, z1; float x2, y2, z2; + float lineWidth; @Override protected void init(Map options) @@ -334,6 +354,7 @@ public class ShapeDispatcher x2 = NumericValue.asNumber(to.get(0)).getFloat(); y2 = NumericValue.asNumber(to.get(1)).getFloat(); z2 = NumericValue.asNumber(to.get(2)).getFloat(); + lineWidth = NumericValue.asNumber(options.getOrDefault("width", optional.get("width"))).getFloat(); } @Override @@ -361,6 +382,7 @@ public class ShapeDispatcher hash = 31*hash + Float.hashCode(x2); hash = 31*hash + Float.hashCode(y2); hash = 31*hash + Float.hashCode(z2); + hash = 31*hash + Float.hashCode(lineWidth); return hash; } } @@ -374,16 +396,19 @@ public class ShapeDispatcher put("color", ShapeDispatcher::decodeInt); put("from", Vec3Param::decode); put("to", Vec3Param::decode); - + put("width", ShapeDispatcher::decodeFloat); + put("fill", ShapeDispatcher::decodeInt); }}; Map coders = new HashMap(){{ - put("shape", new ShapeParam()); put("player", new PlayerParam()); + put("shape", new ShapeParam()); put("dim", new DimensionParam()); put("duration", new DurationParam()); put("color", new ColorParam()); put("from", new FromParam()); put("to", new ToParam()); + put("width", new WidthParam()); + put("fill", new FillColorParam()); }}; Tag toTag(Value value); //validates value, returning null if not necessary to keep it and serialize Value validate(CarpetContext cc, Value value); // makes sure the value is proper @@ -452,8 +477,6 @@ public class ShapeDispatcher } public static abstract class NumericParam implements Param { - @Override - public Tag toTag(Value value) { return IntTag.of(NumericValue.asNumber(value).getInt()); } @Override public Value validate(CarpetContext cc, Value value) { @@ -471,15 +494,34 @@ public class ShapeDispatcher return ret; } } + public static abstract class PositiveFloatParam extends PositiveParam + { + @Override + public Tag toTag(Value value) { return FloatTag.of(NumericValue.asNumber(value).getFloat()); } + } + public static abstract class PositiveIntParam extends PositiveParam + { + @Override + public Tag toTag(Value value) { return IntTag.of(NumericValue.asNumber(value).getInt()); } + + } public static Value decodeInt(Tag tag) { return new NumericValue(((IntTag)tag).getInt()); } - public static class DurationParam extends PositiveParam + public static Value decodeFloat(Tag tag) { return new NumericValue(((FloatTag)tag).getFloat()); } + public static class DurationParam extends PositiveIntParam { @Override public boolean appliesTo(ExpiringShape shape) { return true; } @Override public String identify() { return "duration"; } } + public static class WidthParam extends PositiveFloatParam + { + @Override + public boolean appliesTo(ExpiringShape shape) { return shape instanceof Box || shape instanceof Line; } + @Override + public String identify() { return "width"; } + } public static abstract class Vec3Param implements Param { @@ -546,12 +588,22 @@ public class ShapeDispatcher } public static class ColorParam extends NumericParam { + @Override + public Tag toTag(Value value) { return IntTag.of(NumericValue.asNumber(value).getInt()); } @Override public boolean appliesTo(ExpiringShape shape) { return true; } @Override public String identify() { return "color"; } } + public static class FillColorParam extends ColorParam + { + @Override + public boolean appliesTo(ExpiringShape shape) { return shape instanceof Box; } + @Override + public String identify() { return "fill"; } + } + public static class FromParam extends Vec3Param { @Override diff --git a/src/main/java/carpet/script/utils/ShapesRenderer.java b/src/main/java/carpet/script/utils/ShapesRenderer.java index 4bb50aa7..46ee549b 100644 --- a/src/main/java/carpet/script/utils/ShapesRenderer.java +++ b/src/main/java/carpet/script/utils/ShapesRenderer.java @@ -91,12 +91,9 @@ public class ShapesRenderer if (shape == null) return; BiFunction> shapeFactory; shapeFactory = renderedShapes.get(tag.getString("shape")); - - - if (shapeFactory == null) { - CarpetSettings.LOG.error("Unrecognized shape: "+tag.getString("shape")); + CarpetSettings.LOG.info("Unrecognized shape: "+tag.getString("shape")); } else { @@ -161,7 +158,7 @@ public class ShapesRenderer @Override public void render(Tessellator tessellator, BufferBuilder bufferBuilder, float cx, float cy, float cz) { - RenderSystem.lineWidth(2.0F); + RenderSystem.lineWidth(shape.lineWidth); bufferBuilder.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); // 3 drawBoxWireGLLines(bufferBuilder, shape.x1 - cx-renderEpsilon, shape.y1 - cy-renderEpsilon, shape.z1 - cz-renderEpsilon, @@ -173,12 +170,13 @@ public class ShapesRenderer @Override public void render2pass(Tessellator tessellator, BufferBuilder bufferBuilder, float cx, float cy, float cz) { + if (shape.fa == 0.0) return; RenderSystem.lineWidth(1.0F); bufferBuilder.begin(GL11.GL_QUADS, VertexFormats.POSITION_COLOR); // 3 drawBox(bufferBuilder, shape.x1-cx-renderEpsilon, shape.y1-cy-renderEpsilon, shape.z1-cz-renderEpsilon, shape.x2-cx+renderEpsilon, shape.y2-cy+renderEpsilon, shape.z2-cz+renderEpsilon, - shape.r, shape.g, shape.b, shape.a/6 + shape.fr, shape.fg, shape.fb, shape.fa ); tessellator.draw(); } @@ -193,7 +191,7 @@ public class ShapesRenderer @Override public void render(Tessellator tessellator, BufferBuilder bufferBuilder, float cx, float cy, float cz) { - RenderSystem.lineWidth(2.0F); + RenderSystem.lineWidth(shape.lineWidth); bufferBuilder.begin(GL11.GL_LINES, VertexFormats.POSITION_COLOR); // 3 drawLine(bufferBuilder, shape.x1-cx-renderEpsilon, shape.y1-cy-renderEpsilon, shape.z1-cz-renderEpsilon, From 681d6ec9ee5a4ce13c989e9c094d182b987aaabd Mon Sep 17 00:00:00 2001 From: gnembon Date: Tue, 2 Jun 2020 11:58:33 -0300 Subject: [PATCH 7/7] fixed overlay --- .../assets/carpet/scripts/overlay.sc | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/main/resources/assets/carpet/scripts/overlay.sc b/src/main/resources/assets/carpet/scripts/overlay.sc index 366d0a7a..fb6b5a52 100644 --- a/src/main/resources/assets/carpet/scripts/overlay.sc +++ b/src/main/resources/assets/carpet/scripts/overlay.sc @@ -12,7 +12,7 @@ global_renderers = m( l('active', false), l('handler', '__chunk_renderer'), l('tasks', m()), - l('range', 4) + l('range', 6) )), l('shapes', m( l('active', false), @@ -95,7 +95,7 @@ __structure_renderer(player_name) -> total_size = _euclidean(from, to); density = max(10, total_size/10); //particle_box('dust 0 1 1 2', from, to+1, density); - draw_shape('box', 15, 'from', from, 'to', to+1, 'color', 0x00FFFFFF); + draw_shape('box', 15, 'from', from, 'to', to+1, 'color', 0x00FFFFFF, 'width', 3); structure_pieces = slice(sort_key(structure_pieces, _euclidean_sq((_:2+_:3)/2,ppos)), 0, config:'max_pieces'); for (structure_pieces, l(piece, direction, from, to) = _; //factor = 1- _i / config:'max_pieces' / 2; @@ -106,8 +106,8 @@ __structure_renderer(player_name) -> g = r; b = 255; a = 255; - color = a+256*(b+256*(g+256*r)); - draw_shape('box', 15, 'from', from, 'to', to+1, 'color', color); + color = 256*(b+256*(g+256*r)); // leaving out a + draw_shape('box', 15, 'from', from, 'to', to+1, 'color', color+a, 'fill', color+a/6); ) ) ); @@ -122,10 +122,9 @@ __chunk_renderer(player_name) -> // get lower corner of the chunk ppos = map(pos(p)/16, floor(_))*16; ppos:1 = 0; - - r = config:'range'; - for(range(-r,r), cx =_; - for (range(-r,r), cz = _; + rang = config:'range'; + for(range(-rang,rang), cx =_; + for (range(-rang,rang), cz = _; ref_pos = ppos + l(16*cx,0,16*cz); if(has(config:'tasks':'slime_chunks') && in_slime_chunk(ref_pos), player_distance = _euclidean(ppos, ref_pos); @@ -138,12 +137,12 @@ __chunk_renderer(player_name) -> b = 30; a = max(0, 255-player_distance); color = a+256*(b+256*(g+256*r)); - draw_shape('line', 15, 'from', top_00, 'to', top_10, 'color', color); - draw_shape('line', 15, 'from', top_10, 'to', top_11, 'color', color); - draw_shape('line', 15, 'from', top_11, 'to', top_01, 'color', color); - draw_shape('line', 15, 'from', top_01, 'to', top_00, 'color', color); - draw_shape('line', 15, 'from', top_00, 'to', top_11, 'color', color); - draw_shape('line', 15, 'from', top_01, 'to', top_10, 'color', color); + draw_shape('line', 15, 'from', top_00, 'to', top_10, 'color', color, 'width', 3); + draw_shape('line', 15, 'from', top_10, 'to', top_11, 'color', color, 'width', 3); + draw_shape('line', 15, 'from', top_11, 'to', top_01, 'color', color, 'width', 3); + draw_shape('line', 15, 'from', top_01, 'to', top_00, 'color', color, 'width', 3); + draw_shape('line', 15, 'from', top_00, 'to', top_11, 'color', color, 'width', 3); + draw_shape('line', 15, 'from', top_01, 'to', top_10, 'color', color, 'width', 3); //part = 'dust 0.2 0.8 0.2 2'; //density = 2+player_distance/2;