Skip to content

Commit 2179436

Browse files
committed
fortnite
1 parent 37ce476 commit 2179436

23 files changed

Lines changed: 357 additions & 273 deletions

‎build.gradle.kts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,11 @@ when (platform) {
4646
// -----------------------------------------------------------------------------
4747
// Loader Specific Logic
4848
// -----------------------------------------------------------------------------
49+
val ctVersion = (findProperty("mod.ct_version") as String?) ?: "fallback"
50+
4951
when (platform) {
5052
"fabric" -> {
5153
configure<LoomGradleExtensionAPI> {
52-
val ctVersion = (findProperty("mod.ct_version") as String?) ?: "fallback"
5354
accessWidenerPath.set(rootProject.file("src/main/resources/ct/customcursor.${ctVersion}.classtweaker"))
5455

5556
decompilers {
@@ -208,7 +209,8 @@ tasks.processResources {
208209
"id" to mod.id,
209210
"name" to mod.name,
210211
"version" to mod.version,
211-
"minecraft" to mod.prop("mc_dep_fabric")
212+
"minecraft" to mod.prop("mc_dep_fabric"),
213+
"classtweaker" to "ct/customcursor.${ctVersion}.classtweaker"
212214
)
213215
// }
214216
// "neoforge" -> {

‎deploy-prism-jj-neo.json‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"project_dir": ".",
3+
"source_dir": "build/libs",
4+
"instances_dir": "~/Library/Application Support/PrismLauncher/instances",
5+
"instance_game_subdir": "minecraft",
6+
"mods_subdir": "mods",
7+
"include": [
8+
"*.jar"
9+
],
10+
"exclude": [
11+
"*-sources.jar",
12+
"*-dev-shadow.jar"
13+
],
14+
"clean": [
15+
"customcursor-*"
16+
],
17+
"mappings": [
18+
{
19+
"src": "26.1-fabric",
20+
"instance": "26.1.2(1)"
21+
},
22+
{
23+
"src": "26.1-neoforge",
24+
"instance": "26.1.2"
25+
},
26+
{
27+
"src": "26.2-fabric",
28+
"instance": "26.2(1)"
29+
},
30+
{
31+
"src": "26.2-neoforge",
32+
"instance": "26.2"
33+
},
34+
{
35+
"src": "26.3-fabric",
36+
"instance": "26.3"
37+
},
38+
{
39+
"src": "26.3-neoforge",
40+
"instance": "26.3(1)"
41+
}
42+
]
43+
}

‎deploy.py‎

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
#!/usr/bin/env python3
2+
"""deploy
3+
4+
Copy freshly built mod jars from a build output folder into the matching
5+
PrismLauncher (MultiMC layout) instances.
6+
7+
If that file does not exist it is created with sensible defaults (matching this
8+
project) and the script exits so you can tweak it first.
9+
10+
Usage:
11+
python3 ./deploy.py # deploy everything
12+
python3 ./deploy.py --dry-run # show what would happen
13+
python3 ./deploy.py --only 26.3-fabric
14+
python3 ./deploy.py --list
15+
python3 ./deploy.py --config other.json
16+
"""
17+
18+
from __future__ import annotations
19+
20+
import argparse
21+
import fnmatch
22+
import json
23+
import shutil
24+
import sys
25+
from pathlib import Path
26+
27+
SCRIPT = Path(__file__).resolve()
28+
SCRIPT_DIR = SCRIPT.parent
29+
DEFAULT_CONFIG = SCRIPT.with_suffix(".json")
30+
31+
DEFAULT_CONFIG_DATA = {
32+
# Base folder. Relative paths elsewhere resolve against this.
33+
"project_dir": ".",
34+
# Where the built jars live, relative to project_dir.
35+
"source_dir": "build/libs",
36+
# PrismLauncher instances folder.
37+
"instances_dir": "~/Library/Application Support/PrismLauncher/instances",
38+
# Layout inside an instance folder.
39+
"instance_game_subdir": "minecraft",
40+
"mods_subdir": "mods",
41+
# Which jar files inside each source folder are candidates...
42+
"include": ["*.jar"],
43+
# ...and which of those to ignore (sources / intermediate jars).
44+
"exclude": ["*-sources.jar", "*-dev-shadow.jar"],
45+
# Delete already-installed files matching these patterns before copying.
46+
"clean": ["customcursor-*"],
47+
# src = folder name in source_dir, instance = folder name in instances_dir.
48+
"mappings": [
49+
{"src": "26.1-fabric", "instance": "26.1.2(1)"},
50+
{"src": "26.1-neoforge", "instance": "26.1.2"},
51+
{"src": "26.2-fabric", "instance": "26.2(1)"},
52+
{"src": "26.2-neoforge", "instance": "26.2"},
53+
{"src": "26.3-fabric", "instance": "26.3"},
54+
{"src": "26.3-neoforge", "instance": "26.3(1)"},
55+
],
56+
}
57+
58+
59+
def load_config(path: Path) -> dict:
60+
if not path.exists():
61+
path.write_text(json.dumps(DEFAULT_CONFIG_DATA, indent=2) + "\n")
62+
print(f"Created default config: {path}")
63+
print("Edit it, then run the script again.")
64+
sys.exit(0)
65+
66+
try:
67+
data = json.loads(path.read_text())
68+
except json.JSONDecodeError as exc:
69+
sys.exit(f"Invalid JSON in {path}: {exc}")
70+
71+
# Merge so a partial config still works.
72+
config = dict(DEFAULT_CONFIG_DATA)
73+
config.update(data)
74+
return config
75+
76+
77+
def matches_any(name: str, patterns: list[str]) -> bool:
78+
return any(fnmatch.fnmatch(name, p) for p in patterns)
79+
80+
81+
def resolve_jar(directory: Path, include: list[str], exclude: list[str],
82+
per_map_exclude: list[str]) -> list[Path]:
83+
if not directory.is_dir():
84+
return []
85+
86+
jars: list[Path] = []
87+
for entry in sorted(directory.iterdir()):
88+
if not entry.is_file():
89+
if matches_any(entry.name, include):
90+
print(f" ! skipping non-file (extracted jar?): {entry.name}")
91+
continue
92+
if not matches_any(entry.name, include):
93+
continue
94+
if matches_any(entry.name, exclude) or matches_any(entry.name, per_map_exclude):
95+
continue
96+
jars.append(entry)
97+
return jars
98+
99+
100+
def main() -> int:
101+
parser = argparse.ArgumentParser(
102+
description="Deploy built mod jars into PrismLauncher instances.",
103+
)
104+
parser.add_argument("--config", type=Path, default=DEFAULT_CONFIG,
105+
help=f"config file (default: {DEFAULT_CONFIG.name})")
106+
parser.add_argument("--dry-run", action="store_true",
107+
help="print actions without touching anything")
108+
parser.add_argument("--only", action="append", metavar="SRC",
109+
help="only deploy this src folder (repeatable)")
110+
parser.add_argument("--list", action="store_true",
111+
help="list mappings and resolved jars, then exit")
112+
args = parser.parse_args()
113+
114+
config = load_config(args.config.resolve())
115+
116+
config_dir = args.config.resolve().parent
117+
project_dir = (config_dir / config["project_dir"]).resolve()
118+
source_dir = (project_dir / config["source_dir"]).resolve()
119+
instances_dir = Path(config["instances_dir"]).expanduser().resolve()
120+
game_sub = config["instance_game_subdir"]
121+
mods_sub = config["mods_subdir"]
122+
include = config["include"]
123+
exclude = config["exclude"]
124+
clean = config["clean"]
125+
126+
if not instances_dir.is_dir():
127+
sys.exit(f"Instances folder not found: {instances_dir}")
128+
129+
mappings = config["mappings"]
130+
if args.only:
131+
wanted = set(args.only)
132+
mappings = [m for m in mappings if m["src"] in wanted]
133+
missing = wanted - {m["src"] for m in mappings}
134+
if missing:
135+
print(f"warning: no mapping for {', '.join(sorted(missing))}")
136+
137+
print(f"source: {source_dir}")
138+
print(f"instances: {instances_dir}")
139+
print()
140+
141+
deployed = 0
142+
for mapping in mappings:
143+
src_name = mapping["src"]
144+
instance_name = mapping["instance"]
145+
src_path = source_dir / src_name
146+
mods_path = instances_dir / instance_name / game_sub / mods_sub
147+
per_map_exclude = mapping.get("exclude", [])
148+
149+
print(f"[{src_name}] -> {instance_name}")
150+
151+
jars = resolve_jar(src_path, include, exclude, per_map_exclude)
152+
if not jars:
153+
print(f" ! no deployable jar in {src_path}")
154+
continue
155+
156+
if not mods_path.is_dir():
157+
if args.dry_run:
158+
print(f" would create {mods_path}")
159+
else:
160+
mods_path.mkdir(parents=True, exist_ok=True)
161+
print(f" created {mods_path}")
162+
163+
# Old installs that would be cleaned out.
164+
stale: list[Path] = []
165+
if mods_path.is_dir():
166+
stale = [p for p in sorted(mods_path.iterdir())
167+
if p.is_file() and matches_any(p.name, clean)]
168+
169+
for existing in stale:
170+
print(f" rm {existing.name}")
171+
for jar in jars:
172+
print(f" copy {jar.name}")
173+
174+
if args.list or args.dry_run:
175+
continue
176+
177+
for existing in stale:
178+
existing.unlink()
179+
180+
for jar in jars:
181+
shutil.copy2(jar, mods_path / jar.name)
182+
deployed += 1
183+
184+
print()
185+
if args.list:
186+
print("(list only, nothing copied)")
187+
elif args.dry_run:
188+
print("dry run, nothing copied")
189+
else:
190+
print(f"deployed {deployed} jar(s)")
191+
return 0
192+
193+
194+
if __name__ == "__main__":
195+
raise SystemExit(main())

‎src/main/java/io/github/jumperonjava/customcursor/CursorRenderer.java‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@
22

33
import com.mojang.blaze3d.platform.NativeImage;
44
import net.minecraft.client.Minecraft;
5-
//? if >= 1.21.6 {
6-
//?} else {
7-
/*import net.minecraft.client.renderer.rendertype.RenderType;
8-
import com.mojang.blaze3d.systems.RenderSystem;
9-
*///?}
105
import net.minecraft.resources.Identifier;
116
import org.lwjgl.BufferUtils;
127

@@ -15,6 +10,8 @@
1510
import java.awt.image.BufferedImage;
1611
import java.io.IOException;
1712
import java.nio.ByteBuffer;
13+
import java.nio.file.Files;
14+
import java.nio.file.StandardOpenOption;
1815

1916
public class CursorRenderer {
2017
public static RenderedCursorBuffer renderState(int size, float x, float y, float rotation, boolean mirroredX, boolean mirroredY, Identifier identifier) {
@@ -74,12 +71,23 @@ public enum ScalingMode {
7471

7572
private static NativeImage getNativeImage(Identifier identifier){
7673
try {
74+
if(identifier.getNamespace().equals("cursorfolder")){
75+
return specialcase_cursorfolder(identifier.getPath());
76+
}
7777
return NativeImage.read(Minecraft.getInstance().getResourceManager().open(identifier));
7878
} catch (IOException e) {
79-
throw new RuntimeException(e);
79+
try{
80+
return NativeImage.read(Minecraft.getInstance().getResourceManager().open(identifier));
81+
} catch (IOException e2){
82+
throw new RuntimeException(e2);
83+
}
8084
}
8185
}
8286

87+
private static NativeImage specialcase_cursorfolder(String filename) throws IOException {
88+
return NativeImage.read(Files.newInputStream(CustomCursorInit.getTextureFolder().path.resolve(filename), StandardOpenOption.READ));
89+
}
90+
8391
private static ByteBuffer argb2rgbaBuf(int[] pixels) {
8492
ByteBuffer buffer = BufferUtils.createByteBuffer(pixels.length * 4);
8593

‎src/main/java/io/github/jumperonjava/customcursor/CursorSettings.java‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.google.gson.Gson;
55
import com.mojang.blaze3d.platform.cursor.CursorType;
66
import com.mojang.blaze3d.platform.cursor.CursorTypes;
7+
import net.minecraft.client.Minecraft;
78
import net.minecraft.resources.Identifier;
89

910
import java.util.List;
@@ -14,17 +15,16 @@ public class CursorSettings implements Cloneable {
1415
public static CursorType globalCursor;
1516

1617
public boolean enabled = false;
17-
public boolean dynamicEnabled = true;
1818

1919
public final CursorSprite arrow = new CursorSprite(0.0625f, 0.0625f, 0, false, false, Identifier.fromNamespaceAndPath("customcursor", "cursors/arrow.png"));
2020
public final CursorSprite ibeam = new CursorSprite(0.5f, 0.5f, 0, false, false, Identifier.fromNamespaceAndPath("customcursor", "cursors/ibeam.png"));
2121
public final CursorSprite crosshair = new CursorSprite(0.5f, 0.5f, 0, false, false, Identifier.fromNamespaceAndPath("customcursor", "cursors/crosshair.png"));
22-
public final CursorSprite pointing_hand = new CursorSprite(0.375f, 32, 0, false, false, Identifier.fromNamespaceAndPath("customcursor", "cursors/pointing_hand.png"));
22+
public final CursorSprite pointing_hand = new CursorSprite(0.375f, 0.0625f, 0, false, false, Identifier.fromNamespaceAndPath("customcursor", "cursors/pointing_hand.png"));
2323
public final CursorSprite resize_ns = new CursorSprite(0.5f, 0.5f, 0, false, false, Identifier.fromNamespaceAndPath("customcursor", "cursors/resize_ns.png"));
2424
public final CursorSprite resize_ew = new CursorSprite(0.5f, 0.5f, 0, false, false, Identifier.fromNamespaceAndPath("customcursor", "cursors/resize_ew.png"));
2525
public final CursorSprite resize_all = new CursorSprite(0.5f, 0.5f, 0, false, false, Identifier.fromNamespaceAndPath("customcursor", "cursors/resize_all.png"));
2626
public final CursorSprite not_allowed = new CursorSprite(0.5f, 0.5f, 0, false, false, Identifier.fromNamespaceAndPath("minecraft", "textures/item/barrier.png"));
27-
public int size;
27+
public int size=16;
2828

2929
public Map<String, CursorSprite> allCursors() {
3030
return Map.of(
@@ -64,9 +64,9 @@ public static Map<String, CursorType> cursors() {
6464
);
6565

6666
public CursorSprite cursorToSprite(CursorType cursor) {
67-
if (!this.dynamicEnabled) {
68-
return this.arrow;
69-
}
67+
// if (!this.isDynamicEnabled()) {
68+
// return this.arrow;
69+
// }
7070
if (cursor == CursorTypes.ARROW) return arrow;
7171
if (cursor == CursorTypes.IBEAM) return ibeam;
7272
if (cursor == CursorTypes.CROSSHAIR) return crosshair;
@@ -82,6 +82,14 @@ public CursorSettings clone() {
8282
return new Gson().fromJson(new Gson().toJson(this), CursorSettings.class);
8383
}
8484

85+
public boolean isDynamicEnabled() {
86+
return Minecraft.getInstance().options.allowCursorChanges().get();
87+
}
88+
89+
public void setDynamicEnabled(boolean dynamicEnabled) {
90+
Minecraft.getInstance().options.allowCursorChanges().set(dynamicEnabled);
91+
}
92+
8593

8694
public static class CursorSprite {
8795
public float x;

0 commit comments

Comments
 (0)